Computer Laboratory

Raspberry Pi

RPii - C Tutorial Page 1

C.2 Basic C concepts and Syntax

Before we start this section, lets make a new directory in which to save all of the Exercises done in the rest of the tutorial. Using the mkdir command (see section GS.1 for help), create a new directory called RPiiExercises.
If at any point you get really (really) stuck, the sources used in the examples here, and solutions to each exercise can be found in examplesources/RPii_C-2.

C.2.1 Data types and more printf

A lot of errors when dealing with computational arithmetic arise from complications due what are known as data types. On a computer there are multiple ways of storing a number and each type has its own pro's and cons. Commonly used data types are int for an integer numbers, float for a floating point/decimal numbers, and char for characters. When performing calculations with ints, care must be taken as the computer will truncate results if it is asked to store a decimal[1] . We also use the data type char to store strings of letters, e.g words and sentences [2] . When we want to manipulate values using a computer we must create what we call variables. To use a variable, we must first declare it - this tells the computer to allocate an area of memory to the variable. Different data types require different amounts of memory to be stored. Once a variable has been declared, it can be used in calculations, as inputs to other functions, or as a place to store the output of functions.

Before we can learn about how to do arithmetic in C, we first need to know how to print out our answers to the terminal; the following section goes through this.

The 'f' in the 'printf' command stands for 'formatted'. The function allows us to leave a 'format specifier' in the string which is passed as the first argument of printf. The following arguments in the function call are the variables that we want to fill the format specifier's positions. Depending on the data type of each variable we want to put into the string, we use different 'format specifiers'. See Table C.2.1 for a list of commonly needed format specifiers. (Only data types used in this tutorial series are shown).

Table C.2.1 - A table of format specifiers
Format Specifier Data type
%i,%d int
%f float
%s string ( a series of chars )
%c char

This is a very useful table for the following Exercises - if you are getting compiler errors ensure that all of the format specifiers used match the data types of the variables which are associated with them.

Consider ExS.2 below of the program printdatatypes.c

ExS.2 Example Source Code: printdatatypes.c

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
// Example source ExS.2: printdatatypes.c
#include <stdio.h>

int main(){

//initialise a variable of each type
int integer;
float decimal;
char character;
char *string;
int willberounded;

//Assign each variable a value
integer = 1;
decimal = 2.4;
character = 'x';
string = "Hello";
willberounded = 0.4;

// print out the contents of each variable
printf("%s", "This printout contains:\n");
printf("An integer: %i\na float: %f\n", integer, decimal);
printf("A character : %c\n", character);
printf("And a a string: %s\n", string);
printf("A common error is trying to store ");
printf("a variable in an int.\n");
printf("0.4 = %d\n", willberounded);
return 0;
}

A line by line breakdown of ExS.2 printdatatypes.c

Line No. Comment
7. Declare variable integer of type int.
8. Declare variable decimal of type float.
9. Declare variable character of type char.
10. Declare variable string of type pointer[3] to char.
11. Declare variable willberounded of type int.
14. Initialise integer as 1.
15. Initialise decimal as 2.4.
16. Initialise character as x. Note that the x is surrounded by single quotes.
17. Initialise string as the string "Hello". Note the double quotes used.
18. Initialise willberounded to 0.4. As this is of type int and we are asking it to store a decimal, it will have to truncate[1]/round it.
21. The first argument contains only a format specifier. This looks for a string in the follow arguments to replace it. We can pass this string as a variable (see later lines) or directly as is done here. Alternatively we could have not used a format specifier at all and could have just written in the first quotes as in Exercise 3 when we use printf("Hello Pi").
22. Printf can take many format specifiers in one call. Here we have two in the same function call, and list the variables to replace them in the same order as they were used in the first argument. Note that although this was written in one line in the source code, when the program is run, it takes up two on the terminal. This is due to the new line character, \n which was used.
23. A demonstration of using the format specifier for a character.
24. A demonstration of using the format specifier for a string, and passing in a variable.
25. Note that although this statement is written over two lines…
26. Because there is no new line character, the console writes it all onto one.
27. The output from this line is 0 even though willberounded is defined as 0.4. This demonstrates that accidentally trying to store decimals in ints can cause errors.

C.2.2 Mathematical operators, syntax and Basic arithmetic

If you are used to using a calculator, it is likely that it will take you no time to get comfortable using C for basic arithmetic. Table RPii.2.1.2 contains the first few operators that you might want to use.

Table C.2.2 - Mathematical Operators
Arithmetic Operators Conditional Operators
Syntax Operation Syntax Operation
+ Add == Equal to
- Subtract <= Less than or Equal to
/ Divide >= More than or Equal to
* Multiply < Less than
% Modulo > More than
a++ Increase 'a' by 1 != Not equal to
a-- decrease 'a' by 1

