Sunteți pe pagina 1din 19

Cours 5

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.

5.1 La fonction malloc


Lorsque vous déclarez un pointeur p, vous allouez un espace mémoire pour y stocker une adresse
mémoire. Vous pouvez ensuite faire pointer p sur l’adresse mémoire que vous voulez : soit cette
adresse est celle d’une variable qui existe déjà, soit cette adresse est celle d’un espace mémoire
créé spécialement pour l’occasion.

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é.

5.2 La fonction sizeof


Il n’est pas toujours évident de connaître la taille nécessaire pour stocker une donnée. Pour
les types simples, la taille peut dépendre du système d’exploitation. Pour les types structurés, il
faut alors connaître la taille nécessaire au stockage de chaque champ 1 . La fonction sizeof permet
� �
d’indiquer le nombre d’octets nécessaires pour stocker une donnée. Ainsi, l’exécution du code :
1 #include<stdio.h>
2 typedef struct
3 {
4 int x;
5 int y;
6 }point;
7

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));.

5.3 Valeur NULL comme valeur de retour de la fonction malloc


Pour signifier qu’un pointeur ne pointe sur aucun élément en mémoire, on lui affecte la valeur
NULL. Ceci permet alors de faire des tests sur le pointeur pour savoir s’il pointe ou non sur un
espace mémoire valide.
Lors de l’appel de la fonction malloc, si le programme n’a pas pu allouer la mémoire (car il
n’y a pas suffisamment d’espace libre), la valeur retournée est alors NULL. Il est donc nécessaire, à
chaque malloc, de vérifier si la valeur retournée par la fonction malloc est différente de NULL.
1. En réalité, l’espace occupé par un type structuré peut être légèrement plus grand que l’ensemble des espaces
occupés par chacun de ses champs.

� �
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 }

5.4 La fonction free


Lorsque que l’on effectue une allocation dynamique, l’espace réservé ne peut pas être alloué
pour une autre variable. Une fois que vous n’en avez plus besoin, vous devez libérer l’espace
mémoire alloué avec la fonction free(var) où var est une variable contenant l’adresse mémoire

� �
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

5.5 L’allocation dynamique d’un tableau


Pour allouer dynamiquement un tableau, il suffit de réserver avec la fonction malloc le nombre
d’octets nécessaires pour stocker les différentes valeurs du tableau. Cet espace correspond à la
taille en octets d’une case multipliée par le nombre de cases du tableau. Par exemple, pour al-
louer un tableau de 10 int, on exécute malloc(10*sizeof (int)). Voici un programme allouant
dynamiquement un tableau dont la taille est saisie par l’utilisateur :
� �
1ère année (2014/2015) �51 � Langage C
IUT de Villetaneuse

� �
1 #include<stdio.h>
2 #include <stdlib.h>
3

4 void initTab(int* tab, int n)


5 {
6 int i;
7 for (i=0 ; i<n ; i++)
8 tab[i] = i + 1;
9 }
10 void afficheTab(int* tab, int n)
11 {
12 int i;
13 for (i=0 ; i<n ; i++)
14 printf (" %d", tab[i]);
15 printf ("\n");
16 }
17

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 }

� Sur ce thème : Exercice 1, Question 5, TD5


� Sur ce thème : Exercices 3 et 4, TD5

� �
Langage C �52 � 1ère année (2014/2015)
Département informatique

TD5 : Allocation dynamique (Corrigé)

Exercice 1 : Questions de compréhension


Question 1.1 : À quoi sert la fonction malloc ?
Correction :
La fonction malloc sert à réserver en mémoire un nombre d’octets passé en paramètre. Elle retourne l’adresse du
premier octet alloué. �

Question 1.2 : À quoi sert la fonction free ?


Correction :
La fonction free permet de libérer l’espace réservé en mémoire par la fonction malloc. Il faut passer en paramètre
l’adresse du premier octet que l’on souhaite libérer. �

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). �

Question 1.5 : Le programme suivant 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 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

16 printf ("Première valeur : ");


17 scanf("%lf",p1);
18

19 printf ("Deuxième valeur : ");


20 scanf("%lf",p2);
21

22 *p1 = *p1 + *p2;


23 printf ("Résultat = %lf\n",*p1);
24 return 0;

� �
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 :

