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