Exercise 3: Printing out the results of equations

For this exercise, we will try to build a source file from scratch. There are completed example codes in examplesources/RPii_C-2 provided but do try to attempt all of this exercise first. The file printdatatypes.c is a good reference file for this exercise.

When compiling your program, you can either compile from the command line using:
gcc -o 'exe''src.c'
Or you can make your own make file in the same directory as the sourcefile.

  1. Inside the RPiiExercises directory, create a new directory called Ex3, and open a new file in a text editor called ex3.c: see if you can do this from the command line. (see exercise 1 for a hint)
  2. The only library you will need for this is stdio. The library and its header are stored in the default install paths and so their location does not need to be specified.
  3. Using section C.1.3, write yourself a template source file which includes: #include for each header needed and a main function which returns 0 when it is complete. Write a makefile to compile this file.
  4. As a quick example, copy the line below into your main function, compile and run the program. See if you can work out what each part of this line of code does - write this in a comment above the line as it is useful later on in this exercise.
    printf("One add one = %i\n", 1+1);
  5. In your main function, declare and initialise two integers 'a' and 'b' as 3 and 4 respectively. Write a few more lines in your main function which will print out their sum, product and difference in the following ways:
    • By creating a new variable for each result (of type int) and storing the value of the sum, product and difference in these variables, print out the value of these variables with a description of what each variable is, e.g.
      int product;
      product = a*b;
      printf("The product of %d and %d is: %d\n", a,b,product);
    • See if you can do it without creating any new variables. (hint, use part 4)
  6. By declaring and initialising two decimal numbers(Think about which data type will be needed - and which format specifier must be used in order to print this datatype) 'c' and 'd' as 0.5 and 2.25 respectively, print out their sum, product, difference and divisions using the 2 techniques suggested in part 5.
  7. Consider storing the result of the division of two variables in a third variable. In a new source file, explore all combinations of int and float type variables by printing out the result of each division using printf. (i.e try an int divided by an int - stored in an int, a float divided by an int - stored in a float etc...)Don't forget to match the format specifier of the printf statement with that of the variable you are trying to print. Which combinations truncate and which ones don't? Can you work out why this might be?

C.2.3 Using scanf

Be aware that using scanf in any ways more complicated than those shown in these examples - without the correct error handling (see section C.2.10) - can lead programs to crash.

Similarly to printf, scanf is a function included in the stdio library. It can be used to read in a number from the keyboard and save the number in a variable. Consider the example code 'usingscanf.c'.

ExS.3a Example Source Code: ExS-3a-usingscanf.c

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
// Example source ExS.3a: usingscanfa.c
#include <stdio.h>

int main(){

//initialise the variable to store the keyboard input
int input = -1;

//using a format specifier, indicate expected type of input
printf("Input an integer from the keyboard and press enter\n");
scanf("%d", &input);
printf("Input now contains the number %d. \n". input);

return 0;
}

In scanf we use format specifiers as we do in printf, but in a different way. In comparison to printf, scanf looks at the input string[3] (what is typed into the keyboard) for the combination of characters which match those in scanf's first argument. Where the first argument contains a format specifier, the function infers which character in the input is in the same position as the the format specifier in the argument. Scanf then stores this inferred value in the relevant variable which is passed to scanf in subsequent arguments [4]. Similarly to printf, the variables which are to store the inputs are give to scanf in the order that their format specifiers are used, consider the example below:

ExS.3b Example Source Code: ExS-3b-usingscanf.c to remove file information

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
// Example source ExS.3b: usingscanfb.c
#include <stdio.h>

int main(){

//initialise the variable to store the keyboard input
int hour = -1;
int min = -1;

//using format specifiers, indicate expected type of input
printf("Input a data filename from the terminal and press enter.\n");
scanf("WiiData_%d-%d", &hour, &min);
printf("The file was created at %dhr and %dmins.\n", hour, min);

return 0;
}

Running the program in ExS.3b, with the input WiiData_16-08 would print the following to the terminal:

pi@raspberrypi ~ $ ./usingscanfb
Enter a data filename from the terminal and press enter.
WiiData_16-08
This file was created at 16hr and 8mins.

A little inspection of this example will highlight how scanf can be used to pick valuable characters out of a known input string. In this instance, by modifying the program to read in a filename from a directory, we could create a program to list the date of each data file created if we know the format of the filenames.

In 'usingscanfa.c's' case, scanf looks in the keyboard input string for characters which can be inferred as a value of integer type. If the input only contains characters which cannot be inferred as integers, e.g any none numberical character, then scanf will store nothing new in the variables passed as arguments. If however the string passed by the keyboard does contain a character which can be inferred as an integer (e.g a number), then scanf overwrites the value of the variable "input" with that of the number found in the input string. Hence, in the case above, if no number is contained in the input string, the value of 'input' will not be changed, and so the output of the program will read:

Input now contains the number -1.

As it could be possible for users to accidentally fail to input numbers in circumstances where scanf is used, when scanf is used it is advisable to include further code to check that the input was valid, and if it was not, to return an error. See section C.2.10 for suggests on how to handle errors.

Exercise 4: A Basic Calculator

Now that we have an idea of how to use scanf as an input, lets see if we can write some of our own useful functions to give us the result of mathematical operations:

  1. In RPiiExercises, create a new directory called 'CalculatorSources' and open a new file called printresults.c.
  2. Using 'usingscanf.c' and your work from exercise 3, by adding only a few extra lines create a program which initialises two integer variables 'a' and 'b' as -1, uses scanf to record the input from the keyboard into these two variables, and prints out the sum, difference and product of the values.
    (It might be helpful to create a makefile for the files which will end up in this directory)
  3. Using the file you have just made, change the inputs to floats. (don't forget the format specifier in the scanf and printf functions) Add a line to show the result of one input divided by the other.
  4. Once we have learnt more functions, we will come back to Calculator Sources to make a more complex calculator program.

C.2.4: The while() and if() functions

A core part of computer programs are sections of code governed by while or if functions. By passing a condition as an argument to these functions, we can control whether or not a computer executes lines of code depending on other variables. Consider the example code 'comparinginputs.c', in examplesources/RPii_C-2/ExampleSources.

ExS.4a Example Source Code: comparinginputs.c

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
// Example source ExS.4a, comparinginputs.c
#include <stdio.h>

int main(){

//initialise the variable to store the keyboard input
int input = -1;

int remainderbythree = -1;

//use format specifier to indicate expected type of input
printf("Input an integer from the keyboard to see whats its remainder is when divided by 3.\n");
scanf("%d", &input);

remainderbythree = input % 3;

if(remainderbythree == 0){
printf("%d is divisible by 3.\n", input);
}
else if(remainderbythree == 1){
printf("%d has a remainder of 1 when divided by 3.\n", input);
}
else {
printf("%d has a remainder of 2 when divided by 3.\n", input);
}

return 0;
}

Within the if and while parenthesis, we can string together as many conditional statments as we like:
We use &&as an and and || as or.

Important lines to understand in ExS.4a comparinginputs.c

Line No. Comment
7. By initialising the variables to -1, it will be clear if a character was input instead as the input will remain -1.
13. The format specifier %d denotes that we want to look for an integer in the keyboard input. We then want to store this input from the keyboard in the variable 'input'.
15. For 'a % b', the % operator gives the remainder when a is divided by b. Thus remainderbythree will be assigned to either a 2, 1 or a 0 depending on the input.
17. The if statement has a conditional statement within its parenthesis. This particular statement is 'if remainderbythree IS EQUIVALENT TO 0'. Similarly to when writing the main() function, we write what we want the program to execute, should the statement be true, between curly brackets { and }.
18. This statement is between the curly brackets of the if() statement. It will print to the terminal if remainderbythree is 0. Following an if() statement, we can use an else statement, to tell the program what to do if the if() statement is not true.
20. If we want to act on multiple different values of 'remainderbythree', we use a series of if, elseif and else functions. If the first if() statement is not true, then the program progressively checks the rest of the elseif() statements. If non of those are true, then it runs the code following the else statement. You may use an if statement without an else statement.

As with all example source files, these can be found in examplesources/RPii_C-2. If you are unsure of any of the explanations copy, compile and run the example program in order to explore its output. Note that this program must be re-run for each new input value...

Now consider how we can use while() loops so that we can test as many numbers at once as we like until we choose the exit the program. Similarly to using if() functions, we put a conditional statement in between the parenthesis of a while loop( The most useful comparators are shown in table C.2.2). The program in ExS.4b repeatedly runs the code written in curly brackets after the while() statement, until the conditional statement in the parenthesis is true. ExS.4b is a slight expansion of the example code in Source ExS.4a, so that we can test as many numbers as we want without the program terminating.

ExS.4b Example Source Code: comparingmanyinputs.c

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
// Example source ExS.4b, comparingmanyinputs.c
#include <stdio.h>

int main(){

//initialise the variable to store the keyboard input
int input = -1;
int remainderbythree = -1;
printf("Input an integer from the keyboard to see whats its remainder is when divided by 3.\n");
printf("While loop will terminate if input is 0.\n");

while(input != 0){

input = -1;

scanf("%d", &input);

if(input ==-1){
printf("Invalid input, terminating program.\n");
return 1; //The function exits when it reaches a return.
//By calling this return, we cause the main function (and thus the program) to terminate
}

remainderbythree = input % 3;

if(remainderbythree == 0){
printf("%d is divisible by 3.\n", input);
}
else if(remainderbythree == 1){
printf("%d has a remainder of 1 when divided by 3.\n", input);
}
else {
printf("%d has a remainder of 2 when divided by 3.\n", input);
}

}
return 0;
}

Important lines to understand in ExS.4b comparinginputs.c

Line No. Comment
12. This is the start of the while loop. The code between lines 15 and 30 continue to run over and over again until the conditional statement "input IS NOT EQUAL TO 0" is no longer true.
14,18-22. These lines handle the possible errors which might occur. If an input is invalid, then the value of the variable input will stay at -1 after it has been reset in line 14. Thus, we can detect an invalid input by checking the value of 'input'. As a function will end when it reaches a return command, this if() statement will cause the return 1 line to be reached in the main function, and so will cause the end of the program.
36. This is the end of the while loop. Inspecting the code, we can see that this curly bracket closes the one that opens after while().

Exercise 5:Divisible by 6?

Note that the sources used to copy from can be copied directly from this webpage, or can be found in the usual location.

  1. In a new directory call Ex5and6, create a file called divisbysix.c
  2. Adapt the source in ExS.4a to write a program which prints out whether or not an input is:
    • Divisible by 3
    • Even or Odd
  3. Use a while loop so that the program only finishes when a particular input is given. Using only the %2 and %3 operations, write a program which prints out whether or not a number is divisible by 6.

Exercise 6:Counting While loops

A powerful technique commonly used in programming is to increment a variable by one and repeat a section of code - in order to perform the same routine many times. We can do this by placing a simple line of code within a while loop; say we have a variable 'a, to increment its value by 1, we can simple write:

a = a+1;

OR

a++;

This line implements: "add one to the variable 'a', and save the result in variable 'a'". By placing this line of code in a while loop, we are able to count up how many times the while loop has gone around. The RPii Motion Logger uses this very technique to count up how many samples it takes when the program runs.

  1. Copy the source from divisbysix.c used in Exercise 5 into a new source file ( in the Ex5and6 directory) called whiledivisbysix.c . In the main loop (but not in the while loop), declare another integer 'a' and set it to 0 before the while loop starts.
  2. Add the following line at the top of the while loop:
    printf("This while loop has iterated %d times.\n", a);
    and use one of the lines used above to increment 'a' at the bottom of the while loop.
  3. Compile and run this program. Use if a few times and note that the value of a should increase each time an input is evaluated.
  4. Edit your program so that instead of the while loop ending when the variable 'input' is of a certain value, it ends when a reaches the value 5.
  5. Using this concept, write a new program to print out the numbers from 0 to 10 on the screen by only using one printf line of code. (hint, copy your old program and remove all of the code which is no longer relevant).
  6. Note that we could have done this by writing a file containing:
    printf("1\n");
    printf("2\n");

    printf("10\n");
    But this would have taken a lot more lines and a lot more code. Just by changing the value in the conditional statement in the while loop, we can now easily print out all of the numbers up to 100, or 1000, whereas if we were to write out each line as above, it would take much longer to write the same program.
  7. By making a copy of dividebysix.c again, remove the scanf function, and see if you can write a program that prints out all of the numbers which are divisible by 6 up to 100 (hint, increment the value of input instead of asking for it using scanf).

Although we have found a way to iterate programs many times, the C programming language actually provides us with an even easier way. This is called the for() loop, which leads us nicely into section C.2.5.

C.2.5 The for() loop

The for() loop function is a very similar concept to the while loop, except it has 3 arguments rather than only one. Each argument is seperated by a semi-colon.

The arguments and syntax

Consider the following common for loop call:

int i;//This declares the variable befor it is used in the for loop
for ( i = 0; i<10; i++ ){
//this code is run over and over again as i increases in value
}

The first argument of a for() loop:

  1. This specifies which variable(s) will be re-intialised before the for() loop runs.
  2. These variables must be declared before they are re-initialised by the for loop.
  3. We can set as many variables as we want, each seperated by a comma, however most of the time we only need one.

The second argument of a for() loop:

  1. This argument has the same function as that used in a while loop, it is a conditional statement which will terminate the for() loop the first time it is evaluated as true.

The third argument of a for() loop:

  1. This argument includes any codewhich is to be implemented at the end of ever loop.
  2. In this case, we simply increment the value of i by 1.

If you feel like you would like to practice using for() loops now, try re-doing exercise 5 with for loops. If not, then they will be brought up in the Exploring libRPii section.

Continue to the Next Page for section C.2.6 to continue this tutorial.