1 void alloue(double **p)


2 {
3 *p = malloc(sizeof(double));
4 }
5

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

14 int * tmp = tab1;


15 tab1 = tab2;
16 tab2 = tmp;
17 printf ("Premier élément de tab1 : %d\n",tab1[0]);
18 printf ("Premier élément de tab2 : %d\n",tab2[0]);
19 free (tab1);
20 free (tab2);
21 return 0;

� �
22 }

Correction :
� �
Le programme est correct. Il affiche :

1 Premier élément de tab1 : 100

� �
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). �

Exercice 2 : Utilisation simple de malloc et free*


Écrire un programme en C qui alloue dynamiquement la place pour un flottant, demande une
valeur à l’utilisateur pour ce nombre et l’affiche à l’écran avant de désallouer l’espace réservé pour
ce flottant.
� �
Correction :
1 #include <stdio.h>
2 #include <stdlib.h>
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 }

Exercice 3 : Utilisation simple de malloc et free pour les tableaux*


Écrire un programme qui répète trois fois les instructions suivantes :
– demander à l’utilisateur la taille d’un tableau d’entiers,
– réserver la place exacte pour ce tableau,
– demander les valeurs successives de ce tableau à l’utilisateur,
– afficher le tableau,
– libérer la mémoire du tableau.
� �
Correction :
1 #include <stdio.h>
2 #include <stdlib.h>
3

4 int main()
5 {
6 int* tab;
7 int taille ,i,j;
8

9 for (i=0; i<3; i++)


10 {
11 printf ("Donner la taille du tableau : ");
12 scanf("%d",& taille );
13 tab=malloc(sizeof(int)*taille);
14 if (tab==NULL)

� �
Langage C �56 � 1ère année (2014/2015)
Département informatique

15 printf ("erreur d’allocation");


16 else
17 {
18 for (j=0; j< taille ; j++)
19 {
20 printf ("Donner une valeur pour tab[%d] : ",j);
21 scanf("%d", &tab[j]);
22 }
23 for (j=0; j< taille ; j++)
24 printf ("Valeur de tab[%d] : %d\n",j,tab[j]);
25 free (tab); // un free pour un malloc
26 }
27 }
28 return 0;

� � �
29 }

Exercice 4 : structures et allocation dynamique***


Un polygone est constitué d’un ensemble de points (par exemple 5 points pour un pentagone,
8 points pour un octogone, etc). Ainsi, le polygone constitué des points (1,3) (2,4) (5,3) (6,2) (3,1)
est un pentagone. Dans cet exercice le tableau de points devra avoir la taille exacte du nombre de
points qui constitue le polygone en utilisant l’allocation dynamique.
Question 4.1 : Proposez une structure polygone.

� �
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

16 printf ("Affichage du polygone : \n");


17 for (i = 0 ; i < poly. taillePoly ; i++)
18 printf ("Point numéro %d : (%d,%d)\n",i+1,poly.tabPoints[i].x,poly.tabPoints[i].y);
19 free (poly.tabPoints);
20 return 0;

� �
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 :

1 polygone * creerPoly(int nbPoints)


2 {
3 polygone * p ;
4 int i;
5 p = malloc(sizeof(polygone));
6 p-> taillePoly = nbPoints ;
7 p->tabPoints = malloc(sizeof(point) * nbPoints) ;
8 for (i=0 ; i < nbPoints ; i++)
9 {
10 printf ("Point numero %d : \n coordonnée x = ", i+1) ;
11 scanf("%d",&(p->tabPoints[i].x));
12 printf (" coordonnée y = ");
13 scanf("%d",&(p->tabPoints[i].y));
14 }
15 return p ;

� �
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 :

1 void affichePoly (polygone * p)


2 {
3 int i;
4 for (i = 0 ; i < p-> taillePoly ; i++)
5 printf ("Point numéro %d : (%d,%d)\n",i+1,p->tabPoints[i].x,p->tabPoints[i].y);

� �
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

17 for (i = 0 ; i < 3 ; i++)


18 supprPoly(tab[i]);
19 return 0;

� � �
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

TP5 : Allocation dynamique (Corrigé)

Exercice 5 : Code barre**


Le but de cet exercice est de représenter un code barre. On considère qu’un code barre est une
suite de traits blancs et noirs de différentes épaisseurs. On suppose par la suite que le premier
� �
trait est un trait noir. Pour représenter un tel code, on utilise la structure suivante :
1 typedef struct
2 {
3 int taille ;
4 int * code;

� �
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 }

Question 5.4 : Définir la fonction afficheCodeBarre prenant en paramètre un code barre et


un entier h et affichant le code barre sur h lignes. L’appel de cette fonction avec le code barre
� �
précédent et la valeur 5 pour h devra afficher :
1 * ***
2 * ***
3 * ***
4 * ***

� �
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 }

Exercice 6 : Tableaux dynamiques***


� �
Langage C �62 � 1ère année (2014/2015)
Département informatique

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;

Question 6.2 : Définir la fonction creationTableau prenant en paramètre un entier n. La fonc-


tion allouera dynamiquement une variable de type tableauDynFlottants contenant 0 éléments
mais pouvant stocker sans réallocation jusqu’à n flottants (autrement dit, le tableau tab devra
contenir n cases). La fonction renverra la variable nouvellement allouée.

� �
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 }

