TP4 bis
Après avoir pris connaissance de la correction de la version 1, terminez le TP.
Correction version 1¶
tab.h
tab.c
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 |
|
test.c
Version 2 : tableau alloué dynamiquement¶
Le point faible de notre programme est qu'il utilise des tableaux de taille 100 en mémoire, alors que le nombre de matières est inconnu. Pour pouvoir utiliser un tableau de la bonne taille, il faut pouvoir l'allouer dynamiquement, c'est à dire que sa taille sera connue uniqument lors de l'exécution (et pas par le compilateur), et que les données seront stoquée sur le tas et non sur la pile.
Pour obtenir une zone de mémoire utilisable sur le tas, il faut utiliser la
fonction malloc
. Cette dernière prend en paramètre un entier : la taille en
octets de la zone mémoire désirée.
La fonction malloc
renvoie un void *
, un type qui est compatible avec tous les autres types de pointeurs : c'est bien pratique, ca permet d'avoir une fonction unique pour allouer ce qu'on veut !
Warning
Si il n'y a pas assez de mémoire disponible, malloc
renverra la valeur spéciale NULL
. Il faut donc toujours vérifier que malloc
ne nous à pas renvoyer NULL
avant d'utiliser le pointeur retourné !
Si nous revenons à notre tableau de 100 float
: quelle est la taille en octets de ce tableau ?
Example
100 fois la taille d'un float
! Mais quelle est la taille d'un float
?
Vous n'avez pas à la savoir ! c'est le but de l'opérateur sizeof()
dont
l'utilisation ressemble à l'appel d'une fonction, sauf qu'on lui donne en
paramètre un type.
Voici un code complet qui permet d'allouer un tableau de 23 entiers sur le tas :
int * tab = (int*) malloc(23*sizeof(int));
if(tab==NULL){
fprintf(stderr, "Erreur d'allocation\n");
exit(1);
}
Durée de l'allocation ?
Contrairement à une allocation sur la pile, qui est valable jusqu'à la fin
de la fonction, l'allocation dynamique n'a pas de fin implicite. La mémoire
reste réservée jusqu'à une libération explicite, grace à la fonction free()
.
Il ne faut pas oublier de libérer la mémoire quand on ne l'utilise plus,
sous peine de dégrader les performences, et dans les cas extrèmes de provoquer
une fin prématuée du programme si celui ci demande de la mémoire et qu'il n'y
en a plus de disponible.
-
Soit le code suivant, expliquez pourquoi il ne peut pas être correct (2 raisons) :
-
Que faut il faire alors ? (réponse : utiliser
malloc()
) -
Adaptez le programme de la première partie pour que les tableaux soient alloués dynamiquement avec comme taille la valeur
argc-2
(pourquoi ?). Vous ferez l'allocation dans une fonction séparéeallocate_array()
et la libération grace à une fonctionfree_array()
Version 3 : avec une structure¶
- Définissez une structure contenant les deux pointeurs de float (les tableaux) et la valeur
count
. - Faites une fonction d'allocation pour cette structure (sizeof() fonctionne aussi avec un type structuré)
- modifiez votre programme pour utiliser cette structure plutot que les trois variables séparémment
Pointeurs dans une structure
Si une structure contient un champs a
de type int *
(par exemple), si on dispose d'une variable v
du type de la structure, pour accéder à son champs, il faut écrire :
a
, il faut donc écrire :
Les parenthèses sont nécessaires, sinon on ne pourrait pas savoir si l'opérateur s'applique à v
ou à v.a
.
Afin de lever cette ambiguité sans mettre de parenthèses, on peut également réécrire avec la syntaxe :