Documente Academic
Documente Profesional
Documente Cultură
Allocation dynamique
Lorsque l’on déclare un tableau, il est obligatoire de préciser sa taille à l’aide d’une constante.
Cela signifie que la taille d’un tableau doit être connue à la compilation. Alors, que faire si l’on ne
connait pas cette taille ? La seule solution qui se présente pour le moment est le surdimensionne-
ment, on donne au tableau une taille très élevée de sorte qu’aucun débordement ne se produise.
Nous aimerions procéder autrement, c’est-à-dire préciser la dimension du tableau au moment de
l’exécution.
La fonction qui permet, lors de son appel, de réserver n octets est malloc(n) qui retourne
l’adresse mémoire du premier octet de la zone réservée. Si vous écrivez malloc(10), le système
réserve 10 octets, cela s’appelle une allocation dynamique, c’est-à-dire une allocation de la
mémoire au cours de l’exécution. Si vous voulez réserver de l’espace mémoire pour stocker un int
par exemple, il suffit d’appeler malloc(4), car un int occupe 4 octets en mémoire.
La fonction malloc retourne l’adresse mémoire du premier octet de la zone réservée. Par
conséquent, si vous voulez créer un int, il convient d’exécuter l’instruction : p = malloc(4);
où p est de type int *. Cette affectation place donc dans p l’adresse mémoire du int. Voici un
� �
exemple d’allocation dynamique :
1 #include<stdio.h>
2 #include <stdlib.h>
3 int main()
4 {
5 int* p;
6 p = malloc(4);
7 *p = 28;
8 printf ("%d\n", *p);
9 return 0;
� �
10 }
Remarque : La fonction malloc renvoie un pointeur de type void * parce qu’il ne sait pas le
type de données que vous souhaitez stocker dans l’espace qu’il vient d’allouer. Il y a donc un
transtypage (cast) implicite qui est effectué lorsque l’adresse est stockée dans le pointeur (int*
49
IUT de Villetaneuse
dans l’exemple). Il est possible de transtyper de manière explicite la valeur retournée pour qu’elle
corresponde au type de pointeur dans lequel vous stockez l’adresse de la mémoire allouée. Ainsi,
il est possible d’écrire p = (int*) malloc(4);
Remarque : Pour utiliser les fonctions relatives à l’allocation dynamique, telles que la fonction
malloc, il faut inclure le fichier stdlib.h.
Attention : L’appel de la fonction malloc réserve de l’espace en mémoire mais ne fait aucune
initialisation. On ne peut donc pas prévoir les valeurs contenues dans l’espace alloué.
8 int main()
9 {
10 printf ("Nombre d’octets pour stocker un entier : %lu\n",sizeof(int));
11 printf ("Nombre d’octets pour stocker un flottant : %lu\n",sizeof(double));
12 printf ("Nombre d’octets pour stocker un caractère : %lu\n",sizeof(char));
13 printf ("Nombre d’octets pour stocker un point : %lu\n",sizeof(point));
14 return 0;
� �
15 }
� �
affiche :
1 Nombre d’octets pour stocker un entier : 4
2 Nombre d’octets pour stocker un flottant : 8
3 Nombre d’octets pour stocker un caractère : 1
� �
4 Nombre d’octets pour stocker un point : 8
Remarque : %lu indique que l’on souhaite afficher un entier long non signé (c’est-à-dire positif
ou nul), qui est le type retourné par la fonction sizeof.
Lors de l’appel de la fonction malloc, il convient d’utiliser la fonction sizeof pour indiquer
le nombre d’octets à réserver. Ainsi, pour allouer dynamiquement un entier, l’instruction devient
int *p = malloc(sizeof(int));.
� �
Langage C �50 � 1ère année (2014/2015)
Département informatique
� �
1 #include <stdio.h>
2 #include <stdlib.h>
3 int main()
4 {
5 int* p = malloc(sizeof(int));
6 if (p == NULL)
7 {
8 printf ("Plus assez de mémoire pour l’allocation\n");
9 exit (1); /* La fonction exit termine le programme quel que soit l’endroit dans le programme
10 où elle est appelée. Pour pouvoir l’utiliser, il faut inclure le fichier stdlib.h */
11
12 }
13 *p = 28;
14 printf ("%d\n", *p);
15 return 0;
� �
16 }
� �
de la zone à libérer. Voici un exemple :
1 #include<stdio.h>
2 #include <stdlib.h>
3 int main()
4 {
5 int * p = malloc(sizeof(int));
6 *p = 28;
7 printf ("%d\n", *p);
8 free (p);
9 return 0;
� �
10 }
Remarque : Si l’adresse passée en paramètre de la fonction free est NULL, aucune libération
mémoire n’est faite.
Attention : Quel que soit l’endroit où la fonction malloc est appelée dans le programme, l’espace
alloué n’est libéré qu’à l’appel de la fonction free (avec en paramètre l’adresse du premier octet
alloué), ou à la fin du programme. En particulier, une allocation dynamique faite à l’intérieur
d’une fonction n’est pas automatiquement libérée à la fin de l’appel de la fonction.
� Sur ce thème : Exercice 1, Questions 1 à 4, TD5
� Sur ce thème : Exercice 2, TD5
� �
1 #include<stdio.h>
2 #include <stdlib.h>
3
18 int main()
19 {
20 int N;
21 printf ("Veuillez saisir le nombre de cases : ");
22 do
23 {
24 scanf("%d",&N);
25 }
26 while (N <= 0);
27
28 int* t;
29 t = malloc(N*sizeof(int));
30 if (t == NULL)
31 {
32 printf ("Le tableau n’a pas pu être alloué\n");
33 exit (1);
34 }
35 initTab (t, N);
36 afficheTab (t, N);
37 free (t);
38 return 0 ;
� �
39 }
� �
Langage C �52 � 1ère année (2014/2015)
Département informatique
Question 1.3 : Le programme est-il correct ? Si oui, qu’affiche-t-il ? Représenter la mémoire lors
� �
de l’exécution du programme.
1 int main()
2 {
3 int * p = malloc(sizeof(int));
4 *p = 5;
5 printf ("valeur : %d\n",*p);
6
7 p = malloc(sizeof(int));
8 *p = 18;
9 printf ("valeur : %d\n",*p);
10
11 return 0;
� �
12 }
Correction :
Le programme fonctionne mais n’est pas correct puisque l’on ne désalloue pas la mémoire. De plus, comme on n’a
pas sauvegardé la première zone mémoire allouée, on ne peut plus y accéder. Le programme affiche 5 puis 18. Il y
a dans la mémoire, lors de l’exécution 3 zones utilisées : une pour stocker la variable p et deux autres pour chacune
des allocations. �
Question 1.4 : Le programme est-il correct ? Si oui, qu’affiche-t-il ? Représenter la mémoire lors
� �
de l’exécution du programme.
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main()
5 {
6 int * p1 = malloc(sizeof(int));
7 int * p2 = malloc(sizeof(int));
8
9 *p1 = 5;
10 *p2 = 5;
11
12 if (p1==p2)
13 printf ("Premier test vrai\n");
� �
1ère année (2014/2015) �53 � Langage C
IUT de Villetaneuse
14 else
15 printf ("Premier test faux\n");
16
17 if (*p1==*p2)
18 printf ("Deuxième test vrai\n");
19 else
20 printf ("Deuxième test faux\n");
21
22 free (p1);
23 free (p2);
24 return 0;
� �
25 }
Correction :
Le programme est correct. Il affiche Premier test faux puis Deuxième test vrai. En effet, comme il y a deux
malloc, il y a deux endroits différents alloués en mémoire, les valeurs des pointeurs p1 et p2 sont donc deux adresses
différentes. Par contre, les valeurs dans les zones allouées sont les mêmes (elles valent toutes les deux 5). �
4 void alloue(double * p)
5 {
6 p = malloc(sizeof(double));
7 }
8
9 int main()
10 {
11 double * p1;
12 double * p2;
13 alloue (p1);
14 alloue (p2);
15
� �
25 }
Correction :
Le programme n’est pas correct. La mémoire n’est pas désallouée. Plus grave encore, lors de l’appel de la fonction
alloue, le paramètre p (pointeur sur double) est passé par copie. À la fin de l’appel de la fonction alloue, l’adresse
de la mémoire allouée est donc perdue ! Il faut modifier la fonction alloue. Puisque l’on veut modifier la valeur du
� �
paramètre p, il faut passer celui-ci par adresse. On obtient donc :
6 int main()
� �
Langage C �54 � 1ère année (2014/2015)
Département informatique
7 {
8 ...
9 alloue (&p1);
10 ...
11 alloue (&p2);
12 ...
� �
13 }
Il est sinon possible de retourner l’adresse de la mémoire allouée par la fonction alloue. Dans ce cas, on n’a plus
� �
besoin de paramètre :
1 double * alloue()
2 {
3 return malloc(sizeof(double));
4 }
5
6 int main()
7 {
8 ...
9 p1 = alloue();
10 ...
11 p2 = alloue();
12 ...
� �
13 }
� �
Il faut finalement, à la fin du programme désallouer la mémoire avec les instructions :
1 free (p1);
� � �
2 free (p2);
� �
Question 1.6 : Le programme suivant est-il correct ? Si oui, qu’affiche-t-il ?
1 #include<stdio.h>
2 #include <stdlib.h>
3
4 int main()
5 {
6 int * tab1 = malloc(4 * sizeof(int));
7 int i;
8 for(i = 0 ; i < 4 ; i++)
9 tab1[i] = i;
10 int * tab2 = malloc(3 * sizeof(int));
11 for(i = 0 ; i < 3 ; i++)
12 tab2[i] = 100 + i;
13
� �
22 }
Correction :
� �
Le programme est correct. Il affiche :
� �
2 Premier élément de tab2 : 0
� �
1ère année (2014/2015) �55 � Langage C
IUT de Villetaneuse
Ce programme est correct car, comme les tableaux tab1 et tab2 sont alloués dynamiquement, tab1 et tab2 sont des
pointeurs (et non des pointeurs constants comme c’est le cas pour les tableaux statiques). On peut donc échanger
leurs contenus. Après l’échange, tab1 contient l’adresse (de la première case) du tableau contenant 3 valeurs (100,
101 et 102), et tab2 contient l’adresse du tableau contenant les 4 valeurs (0, 1, 2 et 3). �
4 int main()
5 {
6 double* p;
7
8 p=malloc(sizeof(double));
9 if (p==NULL)
10 printf ("erreur d’allocation");
11 else
12 {
13 printf ("Donner une valeur pour un entier");
14 scanf("%f", p);
15 printf ("Valeur de l’entier : %f", *p);
16 free (p);
17 }
18 return 0;
� � �
19 }
4 int main()
5 {
6 int* tab;
7 int taille ,i,j;
8
� �
Langage C �56 � 1ère année (2014/2015)
Département informatique
� � �
29 }
� �
Correction :
1 typdef struct
2 {
3 int x;
4 int y;
5 }point;
6
7 typedef struct
8 {
9 //On doit avoir un pointeur sur un "tableau" de points et non plus un tableau de points.
10 point* tabPoints;
11 int taillePoly ;
� � �
12 }polygone;
Question 4.2 : Écrire un programme principal déclarant une variable de type polygone dont
les points (et le nombre) sont saisis par l’utilisateur, et affichant le polygone.
� �
Correction :
1 int main()
2 {
3 polygone poly;
4 int i;
5 printf ("saisir le nombre de points du polygone : ");
6 scanf("%d",&poly. taillePoly );
7 poly.tabPoints = malloc(poly. taillePoly * sizeof(point));
8 for (i = 0 ; i < poly. taillePoly ; i++)
9 {
10 printf ("Point numero %d : \n coordonnée x = ", i+1) ;
11 scanf("%d",&poly.tabPoints[i].x);
12 printf (" coordonnée y = ");
13 scanf("%d",&poly.tabPoints[i].y);
� �
1ère année (2014/2015) �57 � Langage C
IUT de Villetaneuse
14 }
15
� �
21 }
�
Question 4.3 : On souhaite maintenant allouer dynamiquement un polygone (et plus seulement le
tableau de points de ce polygone). Définir la fonction creerPoly qui permet de créer (en allocation
dynamique) un nouveau polygone. La fonction a en paramètre le nombre de points du polygone.
La fonction demande à l’utilisateur les points qui constituent ce nouveau polygone et retourne un
pointeur sur ce polygone créé.
� �
Correction :
� �
16 }
�
Question 4.4 : Définir la fonction supprPoly qui reçoit un pointeur sur un polygone alloué
dynamiquement et qui désalloue la place occupée par ce polygone.
� �
Correction :
1 void supprPoly(polygone * p)
2 {
3 free (p->tabPoints) ; // un free pour tous les points
4 free (p); // un free pour le polygone
� �
5 }
�
Question 4.5 : Définir la fonction affichePoly prenant en paramètre un pointeur sur polygone
et affichant ce polygone.
� �
Correction :
� �
6 }
� �
Langage C �58 � 1ère année (2014/2015)
Département informatique
Question 4.6 : Modifier le programme principal pour déclarer un pointeur de type polygone.
Le polygone sera alloué, affiché puis désalloué grâce aux fonctions précédentes.
� �
Correction :
1 int main()
2 {
3 int nbPoints;
4 printf ("Donner le nombre de points du polygone : ");
5 scanf("%d",&nbPoints);
6 polygone * p = creerPoly(nbPoints);
7 printf ("Affichage du polygone : \n");
8 affichePoly (p);
9
10 supprPoly(p);
11 return 0;
� � �
12 }
Question 4.7 : On souhaite maintenant créer 3 polygones de manière dynamique et les stocker
dans un tableau. Quel est le type de chaque case du tableau ? Modifier le programme principal
pour qu’il crée ces 3 polygones de manière dynamique, les affiche et les désalloue.
Correction :
� �
Dans chaque case : polygone *. On crée polygone * tab[3];
1 int main()
2 {
3 polygone * tab [3];
4 int nbPoints,i;
5 for (i = 0 ; i < 3 ; i++)
6 {
7 printf ("Donner le nombre de points du polygone numero %d : ",i+1);
8 scanf("%d",&nbPoints);
9 tab[i] = creerPoly(nbPoints);
10 }
11 for (i = 0 ; i < 3 ; i++)
12 {
13 printf ("Affichage du polygone numero %d: \n",i+1);
14 affichePoly (tab[i]);
15 }
16
� � �
20 }
Question 4.8 : On souhaite maintenant que le tableau de polygones soit alloué de manière
dynamique, après que l’utilisateur ait saisi le nombre de polygones qu’il voulait créer. Quel est
maintenant le type de la variable tab ? Modifier le programme principal en conséquence.
� �
Correction :
1 int main()
2 {
3 polygone ** tab;
4 int nbPoly;
5 printf ("Entrer le nombre de polygones : ");
� �
1ère année (2014/2015) �59 � Langage C
IUT de Villetaneuse
6 scanf("%d",&nbPoly);
7 tab = malloc(sizeof(polygone *) * nbPoly);
8 if (tab == NULL)
9 {
10 printf ("Erreur d’allocation");
11 exit (1);
12 }
13
14 int nbPoints,i;
15 for (i = 0 ; i < nbPoly ; i++)
16 {
17 printf ("Donner le nombre de points du polygone numero %d : ",i+1);
18 scanf("%d",&nbPoints);
19 tab[i] = creerPoly(nbPoints);
20 }
21 for (i = 0 ; i < nbPoly ; i++)
22 {
23 printf ("Affichage du polygone numero %d: \n",i+1);
24 affichePoly (tab[i]);
25 }
26 for (i = 0 ; i < nbPoly ; i++)
27 supprPoly(tab[i]);
28 return 0;
� � �
29 }
� �
Langage C �60 � 1ère année (2014/2015)
Département informatique
� �
5 } codeBarre;
Le champ code correspondra à un tableau d’entiers alloué dynamiquement. Chaque case contiendra
un entier entre 1 et 5 définissant l’épaisseur du trait correspondant. Le champ taille correspond
au nombre de cases du tableau code.
Question 5.1 : Définir la fonction genereCodeBarre prenant en paramètre un entier t. La
fonction devra créer une variable de type codeBarre, dont le champ taille est égal à t et code
correspond à un tableau de taille taille dont les valeurs sont des nombres aléatoires compris
entre 1 et 5 inclus.
� �
Correction :
1 codeBarre genereCodeBarre(int taille )
2 {
3 codeBarre tmp;
4 tmp. taille = taille ;
5 tmp.code = malloc(sizeof(int) * tmp.taille);
6 int i;
7 for (i = 0 ; i < tmp.taille ; i++)
8 tmp.code[i] = 1 + rand()%5;
9 return tmp;
� � �
10 }
Question 5.2 : Définir la fonction detruitCodeBarre qui désalloue le tableau d’une variable de
type codeBarre passée par copie.
� �
Correction :
1 void detruitCodeBarre(codeBarre b)
2 {
3 free (b.code);
� � �
4 }
Question 5.3 : Définir la fonction afficheLigne prenant un code barre en paramètre et affichant
une ligne de ce code barre. Les traits blancs seront affichés avec des espaces et les traits noirs
avec des étoiles. Le nombre d’étoiles ou d’espaces correspondra à l’épaisseur de chaque trait. Par
exemple, si un code barre contient 3 traits d’épaisseur 1, 2 et 3 (le tableau code est donc un
tableau de 3 cases contenant les valeurs 1, 2 et 3), l’affichage devra être * ***.
� �
Correction :
1 void afficheLigne (codeBarre b)
2 {
� �
1ère année (2014/2015) �61 � Langage C
IUT de Villetaneuse
3 int i,j;
4 char symbole = ’*’;
5 for (i = 0 ; i < b. taille ; i++)
6 {
7 for (j = 0 ; j < b.code[i]; j++)
8 printf ("%c",symbole);
9
10 if (symbole==’*’)
11 symbole = ’ ’;
12 else
13 symbole = ’*’;
14 }
15 printf ("\n");
� � �
16 }
� �
5 * ***
� �
Correction :
1 void afficheCodeBarre(codeBarre b, int h)
2 {
3 int i = 0;
4 for (i = 0 ; i < h ; i++)
5 afficheLigne (b);
� � �
6 }
Question 5.5 : Écrire un programme principal créant 5 codes barres différents et les affichant.
� �
Correction :
1 int main()
2 {
3 srand(time(NULL));
4
5 codeBarre b;
6 int i;
7 for (i = 0 ; i < 5 ; i++)
8 {
9 printf ("Code bar numéro %d : \n",i);
10 b = genereCodeBarre(15);
11 afficheCodeBarre (b, 20);
12 detruitCodeBarre (b);
13 }
14 return 0;
� � �
15 }
Le but de cet exercice est de créer un tableau de flottants qui peut se redimensionner automa-
tiquement s’il ne contient plus de place.
Question 6.1 : Créer le type structuré tableauDynFlottants contenant les champs suivants :
– un pointeur sur double, appelé tab, correspondant au tableau alloué dynamiquement,
– un entier capacite correspondant au nombre de cases du tableau,
– un entier nbE correspondant au nombre de cases utilisées.
� �
Correction :
1 typedef struct
2 {
3 double * tab;
4 int capacite;
5 int nbE;
� � �
6 }tableauDynFlottants;
� �
Correction :
1 tableauDynFlottants * creationTableau(int n)
2 {
3 if (n <= 0)
4 return NULL;
5 tableauDynFlottants * t = malloc(sizeof(tableauDynFlottants));
6 if (t==NULL)
7 return NULL;
8 t->capacite = n;
9 t->nbE = 0;
10 t->tab = malloc(n * sizeof(double));
11 if (t->tab==NULL)
12 {
13 free (t);
14 return NULL;
15 }
16 return t;
� � �
17 }
� �
Correction :
1 void destructionTableau(tableauDynFlottants * t)
2 {
3 free (t->tab);
4 free (t);
� � �
5 }
a plus de place pour ajouter la valeur val, le tableau devra être redimensionné pour être deux fois
plus grand.
� �
Correction :
1 void ajoutValeurFin(tableauDynFlottants * t, double val)
2 {
3 if (t->nbE == t->capacite) //S’il n’y a plus de place
4 {
5 //Réallocation
6 t->capacite *= 2;
7 double * tmp = malloc(t->capacite * sizeof(double));
8 if (tmp==NULL)
9 {
10 printf ("Plus de place");
11 exit (1);
12 }
13 int i;
14 //Recopie des elements
15 for (i = 0 ; i < t->nbE ; i++)
16 tmp[i] = t->tab[i];
17 free (t->tab);
18 t->tab = tmp;
19 }
20 t->tab[t->nbE] = val;
21 t->nbE++;
� � �
22 }
� � �
5 }
Question 6.6 : Définir la fonction afficheTableau affichant les valeurs d’un tableau de flottants
passé par adresse.
� �
Correction :
1 void afficheTableau (tableauDynFlottants *t)
2 {
3 int i;
4 for (i = 0 ; i < t->nbE ; i++)
5 printf (" %lf", t->tab[i]);
6 printf ("\n");
� � �
7 }
Question 6.7 : Définir la fonction taille retournant le nombre d’éléments d’un tableau de
flottants passé par adresse.
� �
Correction :
1 int taille (tableauDynFlottants *t)
2 {
� �
Langage C �64 � 1ère année (2014/2015)
Département informatique
3 return t->nbE;
� � �
4 }
Question 6.8 : Définir la fonction insereValeur insérant la valeur val à l’indice ind dans le
tableau de flottants pointé par t, où t, ind et val sont les trois paramètres de la fonction. En cas
de besoin, une réallocation sera faite.
� �
Correction :
1 void insereValeur (tableauDynFlottants * t, double val, int ind)
2 {
3 //Si l’indice n’est pas valide, on ne fait rien
4 if (ind < 0 || ind > t->nbE)
5 return ;
6
� � �
30 }
7 int i;
8 for (i = ind; i < t->nbE ; i++)
9 t->tab[i] = t->tab[i+1];
10 t->nbE--;
� � �
11 }
� �
1ère année (2014/2015) �65 � Langage C
IUT de Villetaneuse
� � �
11 }
Question 6.11 : Définir la fonction copie prenant en paramètre un pointeur t de type tableau-
DynFlottants *. Cette fonction allouera dynamiquement une variable de type tableauDyn-
Flottants, lui affectera toutes les valeurs contenues dans t et renverra l’adresse de la variable
nouvellement allouée.
� �
Correction :
1 tableauDynFlottants * copie(tableauDynFlottants *t)
2 {
3 if (t==NULL) //Si on ne passe pas un tableau de flottants
4 return NULL;
5 tableauDynFlottants * nouveau = creationTableau(t->capacite);
6 if (nouveau == NULL)
7 return NULL;
8
9 nouveau->nbE = t->nbE;
10 //Recopie des éléments
11 int i;
12 for (i = 0 ; i < nouveau->nbE ; i++)
13 nouveau->tab[i] = t->tab[i];
14 return nouveau;
� � �
15 }
13 ajoutValeur (p,2,2);
14 afficheTableau (p);
� �
Langage C �66 � 1ère année (2014/2015)
Département informatique
15 supprimeToutesValeurs(p,2);
16 afficheTableau (p);
17
18 tableauDynFlottants * p2 = copie(p);
19 supprimeToutesValeurs(p2,3);
20
21 afficheTableau (p);
22 afficheTableau (p2);
23
24
25 destructionTableau (p);
26 destructionTableau (p2);
27
28 return 0;
� � �
29 }
� �
1ère année (2014/2015) �67 � Langage C