Memory Management and the Standard Library: Exercises
See here how to set up a development environment to do these exercises.
- You should complete the essential exercises if you want to claim you know how to program in C.
- If you want to go further and make sure you understand everything, you can also complete the additional exercises.
Essential Exercises
- Working with pointers
- Working with pointers (2)
- Dynamic memory allocation with
malloc
- Dynamic memory allocation with
malloc
(2) - Dynamic memory allocation with
malloc
(3) - Standard input and string comparison
- Sleeping and measuring execution time
- File I/O
Working with Pointers
Consider the following program:
#include <stdio.h>
#include <stdlib.h>
int add(int a, int b) {
return a + b;
}
int main(int argc, char **argv) {
if(argc == 3) {
int a = atoi(argv[1]);
int b = atoi(argv[2]);
printf("%d + %d = %d\n", a, b, add(a, b));
}
return 0;
}
Modify the function add
and its invocation so that it takes two int
pointer parameters. Examples of output:
./pointer 10 20
10 + 20 = 30
./pointer 154 -12
154 + -12 = 142
To check the correctness of your program, use a use a Linux distribution with check50 installed and write your solution in a file named pointer.c
.
In a terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/01-pointer
Working with Pointers (2)
With a linked list, the programmer uses pointer chains to link together data structures. In the example program below, a simple linked list with 3 elements is constructed then the value of the last element is printed:
#include <stdio.h>
/* Typedef struct forward declaration for the pointer member */
typedef struct s_list_member list_member;
typedef struct s_list_member {
int value;
list_member *next;
} list_member;
int main(int argc, char **argv) {
list_member lm1, lm2, lm3;
lm1.value = 1; lm1.next = &lm2;
lm2.value = 2; lm2.next = &lm3;
lm3.value = 3; lm3.next = 0x0;
printf("third member value is: %d\n", lm3.value);
return 0;
}
Modify the second parameter of the call to printf
in order to print the value of the third element by using the first member lm1
and following the pointer chain leading to the value of lm3
. The expected output is:
./pointer2
third member value is: 3
To check the correctness of your program, use a use a Linux distribution with check50 installed and write your solution in a file named pointer2.c
.
In a terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/02-pointer2
Dynamic Memory Allocation with malloc
Write a program taking a list of integers as command line parameters, storing them in an array allocated with malloc
, and sorting that array in increasing order.
Output examples:
./malloc 5 4 3 2 1
1 2 3 4 5
./malloc 546 874 18 13 87 54 4651 54 877 8 46351 87 654 657 654
8 13 18 54 54 87 87 546 654 654 657 874 877 4651 46351
To check the correctness of your program, use a use a Linux distribution with check50 installed and write your solution in a file named malloc.c
.
In a terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/03-malloc
Dynamic Memory Allocation with malloc
(2)
Write a C program that takes two integers as command line parameter, x
and y
, and prints on the standard output y
lines of x
integers corresponding to the first (x * y
) natural integers.
The numbers should be stored in a 2-dimensional array allocated with malloc
before being printed.
# 3 rows, 4 columns
./malloc2 3 4
0 1 2 3
4 5 6 7
8 9 10 11
./malloc2 2 5
0 1 2 3 4
5 6 7 8 9
./malloc2 10 11
0 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 101 102 103 104 105 106 107 108 109
To check the correctness of your program, use a use a Linux distribution with check50 installed and write your solution in a file named malloc2.c
.
In a terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/04-malloc2
Dynamic Memory Allocation with malloc
(3)
Fix the memory leak contained in the following program:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
int *a = malloc(10 * sizeof(int));
if(!a) return -1;
for(int i=0; i<10; i++)
a[i] = i*2;
int *b = a;
for(int i=0; i<10; i++)
printf("%d ", b[i]);
printf("\n");
return 0;
}
The expected output is:
./malloc3
0 2 4 6 8 10 12 14 16 18
To check the correctness of your program, use a use a Linux distribution with check50 installed and write your solution in a file named malloc3.c
.
In a terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/05-malloc3
Standard Input and String Comparison
Write a C program reading two strings from the standard input using fgets
, and indicating if the strings are similar or not.
Output examples:
./string
input string1:
test
input string2:
test
strings are similar
./string
input string1:
hello world!
input string2:
goodbye
strings are different
To check the correctness of your program, use a use a Linux distribution with check50 installed and write your solution in a file named string.c
.
In a terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/06-string
Sleeping and Measuring Execution Time
Write a C program taking an integer n
as command line parameter and sleeping for n
seconds.
The execution time of the sleep
function is measured and displayed. Examples output:
./time 3
sleep duration: 3.000082 seconds
./time 5
sleep duration: 5.000108 seconds
To check the correctness of your program, use a
use a Linux distribution with check50 installed
and write your solution in a file named time.c
. In a
terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/07-time
File I/O
Write a C program taking as command line parameter A) a file name f
and B) a word w
.
The program then creates the file f-processed
which is a copy of f
where all occurrences of the word w
have been deleted.
Here is an example of execution:
cat sample-file-1
hello world
this is a test file containing the word hello several times
some lines do not contain that word
while others do: hello
./file sample-file-1 hello
cat sample-file-1-processed
world
this is a test file containing the word several times
some lines do not contain that word
while others do:
You download sample-file-1
here.
To check the correctness of your program, use a use a Linux distribution with check50 installed and write your solution in a file named file.c
.
In a terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/08-file
Make sure that sample-file-1
is in the current directory alongside file.c
Additional Exercises
- Working with pointers (3)
- Working with pointers (4)
- Dynamic memory allocation with
malloc
(4) - Dynamic memory allocation with
malloc
(5) - String manipulation
- Copying data in memory with
memcpy
- Math operations
- String to integer conversion with
strtol
- Stream-based file I/O
Working with Pointers (3)
Write a program that takes an integer as parameter and places it in a variable of type int
.
The program then proceeds to print the value as well as the address of the variable as follows:
./pointer3 5
Variable contains 5 and is located @0x7ffcc6d1d7fc
./pointer3 93
Variable contains 93 and is located @0x7fffec3b3dfc
Printing pointers. Pointer can be printed in hexadecimal and prefixed with
0x
using the%p
format specifier forprintf
.
To check the correctness of your program, use a use a Linux distribution with check50 installed and write your solution in a file named pointer3.c
.
In a terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/09-pointer3
Working with Pointers (4)
Consider the following program printing a string to the standard output character by character:
#include <stdio.h>
int main(int argc, char **argv) {
char *string = "hello, world!\n";
int i = 0;
while(string[i] != '\0')
printf("%c", string[i++]);
return 0;
}
Alter the loop to use a char *
pointer as the iterator and as the way to access characters within the string for printing.
The source code should contain no square bracket.
The expected output is:
./pointer4
hello, world!
To check the correctness of your program, use a
use a Linux distribution with check50 installed
and write your solution in a file named pointer4.c
. In a
terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/10-pointer4
Dynamic Memory Allocation with malloc
(4)
Write a C program using malloc
to allocate an array able to contain 10 int
, fill this array with the 10 first natural number (starting with 0).
The expected output is:
./malloc4
0
1
2
3
4
5
6
7
8
9
To check the correctness of your program, use a use a Linux distribution with check50 installed and write your solution in a file named malloc4.c
.
In a terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/11-malloc4
Dynamic Memory Allocation with malloc
(5)
Consider the following program:
#include <stdio.h>
#include <stdlib.h>
void *my_realloc(void *ptr, size_t old_size, size_t new_size) {
/* complete here */
}
int main(int argc, char **argv) {
/* first malloc space for 5 int */
int *array = malloc(5 * sizeof(int));
if(!array) return -1;
for(int i=0; i<5; i++) {
array[i] = i*10;
printf("before realloc, array[%d] = %d\n", i, array[i]);
}
/* expand the size to 10 int */
array = my_realloc(array, 5*sizeof(int), 10*sizeof(int));
if(!array) return -1;
for(int i=5; i<10; i++)
array[i] = i*10;
for(int i=0; i<10; i++)
printf("after realloc, array[%d] = %d\n", i, array[i]);
free(array);
return 0;
}
Write the function my_realloc
that changes the size of a buffer previously allocated with malloc
while preserving all or part of the buffer content according to the requested size.
The function parameters are:
ptr
: buffer addressold_size
: current size of the buffernew_size
: new size requested
The expected output is:
before realloc, array[0] = 0
before realloc, array[1] = 10
before realloc, array[2] = 20
before realloc, array[3] = 30
before realloc, array[4] = 40
after realloc, array[0] = 0
after realloc, array[1] = 10
after realloc, array[2] = 20
after realloc, array[3] = 30
after realloc, array[4] = 40
after realloc, array[5] = 50
after realloc, array[6] = 60
after realloc, array[7] = 70
after realloc, array[8] = 80
after realloc, array[9] = 90
Memory copy in C. Memory copy is achieved with the
memcpy
function that takes 3 arguments: the destination address, the source address, and the number of bytes to copy. To use it you'll need to#include <string.h>
. See here for more information.
Realloc. Although this functionality already exists in the form of the standard function
realloc
(see here -- for the sake of the exercise it is asked to implement it manually here.
To check the correctness of your program, use a use a Linux distribution with check50 installed and write your solution in a file named malloc5.c
.
In a terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/12-malloc5
String Manipulation
Write a C program reading a string from the standard input and capitalise the first letter of each word.
./string2
input a string:
we swears, to serve the master of the precious
We Swears, To Serve The Master Of The Precious
./string2
input a string:
and following our will and wind we may just go where no one's been
And Following Our Will And Wind We May Just Go Where No One's Been
Capitalising letters. See the
toupper
function: https://linux.die.net/man/3/toupper
To check the correctness of your program, use a use a Linux distribution with check50 installed and write your solution in a file named string2.c
.
In a terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/13-string2
Copying Data in Memory with memcpy
Write a C program taking an integer n
as command line parameter, allocating an array of integer of size n
, and filling that array with random integers -- each between 0 and 100.
Next, a second array of size n
is created and the content of the first array is copied into the second one with a single call to memcpy
.
Finally, both arrays are printed.
Example output:
./memcpy 10
array1: 32 32 54 12 52 56 8 30 44 94
array2: 32 32 54 12 52 56 8 30 44 94
./memcpy 15
array1: 32 32 54 12 52 56 8 30 44 94 44 39 65 19 51
array2: 32 32 54 12 52 56 8 30 44 94 44 39 65 19 51
Random Numbers. See the
rand
function: https://linux.die.net/man/3/rand. For example to get a random integer between 0 and 9 (included):int random_int = rand()%10
.
To check the correctness of your program, use a use a Linux distribution with check50 installed and write your solution in a file named memcpy.c
.
In a terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/14-memcpy
Math Operations
Write a C program reading a double
with scanf
and asking the user if he wants this number to be floored or ceiled.
Next, the program performs the requested operation and displays the result. Output examples:
./math
Input a number:
12.4
Input 0 for ceil, 1 for floor
0
13.000000
./math
Input a number:
45.87
Input 0 for ceil, 1 for floor
1
45.000000
To check the correctness of your program, use a use a Linux distribution with check50 installed and write your solution in a file named math.c
.
In a terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/15-math
String to integer conversion with strtol
The program strtol.c converts a string entered by the user into an integer and prints it on the standard output.
The conversion is realised with atoi
, and as such it is not robust in case of malformed strings as well as under/overflows.
Modify the implementation of the function convert_and_print
in this program to use strtol
for the conversion rather than atoi
, and make the program more robust against improper inputs.
Output examples:
$ ./strtol
please enter an integer number (base 10): 1234
you have entered: 1234
$ ./strtol
please enter an integer number (base 10): foo
invalid string
$ ./strtol
please enter an integer number (base 10): 100000000000000000000
under/overflow
$ ./strtol
please enter an integer number (base 10): -100000000000000000000
under/overflow
To check the correctness of your program, use a use a Linux distribution with check50 installed and write your solution in a file named strtol.c
.
In a terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/16-strtol
Stream-Based File I/O
This is a variation of a previous exercise targeting file I/O.
The goal is similar: write a C program taking as command line parameter A) a file name f
and B) a word w
.
The program then creates the file f-processed
which is a copy of f
where all occurrences of the word w
have been deleted.
This time, you should use the stream-based file I/O functions (fopen
, fread
, and fwrite
) to write the program.
Here is an example of execution:
cat sample-file-1
hello world
this is a test file containing the word hello several times
some lines do not contain that word
while others do: hello
./stream sample-file-1 hello
cat sample-file-1-processed
world
this is a test file containing the word several times
some lines do not contain that word
while others do:
You download sample-file-1
here.
To check the correctness of your program, use a use a Linux distribution with check50 installed and write your solution in a file named stream.c
.
In a terminal, with that file in the local directory, check with this command:
check50 -l --ansi-log olivierpierre/comp26020-problems/2024-2025/week3-c-pointers-stdlib/17-stream
Make sure that sample-file-1
is in the current directory alongside stream.c