Question 6.3 : Définir la fonction destructionTableau prenant en paramètre un pointeur de


type tableauDynFlottants * et libérant la mémoire prise par cette variable. Attention, il convient
de désallouer le champ tab et la variable passée en paramètre.

� �
Correction :
1 void destructionTableau(tableauDynFlottants * t)
2 {
3 free (t->tab);
4 free (t);

� � �
5 }

Question 6.4 : Définir la fonction ajoutValeurFin prenant en paramètre un pointeur de type


tableauDynFlottants * t et un flottant val. La fonction ajoutera la valeur val au tableau de
flottants. Le nombre d’éléments du tableau devra être modifié en conséquence. Attention, s’il n’y
� �
1ère année (2014/2015) �63 � Langage C
IUT de Villetaneuse

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 }

Question 6.5 : Définir la fonction supprimeValeurFin prenant en paramètre un pointeur de


type tableauDynFlottants * et supprimant la dernière valeur du tableau.
� �
Correction :
1 void supprimeValeurFin(tableauDynFlottants *t)
2 {
3 if (t->nbE)//Si le nombre de valeurs n’est pas nul
4 t->nbE--;

� � �
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

7 if (t->nbE == t->capacite) //S’il n’y a plus de place


8 {
9 //Réallocation
10 t->capacite *= 2;
11 double * tmp = malloc(t->capacite * sizeof(double));
12 if (tmp==NULL)
13 {
14 printf ("Plus de place");
15 exit (1);
16 }
17 int i;
18 //Recopie des elements
19 for (i = 0 ; i < t->nbE ; i++)
20 tmp[i] = t->tab[i];
21 free (t->tab);
22 t->tab = tmp;
23 }
24 //Décalage de toutes les valeurs après l’indice
25 int i;
26 for (i = t->nbE + 1; i > ind ; i--)
27 t->tab[i] = t->tab[i-1];
28 t->tab[ind] = val;
29 t->nbE++;

� � �
30 }

Question 6.9 : Définir la fonction supprimeValeur supprimant dans le tableau de flottants


pointé par t la valeur d’indice ind.
� �
Correction :
1 void supprimeValeur(tableauDynFlottants * t, 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

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

Question 6.10 : Définir la fonction supprimeToutesValeurs prenant en paramètre un pointeur


t de type tableauDynFlottants * et un flottant val et supprimant dans le tableau de flottants
pointé par t tous les éléments correspondant à la valeur val.
� �
Correction :
1 void supprimeToutesValeurs(tableauDynFlottants *t, double val)
2 {
3 int i = 0;
4 while (i < taille (t))
5 {
6 if (t->tab[i]==val)
7 supprimeValeur(t,i);
8 else
9 i ++;
10 }

� � �
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 }

Question 6.12 : Écrire un programme principal utilisant les différentes fonctions.


� �
Correction :
1 int main()
2 {
3 tableauDynFlottants * p = creationTableau(5);
4 if (p==NULL)
5 return 0;
6 int i;
7 for (i = 0 ; i < 10 ; i++)
8 ajoutValeurFin (p,i);
9

10 for (i = 0 ; i < 10 ; i++)


11 ajoutValeurFin (p,i);
12

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

S-ar putea să vă placă și