Allocation Dynamique

Nous avons introduit le fonctionnement de base de l’ordinateur. Bien que l’allocation dynamique soit déjà un degré de complication au-dessus des premiers exercices, sa compréhension ne devrait pas poser de problèmes dés lors que le I est bien assimilé. Nous allons l’introduire au moyen de quelques exemples :

a) Allocation statique:

Supposons que l’on pose à un étudiant le sujet suivant : « Le programme doit demander à l’utilisateur de rentrer 5 nombres au clavier, les stocker dans un tableau, puis les afficher ». Un étudiant normal codera à peu près ceci :

int main(void)
{
int i;
int t[5];

./*PHASE DE SAISIE*/
puts(« entrez 5 entiers »);
for(i=0;i<5;i++)
scanf(« %d »,t+i);

.

/*PHASE D’AFFICHAGE*/
puts(« vous avez saisi : « );
for(i=0;i<5;i++)
printf(« %d, « ,t[i]);

printf(« \n »);
}

.
.
/*declaration du compteur de boucle*/
/*declaration d’un tableau statique de 5 entiers*/
.
/*equivalent de printf(« entrez 5 entiers\n »)*/
/*initialisation de i à 0 puis avant chaque boucle, vérification que*/ /*i<5, puis exécution des instructions de la boucle, enfin*/
/*incrémentation de i.*/
/*boucle : saisie d’un nombre au clavier et stockage à l’adresse*/ t+i*/

.

/*le %d indique que l’on va afficher un entier. t[i] est la valeur*/
/*de la i ème*/
/*case du tableau (on compte à partir de zéro)*/
/*pour passer à la ligne en fin d’éxécution*/

Bon les commentaires sont là pour faciliter la compréhension de tous. Mais compte tenu de leur lourdeur et du fait que ce n’est pas une partie de plaisir de mettre des tabulations et autres procédés de mise en forme en html, c’est un luxe que je ne vais pas longtemps me permettre. Voyons tout de suite le problème suivant : « Le programme doit demander à l’utilisateur de choisir un nombre n puis de rentrer n entiers au clavier, de les stocker dans un tableau, puis de les afficher ».

La première solution qui vient à l’esprit du programmeur qui n’aime pas trop réfléchir et qui préfère extrapoler à partir de l’exemple d’avant consiste à rajouter au début du code précédent « int n; printf(« Donne n> »); scanf(« %d »,&n);  » puis de remplacer les 5 par des n, puis de se demander pendant une demi heure pourquoi le int t[n]; ne passe pas à la compilation (Si vous avez des doutes, relire le précédent article ne sera pas du luxe).

Il convient alors de se rappeller que nulle mémoire n’est infinie et que quelque soit le mécanisme qui va limiter la taille du tableau, il ne peut pas ne pas en exister un qui n’impose une limite (à moins peut être de travailler sous windows ;=) ), et ça peut très bien être vous. En allocation statique il n’existe pas vraiment de manière élégante de s’en tirer. Le plus simple est alors de supposer que l’utilisateur ne choisira pas un nombre plus grand qu’un maximum que vous fixez. Vous pouvez par exemple déclarer un tableau de 1024 entiers {int t[1024];} en supposant qu’aucun utilisateur ne sera jamais assez courageux pour choisir plus de 1000 nombres. Par contre ne faites que n boucles 😉 Les puristes rajouteront un petit test pour afficher un message d’erreur dans le cas où le n choisi est supérieur à 1024. Voici un exemple de ce que vous pouvez faire :

int main(void)
{
int i,n;
int t[1024];

/*PHASE DE SAISIE*/
puts(« combien de nombres voulez vous rentrer? »);
scanf(« %d »,&n);

printf(« donnez %d nombres \n »,n);
for(i=0;i<n;i++)
scanf(« %d »,t+i);

/*PHASE D’AFFICHAGE*/
puts(« vous avez saisi : « );
for(i=0;i<n;i++)
printf(« %d, « ,t[i]);
printf(« \n »);
}

b) Allocation Dynamique:

Le problème de la solution que l’on vient d’exposer est qu’elle est un peu bancale notamment au niveau de l’optimisation de l’espace mémoire, mais ce n’est que le problème le plus évident et il y en a d’autres. La solution est simple : il faut allouer soi même la mémoire dont on va avoir besoin en spécifiant la manière dont on va l’utiliser pour que le compilateur ne soit pas perdu. Pour cela on utilise des instructions spécifiques dont malloc et calloc. Je vais expliquer pour le calloc car c’est celui qui s’applique le mieux à notre exemple : pour réserver un tableau de n entiers on va écrire :

nt *t=(int*)calloc(n,sizeof(int));

et en voici la traduction :

  • ‘int *t’ =>on déclare un tableau d’entiers.
  • ‘calloc(n, sizeof(int))’ => on réserve pour ce tableau la place nécessitée par le stockage de n entiers sachant que sizeof(int) retourne le nombre d’octets utilisés pour stocker un entier. Il en découle pour le compilateur que le nombre d’octets à réserver est donc n*sizeof(int).
  • ‘(int*)’ est un cast c’est à dire un opérateur de conversion qui va indiquer au compilateur que l’espace que l’on va alouer va correspondre à un tableau d’entiers.

Pour les curieux, la petite étoile a un rapport avec quelque chose d’assez mystérieux appelé les pointeurs, nous y viendrons bien assez tôt. Et pour les malins qui ont repéré que sizeof(int) retournait 4 sur leur ordinateur et qui se contentent donc d’écrire « int *t=(int *)calloc(n,4); », pensez que vous exécuterez peut être un jour votre programme sur un ordinateur qui utilise 8 octets pour stocker un int. Ce jour là vous aurez l’air malin (et ce d’autant plus que vous n’aurez pas de bug à la compilation, mais seulement à l’éxécution et encore pas systématiquement, un coup à s’arracher les cheveux). Bref voici donc comment traiter le problème précédent en utilisant l’allocation dynamique :

int main(void)
{
int i,n;
int *t;

/*PHASE DE SAISIE*/
puts(« combien de nombres voulez vous rentrer? »);
scanf(« %d »,&n);
t=(int *)calloc(n, sizeof(int));

printf(« donnez %d nombres \n »,n);
for(i=0;i<n;i++)
scanf(« %d »,t+i);

/*PHASE D’AFFICHAGE*/
puts(« vous avez saisi : « );
for(i=0;i<n;i++)
printf(« %d, « ,t[i]);
printf(« \n »);
}

Il y a bien sûr encore pas mal de choses à dire sur les allocations dynamiques, la différence entre le calloc et le malloc, et l’instruction realloc, mais ce n’est pas l’objet de cette page qui veut avant tout faire comprendre le principe et l’esprit de la programmation C plutôt qu’un exposé rigoureux de ses fonctionnalités. Si vous avez un doute sur une instruction, pensez à ouvrir un terminal et à taper ‘man’ suivit du nom de l’instruction pour avoir des informations sur son mode d’utilisation.

Publicités

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s