Version without JavaScript, read-only: workshops, quizzes and running code are not available here. Full version · Catalogue · Sign in
Place each piece of data in its area, outwit macros, find leaks and overflows, then write code with malloc - concatenation, matrices, and a recycling pool. Chapter 3.
We assume a 64-bit PC running Linux. Programs are compiled with gcc -std=c11 -Wall -Wextra -Werror, and valgrind is available.
Exercise · Where does each piece of data live?
For each piece of data in this program, say which area it lives in (static, stack, heap, or read-only) and how long it lives. What does the program print?
#include <stdio.h>
#include <stdlib.h>
int compteur;
const char *nom = "zones" ;
int *suivant(void )
{
static int n = 0 ;
int *p = malloc(sizeof *p);
if (p != NULL )
*p = ++n;
compteur++;
return p;
}
int main(void )
{
int *a = suivant();
int *b = suivant();
if (a == NULL || b == NULL )
return 1 ;
printf("%s : %d %d %d\n" , nom, *a, *b, compteur);
free(a);
free(b);
return 0 ;
}
The data: compteur, nom, the string "zones", n, p, the integer pointed to by p, a, b.
Exercise · Macros
What does this program print? Fix the macros so that it does what is expected.
#include <stdio.h>
#define DOUBLE(x) x + x
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int main(void )
{
int i = 5 , j = 3 ;
int m;
printf("%d\n" , 3 * DOUBLE(2 ));
m = MAX(i++, j);
printf("m = %d, i = %d\n" , m, i);
return 0 ;
}
Exercise · A concatenation
We want a function that returns the concatenation of two strings.
#include <stdio.h>
#include <string.h>
char *concat(const char *a, const char *b)
{
char buf[100 ];
strcpy(buf, a);
strcat(buf, b);
return buf;
}
int main(void )
{
printf("%s\n" , concat("bon" , "jour" ));
return 0 ;
}
Find the two problems with this function. What does gcc -Wall say? Rewrite it correctly. Who must free the result? Say so in a comment.
Exercise · What valgrind sees
This program compiles without warnings and prints 0 then 14, which is correct.
#include <stdio.h>
#include <stdlib.h>
int *carres(size_t n)
{
int *t = malloc(n * sizeof *t);
for (size_t i = 0 ; i < n; i++)
t[i] = i * i;
return t;
}
int somme_carres(size_t n)
{
int *t = carres(n);
int s = 0 ;
if (n == 0 )
return 0 ;
for (size_t i = 0 ; i <= n; i++)
s += t[i];
free(t);
return s;
}
int main(void )
{
printf("%d\n" , somme_carres(0 ));
printf("%d\n" , somme_carres(4 ));
return 0 ;
}
Find the three errors, without running it. Why does the program still print the right result? Fix it.
Exercise · Matrices on the heap
We want a matrix of integers with h rows and w columns, whose dimensions are only known at run time, and in which we can write m[y][x].
Write int **matrice_nouvelle(size_t h, size_t w), which reserves an array of h pointers, then a row of w zero integers for each of them. If an allocation fails, everything already reserved must be freed, and the function returns NULL. Write void matrice_liberer(int **m, size_t h). Compare with a single block calloc(h * w, sizeof (int)), accessed through m[y * w + x]: number of calls to malloc, ease of freeing, memory footprint.
Exercise · A recycling pool
A linked list constantly allocates and frees nodes, all of the same size:
struct noeud {
int valeur;
struct noeud *suivant;
};
We want to replace malloc and free with a pool of 1024 nodes, reserved in one go:
#define POOL_TAILLE 1024
struct pool {
struct noeud blocs[POOL_TAILLE];
struct noeud *libres;
};
libres is the list of free nodes, linked through their own suivant field : a free node does not need its value, so its space is reused.
Write void pool_init(struct pool *p), which links the 1024 blocks into the free list. Write struct noeud *pool_allouer(struct pool *p) (returns NULL if the pool is exhausted) and void pool_liberer(struct pool *p, struct noeud *n). What is their cost? In main, should the pool be declared as a local variable? How many bytes does it take up?