Allocation dynamique

Transcription

Allocation dynamique
Cours de Programmation Impérative
Allocation dynamique
Julien David
A101 - [email protected]
Julien David (A101 - [email protected])
1 / 31
P˚r`e›v˘i`o˘u¯sfi˜l›y `o“nffl
"P˚r`oˆgˇr`a‹m‹m`a˚tˇi`o“nffl I”m¯p`éˇr`a˚tˇi‹vfle"
Julien David (A101 - [email protected])
2 / 31
Épisode sur les zones de mémoire
Pile d’appel
Tas
Zone de données
Zone texte
Variables locales, information sur les fonctions
Allocation dynamique
Variables Globales et statiques
Contenu des fonctions
Julien David (A101 - [email protected])
3 / 31
Épisode sur les pointeurs
La puissance des pointeurs
Ils permettent d’accéder à n’importe quel bloc de mémoire, situé dans
n’importe quelle zone de mémoire du programme.
Or jusqu’ici. . .
. . .on s’en servait pour se balader dans la pile
Julien David (A101 - [email protected])
4 / 31
Avec les notions actuelles
On ne peut pas (pour l’instant)
créer/réserver de l’espace mémoire avec une fonction.
faire varier la taille d’un tableau
définir des structures contenant des tableaux dont la taille n’est pas
précisée.
Julien David (A101 - [email protected])
5 / 31
1
2
3
4
5
6
7
8
9
10
11
12
Réserver de l’espace mémoire avec une fonction
i n t ∗ c r e e r t a b l e a u ( i n t n ){
i n t tab [ n ] ;
int i ;
f o r ( i =0; i <n ; i ++)
tab [ i ] = 0 ;
r e t u r n tab ;
}
i n t main ( ) {
i n t ∗ tab= c r e e r t a b l e a u ( 4 ) ;
r e t u r n EXIT SUCCESS ;
}
Julien David (A101 - [email protected])
6 / 31
1
2
3
4
5
6
7
8
9
10
11
12
Reserver de l’espace mémoire avec une fonction
i
0,1,2,3,4
112
i n t ∗ c r e e r t a b l e a u ( i n t n ){
i n t tab [ n ] ;
int i ;
f o r ( i =0; i <n ; i ++)
tab [ i ] = 0 ;
r e t u r n tab ;
}
tab[3]
0
112
tab[2]
0
108
tab[1]
0
104
tab
i n t main ( ) {
i n t ∗ tab= c r e e r t a b l e a u ( 4 ) ;
r e t u r n EXIT SUCCESS ;
}
tab[0]
0
100
main
?
80
100
80
creer tableau(4)
tab
main
Julien David (A101 - [email protected])
7 / 31
Reserver de l’espace mémoire avec une fonction
Pour réserver de l’espace mémoire
On a besoin d’utiliser une autre zone de la mémoire.
Julien David (A101 - [email protected])
8 / 31
Définir des structures de taille variable
Actuellement, pour stocker plusieurs données de même type, on utilise des
tableaux.
On ne peut pas faire varier leur taille au cours du programme.
Lorsqu’une structure contient un tableau, on est obligé de définir sa taille
à l’avance.
Julien David (A101 - [email protected])
9 / 31
Faire varier la longueur d’un tableau
1 i n t main ( ) {
2
char chaine [ 1 0 ] ;
3
s c a n f ( ”%s ” , chaine ) ;
4
p r i n t f ( ”%s\n ” , chaine ) ;
5
r e t u r n EXIT SUCCESS ;
6 }
Si l’utilisateur rentre une chaine trop grande, il y aura un débordement.
L’idée se généralise à n’importe qu’elle structure, on ne peut pour
l’instant avoir que des objets de taille fixe.
Julien David (A101 - [email protected])
10 / 31
L’allocation dynamique
Notion Fondamentale : l’allocation dynamique
L’allocation dynamique ou allocation dynamique sur le tas consiste à allouer
de la mémoire dans le tas (la zone de mémoire).
Les avantages
On peut allouer ou libérer la mémoire à tout moment.
On peut accéder à la zone de mémoire à partir de n’importe qu’elle
fonction.
On peut décider de ”modifier la taille” d’une zone de mémoire.
Les inconvénients
Contrairement à l’allocation dans la pile, la mémoire n’est pas libérée
automatiquement.
L’allocation mémoire est un appel à une fonction système, souvent
coûteuse en temps.
Julien David (A101 - [email protected])
11 / 31
L’allocation dynamique
Notion Fondamentale : l’allocation dynamique
L’allocation dynamique ou allocation dynamique sur le tas consiste à allouer
de la mémoire dans le tas (la zone de mémoire).
Les avantages
On peut allouer ou libérer la mémoire à tout moment.
On peut accéder à la zone de mémoire à partir de n’importe qu’elle
fonction.
On peut décider de ”modifier la taille” d’une zone de mémoire.
Les inconvénients
Contrairement à l’allocation dans la pile, la mémoire n’est pas libérée
automatiquement.
L’allocation mémoire est un appel à une fonction système, souvent
coûteuse en temps.
Julien David (A101 - [email protected])
11 / 31
L’allocation dynamique
Notion Fondamentale : l’allocation dynamique
L’allocation dynamique ou allocation dynamique sur le tas consiste à allouer
de la mémoire dans le tas (la zone de mémoire).
Les avantages
On peut allouer ou libérer la mémoire à tout moment.
On peut accéder à la zone de mémoire à partir de n’importe qu’elle
fonction.
On peut décider de ”modifier la taille” d’une zone de mémoire.
Les inconvénients
Contrairement à l’allocation dans la pile, la mémoire n’est pas libérée
automatiquement.
L’allocation mémoire est un appel à une fonction système, souvent
coûteuse en temps.
Julien David (A101 - [email protected])
11 / 31
Les fonctions d’allocations
L’allocation
La fonction void * malloc(size t size);
prend en entrée la taille du bloc de mémoire que l’on souhaite obtenir,
alloue le bloc de mémoire dans le tas,
renvoie l’adresse du bloc de mémoire.
Syntaxe d’un appel à la fonction malloc
malloc(taille case * nombre cases);
Julien David (A101 - [email protected])
12 / 31
1
2
3
4
5
6
7
8
9
10
11
12
Les fonctions d’allocations
i n t ∗ c r e e r t a b l e a u ( i n t n ){
i n t ∗ t a b = m a l l o c ( s i z e o f ( i n t )∗ n ) ;
int i ;
f o r ( i =0; i <n , i ++)
tab [ i ] = 0 ;
r e t u r n tab ;
}
i n t main ( ) {
i n t ∗ tab= c r e e r t a b l e a u ( 4 ) ;
r e t u r n EXIT SUCCESS ;
}
i
tab
?
112
480
100
creer tableau(4)
tab
?
Tas
?
?
?
?
480
484
488
492
80
main
Julien David (A101 - [email protected])
13 / 31
1
2
3
4
5
6
7
8
9
10
11
12
Les fonctions d’allocations
i n t ∗ c r e e r t a b l e a u ( i n t n ){
i n t ∗ t a b = m a l l o c ( s i z e o f ( i n t )∗ n ) ;
int i ;
f o r ( i =0; i <n , i ++)
tab [ i ] = 0 ;
r e t u r n tab ;
}
i n t main ( ) {
i n t ∗ tab= c r e e r t a b l e a u ( 4 ) ;
r e t u r n EXIT SUCCESS ;
}
i
tab
0
112
480
100
creer tableau(4)
tab
?
Tas
0
?
?
?
480
484
488
492
80
main
Julien David (A101 - [email protected])
14 / 31
1
2
3
4
5
6
7
8
9
10
11
12
Les fonctions d’allocations
i n t ∗ c r e e r t a b l e a u ( i n t n ){
i n t ∗ t a b = m a l l o c ( s i z e o f ( i n t )∗ n ) ;
int i ;
f o r ( i =0; i <n , i ++)
tab [ i ] = 0 ;
r e t u r n tab ;
}
i n t main ( ) {
i n t ∗ tab= c r e e r t a b l e a u ( 4 ) ;
r e t u r n EXIT SUCCESS ;
}
i
tab
0,1,2,3,4
112
480
100
creer tableau(4)
tab
?
480
Tas
0
0
0
0
480
484
488
492
main
Julien David (A101 - [email protected])
15 / 31
1
2
3
4
5
6
7
8
9
10
11
12
Les fonctions d’allocations
i n t ∗ c r e e r t a b l e a u ( i n t n ){
i n t ∗ t a b = m a l l o c ( s i z e o f ( i n t )∗ n ) ;
int i ;
f o r ( i =0; i <n , i ++)
tab [ i ] = 0 ;
r e t u r n tab ;
}
i n t main ( ) {
i n t ∗ tab= c r e e r t a b l e a u ( 4 ) ;
r e t u r n EXIT SUCCESS ;
}
Tas
tab
480
80
main
0
0
0
0
480
484
488
492
La fonction creer tableau a une complexité Θ(n) en temps et en espace.
Julien David (A101 - [email protected])
16 / 31
Les fonctions d’allocations
L’allocation
La fonction void *calloc(size t nmemb, size t size);
prends en entrée le nombre de case à allouer et la taille de chaque case,
alloue le bloc de mémoire dans le tas.
Initialise chaque case à 0.
Renvoie l’adresse du bloc de mémoire.
Syntaxe d’un appel à la fonction calloc
calloc(nombre cases,taille case);
Julien David (A101 - [email protected])
17 / 31
Les fonctions d’allocations
1
2
3
4
5
6
7
8
9
i n t ∗ c r e e r t a b l e a u ( i n t n ){
i n t ∗tab= c a l l o c ( n , s i z e o f ( i n t ) ) ;
r e t u r n tab ;
}
i n t main ( ) {
i n t ∗ tab= c r e e r t a b l e a u ( 4 ) ;
r e t u r n EXIT SUCCESS ;
}
tab
480
100
Tas
creer tableau(4)
tab
?
480
0
0
0
0
480
484
488
492
main
La fonction creer tableau a une complexité Θ(n) en temps et en espace.
Julien David (A101 - [email protected])
18 / 31
Malloc/Calloc
Pourquoi avoir deux fonctions ?
La fonction calloc sert uniquement dans le cas où l’on veut initialiser
toutes les cases à 0.
elle évite de devoir initialiser les cases une à une avec une boucle for.
le code est donc plus simple.
il arrive souvent qu’on ne veuille pas initialiser les cases à 0.
Julien David (A101 - [email protected])
19 / 31
Allocation/Désallocation
Allocation/Désallocation
Chaque bloc de mémoire que vous allouez doit être libéré lorsque vous
n’en avez plus besoin.
À la fin d’un programme, le nombre d’allocations doit être égal au nombre
de désallocations.
Julien David (A101 - [email protected])
20 / 31
Les fonctions d’allocations
Désallocation
La fonction void free(void *ptr);
prends en entrée un pointeur contenant l’adresse d’un bloc mémoire,
rend l’espace mémoire à nouveau disponible (libère la mémoire).
Julien David (A101 - [email protected])
21 / 31
1
2
3
4
5
6
7
8
9
10
11
12
13
Les fonctions d’allocations
i n t ∗ c r e e r t a b l e a u ( i n t n ){
i n t ∗ t a b = m a l l o c ( s i z e o f ( i n t )∗ n ) ;
int i ;
f o r ( i =0; i <n , i ++)
tab [ i ] = 0 ;
r e t u r n tab ;
}
i n t main ( ) {
i n t ∗ tab= c r e e r t a b l e a u ( 4 ) ;
f r e e ( tab ) ;
r e t u r n EXIT SUCCESS ;
}
Julien David (A101 - [email protected])
22 / 31
Les fonctions d’allocations
Réallocation
La fonction void *realloc(void *ptr, size t n);
prends en entrée un pointeur contenant l’adresse d’un bloc mémoire et
une taille n,
alloue l’espace mémoire de taille n (malloc),
copie le contenu de la zone mémoire situé à l’adresse ptr vers la
nouvelle zone mémoire,
libère l’espace mémoire mémoire localisé par ptr (free),
renvoit l’adresse de la nouvelle zone mémoire.
Lorsqu’une zone mémoire devient trop petite. . .
on ne l’agrandit pas ,
on en crée une nouvelle.
Julien David (A101 - [email protected])
23 / 31
Structures de taille variable
On peut à présent définir des structures de longueur variable.
Exemple
Dans le TD5 : on aurait bien eu besoin de créer des garages de
longueurs variables.
Mais attention
si la fonction qui permet de créer une instance d’une structure contient un
malloc. . .
on doit définir une fonction qui permet de détruire cette instance.
Julien David (A101 - [email protected])
24 / 31
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
Structures de taille variable
# i f n d e f GARAGE
# d e f i n e GARAGE H
#include ” voiture . h”
s t r u c t garage s{
v o i t u r e t ∗ p l a c e s ; / / t a b l e a u de v o i t u r e s .
i n t nb places max ; / / Nombre maximum de v o i t u r e s .
i n t n b v o i t u r e s ; / / Nombre d ’ emplacements occupes .
};
t y p e d e f garage s g a r a g e t ;
/∗∗
F o n t i o n q u i prends en e n t r e e un nombre n ,
a l l o u e un t a b l e a u de n v o i t u r e s e t r e n v o i t l e garage .
@param n nombre de p l a c e s dans l e garage
@return un garage i n i t i a l i s e
∗/
garage t ∗ creer garage ( i n t n ) ;
/∗∗
F o n t i o n q u i l i b e r e l a memoire a l l o u e e pour un garage g
@param g un garage
∗/
void detruire garage ( garage t ∗ g ) ;
#endif
Julien David (A101 - [email protected])
25 / 31
1
2
3
4
5
6
7
8
9
10
11
12
Structures de taille variable
g a r a g e t ∗ c r e e r g a r a g e ( i n t n ){
garage t ∗ res=malloc ( s i z e o f ( garage t ) ) ;
res−>p l a c e s = m a l l o c ( s i z e o f ( v o i t u r e t )∗ n ) ;
res−>nb places max=n ;
res−>n b v o i t u r e s =0;
r e t u r n res ;
}
v o i d d e t r u i r e g a r a g e ( g a r a g e t ∗ g ){
f r e e ( g−>p l a c e s ) ;
free (g ) ;
}
Julien David (A101 - [email protected])
26 / 31
Copie de variables structurées
Copier une variable
Il n’est plus possible de copier une variable structurée dans une autre en
utilisant l’opérateur =,
on ne ferait que copier la valeur du pointeur.
or deux variables ne doivent pas partager le même espace mémoire.
Solution
Il faut donc écrire une fonction pour recopier la valeur d’une variable
structurée.
Julien David (A101 - [email protected])
27 / 31
Copie de variables structurées
1 g a r a g e t ∗ c o p i e g a r a g e ( g a r a g e t ∗ g ){
2
g a r a g e t ∗ r e s = c r e e r g a r a g e ( g−>nb places max ) ;
3
int i ;
4
f o r ( i =0; i <g−>n b v o i t u r e s ; i ++)
5
res−>p l a c e s [ i ] = g−>p l a c e s [ i ] ;
6
res−>n b v o i t u r e s =g−>n b v o i t u r e s ;
7
r e t u r n res ;
8 }
Julien David (A101 - [email protected])
28 / 31
Tableaux à plusieurs dimensions
Rappel sur les tableaux
Un tableau à une dimension est un pointeur.
un tableau d’entier à une dimension est de type int *
Un tableau à deux dimensions
Chaque case du tableau à deux dimensions est un tableau à une
dimension.
C’est donc un pointeur de pointeur.
un tableau d’entier à deux dimensions est de type int **
Julien David (A101 - [email protected])
29 / 31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Tableaux à plusieurs dimensions
i n t ∗∗ c r e e r t a b l e a u ( i n t h , i n t l ){
int i , j ;
i n t ∗∗ t a b = m a l l o c ( s i z e o f ( i n t ∗)∗h ) ;
f o r ( i =0 , i <h ; i ++){
t a b [ i ] = m a l l o c ( s i z e o f ( i n t )∗ l ) ;
f o r ( j =0 , j <l ; j ++)
tab [ i ] [ j ] = 0 ;
}
r e t u r n tab ;
}
v o i d d e t r u i r e t a b l e a u ( i n t ∗∗ tab , i n t h ){
int i ;
f o r ( i =0 , i <h ; i ++)
f r e e ( tab [ i ] ) ;
f r e e ( tab ) ;
}
Julien David (A101 - [email protected])
30 / 31
On va pouvoir attaquer . . .
˜l´e˙s ¯sfi˚tˇr˚u`cˇtˇu˚r`e˙s `d`e `d`o“n‹n`é´e˙s ˜lˇi‹n`é´a˚i˚r`e˙s
Julien David (A101 - [email protected])
31 / 31