0% ont trouvé ce document utile (0 vote)
5 vues26 pages

Allocation Dynamique de Mémoire en C

Le chapitre traite de l'allocation dynamique de la mémoire en C, expliquant son importance pour éviter le gaspillage de mémoire lors de la déclaration de tableaux et de structures. Il présente les différentes fonctions standard comme malloc, calloc, realloc et free, ainsi que leur utilisation pour gérer la mémoire pendant l'exécution d'un programme. Des exemples illustrent comment créer et manipuler des tableaux et des structures dynamiques, soulignant les avantages de l'allocation dynamique par rapport à l'allocation statique.

Transféré par

Amine. As
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
5 vues26 pages

Allocation Dynamique de Mémoire en C

Le chapitre traite de l'allocation dynamique de la mémoire en C, expliquant son importance pour éviter le gaspillage de mémoire lors de la déclaration de tableaux et de structures. Il présente les différentes fonctions standard comme malloc, calloc, realloc et free, ainsi que leur utilisation pour gérer la mémoire pendant l'exécution d'un programme. Des exemples illustrent comment créer et manipuler des tableaux et des structures dynamiques, soulignant les avantages de l'allocation dynamique par rapport à l'allocation statique.

Transféré par

Amine. As
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Programmation Structurée

Chapitre VI:
Allocation dynamique de la mémoire

Pr Bekkari 1
Cycle préparatoire de l’ENSA de Marrakech
Année universitaire 2024 - 2025 28/11/2024
Contenu du chapitre
1) Introduction
2) Allocation dynamique de la mémoire
3) Allocation dynamique et tableaux
4) Allocation dynamique et structures
5) Allocation dynamique et fonctions

28/11/2024
Introduction
• Quelle est la mémoire du travail d’une machine numérique ?
• Comment l’information est elle représentée dedans ?
• Dans un programme en C, avant de stocker n’importe quelle
donnée il faut lui allouer un espace mémoire.
Problème : lorsqu’on déclare par exemple un tableau de 21
étudiants, mais qu’on n’a finalement que 5 étudiants dans la
promotion!!! Alors gaspillage de mémoire.

3
Introduction
• L’allocation dynamique permet précisément de résoudre ce type
de problème et autres.
• Son rôle est de réserver une zone de mémoire dont la taille peut
être spécifiée à l’exécution (et non pas à la compilation).
• Les fonctions de gestion dynamique de la mémoire permettent
d’allouer et de libérer de la mémoire pendant l’exécution.
• Mais avant d’en parler, on doit savoir quelles sont les zones de
mémoire associées à un programme C ?

4
Les zones de mémoire d’un programme

Il existe 4 zones de mémoire où le Mémoire centrale


compilateur range un programme et ses
données :

• Une zone1 : la pile (stack).


• Une zone2 : le tas (heap).
• Une zone3 : mémoire statique
(segment).
• Une zone4 : mémoire programme
(code)

5
Les zones de mémoire d’un programme

