C Programming Lab: Submitting Assignments, and Requirements For Passing This Lab
C Programming Lab: Submitting Assignments, and Requirements For Passing This Lab
Note: all submitted solutions are stored, and might manually be checked for correctness or signs of cheating at a later point.
cp <file1> <file2>
mkdir <dir>
Ctrl+C
<command> &
gcc file.c -o output
gcc file.c -c -o file.o
emacs file.c &
./program
i n t main ( i n t a r g c , char a r g v ) {
p r i n t f ( This t e x t i s p r i n t e d t o t h e s c r e e n \n ) ;
return 0 ;
}
// p r i n t f u n . c
#include <s t d i o . h>
/
Function i m p l e m e n t a t i o n
/
void p r i n t f u n ( ) {
p r i n t f ( This t e x t i s p r i n t e d t o t h e s c r e e n \n ) ;
}
Compilation now requires three calls to gcc: two to compile the C files to
object files (with option -c), and one for the final linking to an executable:
~/example]$ gcc -Wall example2.c -c -o example2.o
~/example]$ gcc -Wall printfun.c -c -o printfun.o
~/example]$ gcc -Wall example2.o printfun.o -o example2
~/example]$ ./example2
This text is printed to the screen
~/example]$
Compilation is usually automated with the help of a build system, for
instance with the tool make. The compilation steps are defined in a file
named Makefile; for each file that is supposed to be generated through
compilation or linking (here, example2.o, printfun.o, and example2) a
set of commands is specified that produces the file. The Makefile also defines dependencies between source and target files: for instance, example2.o
depends on example2.c and printfun.h, whenever any of the latter two
files change, also example2.o has to be recomputed:
# Makefile
a l l : example2
example2 . o : example2 . c p r i n t f u n . h
g c c Wall example2 . c c o example2 . o
printfun . o : printfun . c
g c c Wall p r i n t f u n . c c o p r i n t f u n . o
example2 : example2 . o p r i n t f u n . o
g c c Wall example2 . o p r i n t f u n . o o example2
~/example]$ make
gcc -Wall example2.c -c -o example2.o
gcc -Wall printfun.c -c -o printfun.o
gcc -Wall example2.o printfun.o -o example2
~/example]$ ./example2
This text is printed to the screen
~/example]$
Exercises
Now that we know how to create and run a program, we move on to the
exercises. The solutions to (most of) the exercises will be provided after
the end of the lab. Please refer to the slides for more information on C
programming.
Exercise 1
Output
In the introductory program we include the library stdio.h, which contains the function printf. This function is used to produce output in the
form of characters that are printed in the terminal. In its simplest form, the
function is called with a string as argument:
printf("This text is printed to the screen\n");
That is great, but we want our programs to output more than just the fixed
strings that the programmer writes in the program. To print the contents
of variables, we add format specifiers to the string and add the variables we
want to print as arguments:
int number;
char letter;
printf("%d is an integer and %c is a character\n", number, letter);
Different types of variables have different specifiers, all starting with a percentage sign. Common specifiers are %d for integers, %f for floats, %c for
characters and %s for strings. To output a percentage sign, we use %%.
Write a function that outputs:
a) The string: One half is 50%
b) two integers and their difference.
c) two floats and the result of dividing one with the other
Write a main function that calls your other functions. The output has to be
as follows:
[.../exercise]$ ./e1
One half is 50%
The difference between 10 and 3 is 7
1.000000 / 3.000000 is 0.333333
[.../exercise]$
Exercise 2
Input
For input we use the function scanf, also from the library stdio.h. The
scanf function takes a format string followed by references to where the
input should be stored. Example that reads an integer to a variable:
6
int number;
scanf("%d", &number);
Notice that the & character in front of the varable name. It means that
the variable is passed as reference to scanf. It allows scanf to update the
value of the variable. If & is not there, the program would likely crash at
that point. When reading a string, the & sign can be omitted:
char my_variable[100];
scanf("%s", my_variable);
Write functions that:
a) asks for two integers and outputs them and their sum.
b) asks for two floats and outputs their product.
c) asks for a word and prints it twice on the same row.
Write a main function that calls your other functions. The output has to be
as follows:
[.../exercise]$ ./e2
Give two integers: 12 5
You entered 12 and 5, their sum is: 17
Give two floats: 3.14 2
You entered 3.140000 and 2.000000, their product is: 6.280000
Give a word: Yey!
Yey! Yey!
[.../exercise]$
Exercise 3
Conditionals
Exercise 4
Loops
printf("%d
i=i+1;
", i);
}
printf("\n");
for(j=11;j<=20;j++){
printf("%d ", j);
}
printf("\n");
Write functions that:
a) print all even numbers between 0 and 40.
b) print all the numbers between 1 and 100, with 10 numbers on each
line. Use two for loops. All columns should be aligned.
c) ask for a number than prints the number squared. This repeats until
the 0 is entered.
Write a main function that calls your other functions. The output has to be
as follows:
[.../exercise]$ ./e4
Even numbers between 0 and 40:
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40
Numbers 1 to 100:
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 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
91 92 93 94 95 96 97 98 99 100
Give a number: 2
The square of 2 is 4
Give a number: 5
The square of 5 is 25
Give a number: 9
The square of 9 is 81
Give a number: 0
You entered zero.
[.../exercise]$
Exercise 5
Loops II
a) Write a program that asks for a number. Then the program should
print 1 through the given number on separate lines.
b) Encapsulate your code in a while-loop that asks the user if he/she
would like to run the program again. Note that when reading a character from the input stream, the newline from the previous input is
still buffered and considered as input. To discard the newline, start
the scanf string with a space like this: scanf(" %c", &input);.
The output has to be as follows:
[.../exercise]$ ./e5
Give a number: 5
1
2
3
4
5
Run again (y/n)? y
Give a number: 2
1
2
Run again (y/n)? n
Exiting...
[.../exercise]$
Exercise 6
Functions
Functions are a great way to make code reusable, improve the structure of
the code and isolate errors. Write functions that:
a) take two floats as argument and returns the minimum of those.
b) take four floats as argument and returns the minimum. Make use of
the function defined in a).
c) are the same as in a) and b), but returns the maximum.
d) take four floats as argument and returns their sum.
Write a main function that asks the user for four floats and then outputs the
minimum, maximum, their sum and mean value. Use the functions from a)
- d) to implement this. The output has to be as follows:
10
[.../exercise]$ ./e6
Give four floats: 10.0 -2.3 13.2 20.4
min: -2.300000
max: 20.400000
sum: 41.299999
mean: 10.325000
[.../exercise]$
Exercise 7
Functions II
Exercise 8
Arrays
11
Write a main function that asks the user to input 10 integers and stores
them in an array. Use your other functions to print the initial array, the
number of zero-valued elements in the array and the contents of the array
when all elements have been tripled. The output has to be as follows:
[.../exercise]$ ./e8
Input 10 numbers: 1 2 3 0 -3 -2 -1 0 10 11
Initial array: { 1, 2, 3, 0, -3, -2, -1, 0, 10, 11 }
Number of 0s: 2
Tripled array: { 3, 6, 9, 0, -9, -6, -3, 0, 30, 33 }
[.../exercise]$
Exercise 9
In this exercise, you will practice how to program with pointers and
strings. Without using any library functions, write a C function
void append(char* str1, char* str2) { ... }
that takes as argument two strings str1, str2 and appends str2 to str1.
After calling append, the pointer str1 is supposed to point to the concatenation of (the original) str1 and str2. The caller of append has to make
sure that enough memory for the result of concatenation is available at the
memory address that str1 points to.
Example
char x[12] = { H, e, l, l, o, ,
0, 1, 2, 3, 4, 5 };
char *y = "world";
append(x, y);
// now "x" contains the string "Hello world"
Your implementation needs to make sure that the output string (pointed
to by str1) remains a well-formed string. Recall that, by definition, a string
in C is an array of characters terminated with zero.
Write a main function that asks the user to input 2 words and stores
them in character arrays. Then use your append function to append the
second word to the first, and output the result. The output has to be as
follows:
[.../exercise]$ ./e9
Enter first word: Hello
Enter second word: World
Result of append: HelloWorld
[.../exercise]$
12
Exercise 10
Exercise 11
Write the function threeColorsSort that takes as input an array of integers in the range of 0 and 2 (0, 1 and 2 only), and arranges them in an
increasing order:
void threeColorsSort(int * theArray, int arraySize)
Your solution should have linear runtime in the parameter arraySize.
Then, write a program that asks the user for how many numbers to
input, and then for the actual numbers. The program should then output
the same numbers in ascending order. Make sure to free up your allocated
memory.
The output has to be as follows:
[.../exercise]$ ./e11
Number of inputs: 5
Give number 0: 2
Give number 1: 1
Give number 2: 0
Give number 3: 1
Give number 4: 1
Input when sorted:
0
1
1
1
2
[.../exercise]$
Exercise 12
Recursion
previous two numbers. The nth number in the sequence can be calculated
as:
f (1) = 1
f (2) = 1
f (n) = f (n 1) + f (n 2)
See the example for the seven first numbers in the sequence.
a) Write a C function with a parameter n that returns the nth Fibonacci
number. The function must be recursive, i.e., it should call itself.
b) Write a program that asks the user for a number n and then prints
the n first numbers in the Fibonacci sequence.
The output has to be as follows:
[.../exercise]$ ./e12
Give n: 7
1
1
2
3
5
8
13
[.../exercise]$
Exercise 13
Write a second function for computing the Fibonacci sequence that uses
a loop instead of recursion, and that has linear runtime in the given input.
The output has to be as follows (negative numbers occur as a result of
arithmetic overflow):
[.../exercise]$ ./e13
Give n: 100
1
1
2
3
5
8
13
[...]
708252800
-798870975
-90618175
15
-889489150
-980107325
[.../exercise]$
Exercise 14
2
4
6
8
3
6
9
12
4
8
12
16
5
10
15
20
6
12
18
24
7
14
21
28
8
16
24
32
9
18
27
36
10
20
30
40
11
22
33
44
12
24
36
48
[.../assignment3]$
10
15
20
25
30
35
40
45
50
55
60
Exercise 15
12
18
24
30
36
42
48
54
60
66
72
Write a program where you declare a structure for a doubly linked list.
The struct should contain a pointer to a string (name) as a key, a pointer to
the previous element, a pointer to the next element and a birthdate. Please
refer to the linked list C-code on the lecture slides for inspiration. Instantiate
a list with input from stdio. End with inputing Q as name. Then output
the list sorted alphabetically by name according to ASCII. Your solution
should work for an arbitrary number of elements, with a maximum name
length of at least 20 characters. Dont forget to free everything you allocate.
The output has to be as follows:
[.../exercise]$ ./e15
Name (Q to quit): Felix
Birthdate: 20121224
Name (Q to quit): Erica
Birthdate: 19980613
Name (Q to quit): Dawn
Birthdate: 19831004
Name (Q to quit): Charles
Birthdate: 19670225
Name (Q to quit): Benny
Birthdate: 20010810
Name (Q to quit): Astrid
Birthdate: 19901105
Name (Q to quit): Greg
Birthdate: 19940423
Name (Q to quit): Q
Astrid, 19901105
Benny, 20010810
Charles, 19670225
17
Dawn, 19831004
Erica, 19980613
Felix, 20121224
Greg, 19940423
[.../exercise]$
Exercise 16
Function pointers
Give number 4: -3
Result of applying op_double: { 20, 18, 16, -2, -6 }
Result of applying op_reset: { 0, 0, 0, 0, 0 }
Result of applying op_invert: { -10, -9, -8, 1, 3 }
[.../exercise]$
Exercise 17
Write a program that reads an integer n as input, and outputs the number of bits that are set in the binary representation of n. Can you write this
program without using bit-shifts <<, >> (or multiplication/division by 2)?
The output has to look as follows:
[.../exercise]$ ./e17
Enter a number: 42
The number of bits set in 42 is 3
[.../exercise]$
Exercise 18
A finite directed graph is a tuple (V, E), where V is a finite set of nodes,
and E V 2 a set of directed edges. A strongly connected component
(SCC) in a directed graph is a maximum subset C V such that the graph
contains a path s0 s1 sn for any two nodes s0 , sn C. Efficient
computation of SCCs is important in various application domains, and can
be used to reduce any graph to a directed acyclic graph (DAG).
Write a program that lets the user input a directed graph and computes
the SCCs of the graph; the SCCs have to be output sorted and in lexicographic order. Can you write a program that runs in time linear in the size
of the graph?
The output has to look as follows:
[.../exercise]$ ./e18
Enter the number of nodes: 4
Graph contains nodes 0, 1, 2, 3
Enter the edges (-1 to terminate):
0 -> 1
1 -> 2
2 -> 1
2 -> 3
-1
The strongly connected components are:
{ 0 }
{ 1, 2 }
{ 3 }
[.../exercise]$
20