Completed: / exercises

1. The a, b, ... ( •_•)>⌐■-■ ...C of this course

On this page you will take the first steps away from the familiar Python of the Elementary Programming course and towards a new conquest: the marvelous programming language C. At the same time you get to know a bit more about the course and its relationship with the Introduction to Programming and, of course, about C as a tool.

Learning objectives

This time you learn what C has to do with this course and why it has been considered necessary to switch the language. The key learning points are the principle differences of these languages that strongly affect the way of programming with them. In addition you will learn the first differences between the
syntaxes
of them.

C programming on this course

Before we get to comparing these two languages, it is crucial to tell you a bit more about the relationship of this course, programming, and C.

This is not an elementary course of programming

For starters, this course continues from where the Elementary Programming course left off. We assume that you know the very basics of programming and we do not have to teach you them again. There is some material that should refresh your memories about Python so that through the language can be shown some of the differences between Python and C. If some things feel completely alien, it is likely you can understand them better if you check the Elementary Programming course material. The order of the contents of the course is about the same as it was in Elementary Programming, but they focus on how to do the things in C instead of Python.

This is not a C programming course

Another important thing to note about this course is that C is only a tool to get to the core of the course. The language is taught from the point of view of embedded systems programming. On the course there are several things about C language that are relevant mostly when you are programming large software for computers. Some standards of the C language are mentioned in the material when it is useful for the course.

This is an embedded systems programming course

This course is a combination of two old courses: Embedded Systems Programming and Computer Engineering - although only the ones doing the 8 credits version find out things related to the latter. This part you are currently reading is included in the 5 credits part and thus is completely about the topics of the former Embedded Systems Programming course. On the lectures you can learn more elaborately about embedded systems, but as a short summary: this course goes much deeper than the Elementary Programming course and is focused on small devices with limited processing power and memory (naturally regular computers also are limited in the same way, but they usually are not so limited that you have to worry about that nearly as much). C offers tools for better
resource
allocation and lets us directly prod the computer's
memory
and low level processes.
What this more accurate control of the processes and memory means you will find out bit by bit as you proceed through the course material. At this point is relevant to remember that the more precise control a tool offers the more precise work you have to do yourself to use it.

From Python to C