• zone « Code » :
Contient le code binaire de notre programme compilé.
• zone « statique » :
Contient les données globales du programme (celles qui sont
en vie durant tout le temps d'exécution du programme)
• zone « tas » :
Utilisée pour stocker les données allouées dynamiquement.
• zone « pile » :
Contient des variables locales, gère le passage de paramètres
et de contextes lors d'appels de fonctions, gère la récursivité, 6
etc.
Types de variables
• Variables automatiques : créées en pile et détruites au fur et à
mesure de l'exécution des fonctions où elles sont définies.
§ Exemple : variables locales « normales ».

• Variables statiques : créées dans le segment de données (zone


statique), occupant un espace mémoire déterminé à la
compilation, elles persistent jusqu’à l’arrêt du programme.
§ Exemple : variables locales déclarées avec le mot clé static et
variables globales.

• Variables dynamiques : dont la création et la destruction


dépendent des demandes explicites faites par le programme au
cours de l'exécution dans le tas (heap). Elles persistent dans la
7
mémoire jusqu’à libération.
Allocation statique
• L'allocation statique s'occupe des données à taille fixe dans le
programme.

• Le compilateur calcule la taille globale de la mémoire requise


pour ces données avant l’exécution du programme.

• Les zones concernées par l’allocation statique sont :


• la pile pour les déclarations locales et les paramètres des
fonctions,
• la zone globale statique dans le cas des déclarations globales et
des déclarations avec le mot clé static.

8
Allocation des variables

Variables normales Variables pointeurs


• La réservation de la • Une variable pointeur est aussi
mémoire s'est déroulée déclaré statiquement.
automatiquement par • Mais, le nombre d'octets p à
l'emploi des déclarations réserver pour un pointeur
statiques des variables. dépend de la machine et du
• Le nombre d'octets à 'modèle' de mémoire choisi.
réserver pour une variable • Donc quelque soit le type de
se calcule pendant la pointeur déclaré, il y aura lieu
compilation à l’aide de son réservation de p octets en
type. mémoire.
9
Allocation dynamique
Un certain nombre de fonctions standards (stdlib.h) permet de
gérer dynamiquement la mémoire suivant deux opérations
différentes :

• L'allocation dynamique de mémoire : la plus importante


fonction de cette opération est malloc qui effectue une
allocation de base, les autres étant des variantes ou des
fonctions secondaires.

• La libération de la mémoire : réalisée par la fonction free qui


permettra de réutiliser la mémoire lors de l’exécution de
programme.
10
La fonction malloc
• Prototype de la fonction : void * malloc ( size_t t );
• Utilisation de la fonction :
type_var* ptr=NULL ;
ptr = (type_var*)malloc( nb_octets );
if (ptr==NULL) ...
Ou bien : type_var* ptr=NULL ;
ptr = (type_var *)malloc( sizeof(type_var) * nb_var );
if (ptr==NULL) ...
L'utilisation de l'opérateur sizeof est recommandée pour éviter le calcul « à
la main » de nb_octets.
Si une telle allocation est impossible par manque de place, «malloc» retourne
la valeur de pointeur « NULL ». Sinon elle retourne l'adresse du premier octet
de la zone allouée dans le tas. D’où vient l’intérêt du test if(ptr==NULL) …
Toutes les valeurs retournées par la fonction « malloc » sont de type « void * ». 11
Pour que le compilateur puisse considérer autre chose qu'une zone d'octets,
il faut effectuer une conversion explicite de type (un cast).
Exemple

int * tab;
/* Création d'un tableau de 4 entiers */
tab = (int*) malloc ( 4 * sizeof(int) );
if(tab == NULL) {
printf("Erreur d’allocation de mémoire") ;
exit(1);}
tab[0] = 1;
tab[1] = 2;
tab[2] = 3;
tab[3] = 4;
for ( i = 0 ; i < 4 ; i++ ) { Résultat:
printf(" tab[%d] = %d \n", i , tab[i] ); tab[0] = 1
} tab[1] = 2
tab[2] = 3 12
tab[3] = 4
La fonction calloc
• Prototype de la fonction:
void * calloc (size_t n, size_t size);
• Le premier argument (size_t n) est le nombre d'éléments qu'on
souhaite pouvoir stocker en mémoire,
• et le deuxième (size_t size) est la taille de ces éléments que l'on
obtient avec l'opérateur sizeof().
int *ptr = (int*) calloc(20 ,sizeof (int));

Remarque: Il existe deux différences majeures entre malloc et calloc :


• Premièrement en nombre d’arguments : malloc() prend un seul
argument, alors que calloc() prend deux arguments.
• Deuxièmement, malloc() n’initialise pas la mémoire allouée, alors 13
que calloc() initialise la mémoire allouée à ZERO.
La fonction realloc
• Prototype de la fonction: void* realloc(void *ptr, size_t size);
• Le premier argument est le pointeur sur lequel on désire effectuer
l'opération,
• le deuxième argument est la taille de l'espace mémoire qu'on veut
réallouer.
• La fonction realloc() s'utilise après qu'on ait utilisé malloc() ou
calloc()
• On peut aussi la rappeler plusieurs fois de suite (dans une boucle for
ou while par exemple).
• Elle sert à ré-attribuer de la mémoire à un pointeur mais pour une
taille mémoire différente.
• La fonction réalloue le bloc mémoire tout en gardant le contenu de
ce qui se trouvait dans le bloc précédent.
14
Exemple
int * tab;
/* Création d'un tableau de 3 entiers */
tab = (int*) calloc ( 3 , sizeof(int) );
if(tab == NULL) {printf("Erreur d’allocation de mémoire") ;exit(1);}
tab[0] = 1;
tab[1] = 2;
tab[2] = 3;
/* Ajout d'un element au tableau */
tab= (int*) realloc (tab, 4 * sizeof(int) );
if(tab == NULL) {printf("Erreur d’allocation de mémoire") ;exit(1);}
tab[3] = 4;
for ( i = 0 ; i < 4 ; i++ ) {
printf(" tab[%d] = %d \n", i , tab[i] ); Résultat:
} tab[0] = 1
tab[1] = 2
tab[2] = 3 15
tab[3] = 4
La fonction free
• Un des intérêts de l'allocation dynamique est de libérer l'espace
mémoire alloué lorsqu'il n'est plus nécessaire.
• Cet espace pourra donc être réaffecté ultérieurement lors de
nouvelles demandes dynamiques.
• La libération de la mémoire allouée dynamiquement s'effectue
très simplement avec la fonction free

• Le prototype de la fonction: void free(void * bloc)


• Utilisation de la fonction :
free( ptr ) ;
ptr=NULL;
16
Tableau dynamique
• La manipulation de tableaux, et non de pointeurs, possède
certains inconvénients dûs au fait qu'un tableau est un pointeur
constant.
• Ainsi:
• on ne peut pas créer de tableaux dont la taille est une variable du
programme,
• on ne peut pas créer de tableaux bidimensionnels dont les lignes
n'ont pas toutes le même nombre d'éléments.
• Ces opérations deviennent possibles dès que l'on manipule des
pointeurs alloués dynamiquement.

17
Tableau dynamique
• Cas de tableau à une dimension:
• Pour créer un tableau d'entiers à n éléments où n est une
variable du programme, on écrit
int n;
int *tab;
...
tab = (int*)malloc(n * sizeof(int));
...
free(tab);

• Si on veut en plus que tous les éléments du tableau tab soient


initialisés à zéro, on remplace l'allocation dynamique
avec malloc par 18
tab= (int*)calloc(n , sizeof(int));
Tableau dynamique
• Cas de tableau à plusieurs dimensions:
• Un tableau à deux dimensions est, par définition, un tableau de
tableaux. Il s'agit donc en fait d'un pointeur vers un pointeur.
• Exactement comme pour les tableaux à une dimension, les pointeurs
de pointeurs ont de nombreux avantages sur les tableaux multi-
dimensionnés.
• On déclare un pointeur qui pointe sur un objet de type type* (deux
dimensions) de la même manière qu'un pointeur, c'est-à-dire
type **nom-du-pointeur;
• De même un pointeur qui pointe sur un objet de
type type ** (équivalent à un tableau à 3 dimensions) se déclare par
type ***nom-du-pointeur;

19
Tableau dynamique
• Cas de tableau à plusieurs dimensions:
• Par exemple, pour créer avec un pointeur de pointeur une matrice
à k lignes et n colonnes à coefficients entiers, on écrit :
int k, n; int **tab;
tab = (int**)malloc(k * sizeof(int*));
for (i = 0; i < k; i++)
tab[i] = (int*)malloc(n * sizeof(int));
....
for (i = 0; i < k; i++)
free(tab[i]);
free(tab);
• La première allocation dynamique réserve pour l'objet pointé
par tab l'espace-mémoire correspondant à k pointeurs sur des entiers.
• Ces k pointeurs correspondent aux lignes de la matrice. 20
• Les allocations dynamiques suivantes réservent pour chaque
pointeur tab[i] l'espace-mémoire nécessaire pour stocker n entiers.
Allocation dynamique et structures
• Cas de champ dynamique dans une structure:
• Un champ dynamique d’une structure est un champ déclaré sous forme
d’un pointeur sur un type, et doit être alloué dynamiquement avant
utilisation.
typedef struct {float r, i; } complexe;
typedef struct {
//pointeur sur tableau de complexes
complexe * tab ;
int taille ; // nombre d’éléments du tableau
} listeComplexes;

• Nous avons construire un autre type de structure nommé


listComplexes représentant un ensemble de complexes qui connait sa
taille.
21
• Notre tableau de complexes sera déclaré comme pointeur dynamique.
Allocation dynamique et structures
• Cas de champ dynamique dans une structure:
int longueur,i;
printf("La longueur de tableau :");
scanf("%d",&longueur);
listeComplexes t={NULL,longueur}; //déclaration et initialisation
//allocation dynamique et initialisation
[Link]=(complexe*) malloc (longueur * sizeof(complexe));
if([Link]==NULL) {printf("Erreur d’allocation de mémoire") ;exit(1);}
for(i=0;i<longueur;i++) {//initialisation par 0
[Link][i].r=0; [Link][i].i=0;
}//pour éviter cette boucle d’initialisation on peut utiliser calloc à l’allocation.
for(i=0;i<longueur;i++) {//affichage et libération de la mémoire
printf("t[%d]=%.2f + i%.2f \n",i,[Link][i].r,[Link][i].i);
}
free([Link]); 22
[Link]=NULL;
Allocation dynamique et structures
• Cas de structure dynamique :
• Pour illustrer le cas d’une structure allouée dynamiquement, on
utilisera une structure qui enregistre les informations d’un étudiant
(nom, taille et âge) déclarées comme variables normales.
typedef struct {
char nom[20];
float taille ;
short int age ;} etudiant;
• Donc, il est possible d’allouer dynamiquement un emplacement pour
un seul étudiant :
//Déclaration d’un pointeur pour la variable de structure.
etudiant * pEtudiant =NULL;
//Allocation dynamique
pEtudiant = (etudiant*) malloc( sizeof(etudiant) );
23
Remarque : on pourra faire les 2 instructions en une seul
(déclaration+allocation).
Allocation dynamique et structures
• Cas de structure dynamique :
• On peut aussi allouer dynamiquement une liste (tableau) d’étudiants
de la manière suivante :

//Déclaration d’un pointeur de type etudiant


etudiant * listeEtudiants=NULL;
//Allocation d'un tableau de structures
listeEtudiants=(etudiant*)malloc(nbETU*sizeof(etudiant) );
Remarque : on devra savoir le nombre d’étudiants (nbETU) avant
l’allocation.
Dans certain cas on trouve une allocation mixte (champs de structure
ainsi que la variable structurée, les deux, à allouer dynamiquement).Par
exemple: Structures auto-référencées.
24
Fonction d’allocation dynamique
• Cas de fonction avec valeur de retour:
Définition d’une fonction d’allocation :
double* fonctionAllocation(int nbElem){
double* ptr =NULL;
ptr= (double*)malloc( nbElem* sizeof(double) );
return ptr;
} //ici sizeof(*ptr) ~ sizeof(double)

Appel de la fonction d’allocation dans le programme :


int main(){
double* ptr =fonctionAllocation(5);
if(ptr == NULL)
{printf("Erreur d’allocation de mémoire") ;exit(1);}
//traitement …… 25
return 0;
}
Fonction d’allocation dynamique
• Cas de fonction sans valeur de retour:
Définition d’une fonction d’allocation :
void fonctionAllocation(double **ptr , int nombreElements){
*ptr =(double*) malloc( nombreElements * sizeof(**ptr) );
}// ici sizeof(**ptr) ~ sizeof(double)

Appel de la fonction d’allocation dans le programme :


int main(){
double * ptr=NULL;
fonctionAllocation(&ptr , 5);
if(ptr == NULL) { printf("Erreur …..") ;exit(1);}
//traitements........
return 0; 26
}

Vous aimerez peut-être aussi