Informatique 1A Langage C 6 ème séance 1
Objectifs de la séance 6 Allocation dynamique de mémoire Application à la création de tableaux 2
Problématique Avantage : on n’a pas à se préoccuper de l’allocation de mémoire, c’est le programme qui s’en charge. Inconvénient : on doit connaître la taille du tableau (en nombre d’octets) au moment où on la déclare. Conséquence : la taille d’un tableau statique doit être connue à la compilation du programme int n=100; int tab[n]; … for(i=1;i<n;i++) tab[i]=0; - Définition d’une variable tab pouvant être utilisée dans le programme pour manipuler des données - Allocation d’un espace mémoire de 100 cases contigües de 4 octets int tab[100]; Cette déclaration fait deux choses : n est une variable : cela ne fonctionne pas en C 3
Allocation dynamique Solution : - Déclarer une variable contenant une adresse (donc un pointeur) - Allouer l’espace mémoire nécessaire à partir de cette adresse, de manière dynamique - Une fonction d’allocation mémoire est la fonction malloc() (pour m emory alloc ation) -L’argument de la fonction malloc() est le nombre d’octets qu’on souhaite réserver Ex : malloc(4) réserve 4 octets en mémoire -La fonction malloc() retourne l’adresse du 1 er élément réservé Ex : malloc(4) est l’adresse du 1 er octet réservé 4
Allocation dynamique : la taille des variables 5
sizeof( ) retourne la taille en octets de son argument L’argument peut être un type ou une expression : Par exemple, sizeof(int) retourne la taille en octets d’un entier Que vaut sizeof(char) ? Améliore la portabilité des programmes et permet de ne pas avoir à calculer la taille mémoire exacte réservée →malloc(sizeof( int )) réserve suffisamment d’espace pour stocker un int, quelle que soit la machine 6
Exemple #include... int dim; int *tab;... dim = 100; tab=malloc(dim*sizeof(int)); for(i=0;i<dim;i++) tab[i]=0; On affecte cette adresse au pointeur tab, que l’on peut ensuite manipuler comme un tableau malloc réserve un emplacement mémoire pour stocker 100 entiers et renvoie l’adresse du 1 er entier 7
#include... int dim; int *tab;... dim=100; for(i=0;i<dim;i++) tab[i]=0; Exemple Intérêt des tableaux dynamiques : la dimension d’un tableau n’a pas besoin d’être connue à la compilation pour déclarer la variable qui permet de le manipuler : cela peut être une variable. Mais : il faut s’occuper soi-même de l’allocation mémoire. Avant d’utiliser un tableau, il faut absolument allouer son espace mémoire. mais en général, le programme « plante » ici à l’exécution ! Pas de problème à la compilation, Pas d’allocation mémoire. 8
#include... int dim; int *tab;... dim=100; tab=malloc(dim*sizeof(int)); for(i=0;i<dim;i++) tab[i]=0; Exemple Intérêt des tableaux dynamiques : la dimension d’un tableau n’a pas besoin d’être connue à la compilation pour déclarer la variable qui permet de le manipuler : cela peut être une variable. Mais : il faut s’occuper soi-même de l’allocation mémoire. Avant d’utiliser un tableau, il faut absolument allouer son espace mémoire. Allocation mémoire pour tab OK 9
#include... int dim; int *tab;... dim=100; tab=malloc(dim*sizeof(int)); for(i=0;i<dim;i++) tab[i]=0; Exemple Intérêt des tableaux dynamiques : la dimension d’un tableau n’a pas besoin d’être connue à la compilation pour déclarer la variable qui permet de le manipuler : cela peut être une variable. Mais : il faut s’occuper soi-même de l’allocation mémoire. Avant d’utiliser un tableau, il faut absolument allouer son espace mémoire. Allocation mémoire pour tab OK Il faut aussi libérer l’espace alloué après utilisation (surtout dans une boucle): La fonction est : free(pointeur) 10
Le pointeur NULL Pointeur NULL : par convention, il pointe sur l’adresse #0000 (adresse fictive qui ne correspond à aucune zone de mémoire accessible) float *p; p = NULL; Exemple : la fonction malloc renvoie : un pointeur sur l’espace mémoire alloué, si l’allocation a pu se faire le pointeur NULL si l’allocation n’a pas pu se faire if (malloc(dim*sizeof(float))!=NULL) for(i=0;i<dim;i++) tab[i]=0; else printf(« Allocation impossible\n »); 11
Allocation mémoire dans les fonctions #define DIM 10 int *fonction1(int dim); main() { int *tab1,*tab2; tab1=fonction1(DIM); //OK tab2=malloc(DIM*sizeof(int)); //OK } int *fonction1(int dim) { int *tab; tab=malloc(dim*sizeof(int)); return tab; } Bonnes méthodes pour allouer de la mémoire à un tableau 12
Allocation mémoire dans les fonctions #define DIM 10 void fonction2(int *tab, int dim); main() { int *tab1; fonction2(tab1,DIM); //ne marche pas } void fonction2(int *tab, int dim) { tab=malloc(dim*sizeof(int)); return; } Problème d’initialisation (warning « variable utilisée sans avoir été initialisée » et plantage à l’exécution) 13
Bilan sur les pointeurs -Fonctions : - malloc() - sizeof() - free() - Pointeur NULL Les points clefs pour traiter des pointeurs : 14 - Pas d’allocation ou allocation mal faite - Pointeur non renvoyé par une fonction d’initialisation - Prototype de fonction non cohérent avec la définition - Arguments de fonctions non cohérents (on transmet un int et la fonction attend un int *) - Erreur sur les types des tableaux Les erreurs courantes :
Bilan sur les pointeurs - réaliser des fonctions qui modifient les variables passées en arguments (on parle de passage d’arguments par adresse) - manipuler des tableaux puisqu’un tableau est un pointeur - définir un tableau dont la taille est une variable. On définit pour cela un pointeur et on alloue l’espace mémoire suffisant à partir de ce pointeur grâce à l’allocation dynamique de mémoire (on parle de tableaux dynamiques) Vous savez utiliser les pointeurs pour … : Les pointeurs servent encore à : -manipuler de gros fichiers (type image) à partir d’une seule adresse (soit un octet), d’où un gain de temps et de mémoire -définir des listes chaînées (sorte de tableaux de taille variable) 15