In this portion is introduced some of the basic differences of the languages. You do not yet need to perfectly understand what these differences mean in practice, but from the start it is good to know they exist. It is also good to know that even if the differences may sound like just semantics, for the most part they - especially in embedded systems programming - have a huge impact on how to write the programs. These differences also hopefully demonstrate the reasons why Python was chosen as the elementary programming language and was now switched to C for this course. In short, Python has lots of automation that eases programming so that it is not that necessary to handle all the small details. However, the efficiency (which does not matter as much at it used to with modern computers) and the fine control(which you don't usually need with programming) suffer because of the automation.

Compiled language vs interpreted language

On the Elementary Programming course you may have run into Python
interpreter
, a program that runs Python code. On this course we will not be talking about interpreters much, because C is not interpreted, it is
compiled
. Whatever the programming language, the code will end up in a
machine language
format. Machine language consists of simple
instructions
for the processor. These instructions may seem very limited to humans, but humans have programmed using it - and still are programming using it, and the students taking part in the later part of the course will get to enjoy it. In practice, programming languages are
abstractions
that have been built on machine language and they offer a more human-friendly collection of commands. Both compiling and interpreting are processes that turn the programming language into machine language for the processor. The name choices are not random - their analog counterparts picture well the differences between the processes. Like in real life when a language is "compiled" the whole text is processed after which the
compiler
sends the finished output forward. "Interpreting" on the other hand happens in real time, the sentences are interpreted one by one.
The nature of interpreting manifests well while using Python's
interactive interpreter
; you can get every written line's output right away:
>>> 5 + 5
10
>>>
Another clear manifestation of it is how Python program often runs up to some point after which it crashes - it only works partly. Especially from the point of view of a beginner this is useful, because this way it is easy to examine how the faulty program acts. However, as a drawback of interpreting is that, because the machine language is produced on the fly, it uses resources while it runs. Another drawback is that while interpreting it has to be taken into account that the next line of code can be anything, which also eats up resources. On a test run this extremely simple Python program used 8 MB of
memory
:
input(": ")
A couple of decades ago 8 MB would have been the size of the whole RAM of a computer. Almost all of this goes in Python's own usage - the upkeep of the architecture that interprets code. As a proof of this the example minesweeper does not take any more memory than that. Python's processing power can be
optimized
with different tools (e.g. PyPy), but that is not very relevant to this course.
Life with a
compiler
is quite different. With it executing the program has two steps: in the first step the code is run through the compiler and it outputs a
binary code file
, which contains the actual executable program. The compiling is done only once. While executing the program it is already in a form that can be given straight for the processor. During the executing resources are not used for compiling at all. Also during the execution there will be less surprises, since the compiler has gone through the whole code. Compilers typically do some optimization - after going through the whole code they can choose the best way to execute the logic. This is possible just because the whole code is known before execution. The C equivalent of the Python example above used up only 640kB of memory. We may look at the code of that program later.
Looking for and solving bugs with a compiler is substantively different. Usually a faulty code can not be executed at all, because it is rejected in the compiling phase. The error and the way it can be fixed has to be read from the
error message
. Even if the program compiles it can also crash also while executing. In addition to error messages, the compiler outputs
warnings
of potential problems. Typically also these are good to fix before executing the program, but even that does not guarantee the program will work. In the end you also have to test the code after compiling anyway. Because of that, there is an additional work step of compiling the code after each change made to the code. If the program is large compilation of several parts, the compilation can take a notable time. At this point one thing you can be sure of: you get to familiarise yourself with all of this many times during the course.

Static vs dynamic type

Regarding many new things Python is rather open. As we (hopefully) remember, the typical way of handling
exceptions
is "try first, regret later." The way Python manages variables is quite liberal. In most situations the type of a variable is not checked - instead it is only tested whether or not the value of the
variable
happens to work in the current situation. This is
dynamic typing
, which is also known as duck typing - if an animal walks like a duck, swims like a duck, and talks like a duck, it can be considered a duck whether or not it really is a duck. If we have, for example, a mathematical
function
, it is only interested in can it compute using the given arguments, not what type the numbers are. The most exact ones may still remember that Python's variables do not even have a type, only their values do. You can set a string to a variable at some point, and a list at another:
>>> aline = "aasi,svengaa,5,10.0"
>>> aline = aline.split(",")
C, on the other hand, has
static typing
. It means that all the types of all variables have to be defined in the code separately. This also applies to the
parameters
and
return
values of functions. The compiler ensures a round piece will not be pushed in a triangular hole even if it was small enough to fit. If the type of the variable has to be changed on the fly, it has to be written in the code separately or the operation will be illegal. With normal variables this difference is not as relevant as the previous one, because the usage of variables is only a little bit more tedious and requires only a bit more work. There are programmers who are vehemently of the opinion that this kind of more strict typing is best and they have theri reasons: it prevents certain mystical errors that appear when something is thought of as a duck and later is revealed to be a goose instead (in other words, the variable had only some of the required attributes, for example a string works in some situations like a list, but not in all). Below you can see a couple of examples of defining variables with type in C:
int jalkojen_lkm = 4;
float korvien_vali = 30.15;
Unfortunately things get more complicated when we move from simple data types to
structures
. The handy general tool of Python,
list[!list!], does not exist in C. C does have its own structure for putting a handful of values in a line. This structure is called [!term=Array!]array
. Array happens to be more unwieldly than list. For arrays you have to define in its
introduction
how many elements it can contain and what type they are - the length of an array can not change during the execution of the program, and it is not possible to put different types of items in it. Naturally it is possible to come up with solutions to this, but they are not easy, and usually they do not reach the level of versatility of the lists of Python. Fortunately you will not need them much on this course.
There is one more difference between the typings: on the Python course you may have been constantly reminded that
variables
do not contain values, they only point at them. All the variables worked in the same way. But in C there are
variables
that contain values and variables that contain
pointers
to values. This separation is one of the most difficult things to learn about C programming, because it can cause very mystical errors when the memory is accessed without doing it through variables. This is why we have on this course material a part dedicated for this problem.

Syntax differences

Perhaps the most insignificant difference between the languages, at least in terms of problem solving, is that they look a bit different. Let us begin from the easiest one: in C the
statements
, usually individual lines of code, end with a semicolon, while in Python they simply end at the end of the line. A compiler can point out missing semicolons rather eagerly. Another difference is related to marking up [!term=Block of statements]blocks of statements[!term!]. In Python the blocks are separated by indentation. In C the indentation does not matter and the blocks are marked with curly braces - everything within a pair of curly braces belong to the same block of statements. Naturally there can be more blocks within a block also. Curly brackets are used with
functions
and
control structures
. Even when the indentation does not mean anything, using indentation like in Python makes the code significantly easier to read with human eyes. Other very small differences are, among others, that conditionals and things resembling them are put between parentheses and some symbols are used differently.
In C the
main program
does not exist the same way as in Python either. Instead of it in C there is the
main function
, from which the execution of the program begins. Because of this, in a simple C program there is more stuff:
#include <stdio.h>

int main() {
    printf("aasisvengaa!\n");
    return 0;
}
Equivalent in Python:
print("aasisvengaa")
In the example you can see a couple of other differences also. #include <stdio.h> works the same way as Python's import. It is required for using printf function, since you need to get it from stdio-
library
(standard input/output). int main() is a definition of the main function. A separate
keyword
, like def in Python, does not exist in C for marking a function. A function is recognized by parentheses at the end of its name, otherwise its introduction looks similar to a variable's introduction, since you have to define the function's return value's type when you introduce the function.

C tools

Before diving deeper, at the end of this introduction page is some basics of executing a C-program. Like was mentioned before, compared to "starting" a Python program there is one additional step with C: compiling. As a tool we use a
C compiler
, which should have been installed by now. In this material the compiler and programs are executed in
terminal
, like with Elementary Programming course. As an example we could use the code above. In terminal you navigate to the directory where the code is located. After that you cast this basic spell (in Windows):
C:\path\to\somewhere>gcc -Wall -o svengaa.exe svengaa.c
In this line "gcc" is the name of the compiler. The rest are its commandline parameters, of which the last one is the name of the source code file. The third and fourth, -o svengaa.exe, belong together: -o says that the next parameter will be the name of the compiled program. In linux the spell is the same otherwise, but .exe is left out - Linux executables usually do not have endings like that. After this the program can be executed:
C:\path\to\somewhere>svengaa.exe
aasisvengaa!
A compiler is a quite complicated thing and -o is only one of the todella many of its
flags
. On this course we will not touch the inner workings of a compiler very much, but some other flags probably will be used.

Summary

This time we went through C language on a very general manner. We took note of some principle differences between it and Python. Basically we prepared for the future, and the meanings of these differences will come clearer when we get to details. In any case, at the beginning is good to be aware of how C is not an animal like Python; it won't be a huge surprise that things have to be done in somewhat different ways. In C programming the coder has to handle more details. But as a reward they get more superpowers for controlling the lives of computers.
?