Pointeurs et tableaux
Un pointeur peut être utilisé comme un tableau
Le programme suivant alloue sur le tas 3 cases contenant chacune un entier.
int* p = malloc(3*sizeof(*p));
p[0] = 1
p[1] = 3
p[2] = 35
p[0]
et *p
sont synonymes.
- Que pensez-vous de ce programme ?
int* p = malloc(3*sizeof(*p));
p[0] = 1
p[1] = 3
p[2] = 35
p[10] = 5
malloc
c'est acheter une zone mémoire. Là, avec p[10] = 5
, on écrit là où on a pas acheté.
- Qu'est ce qui est moche dans
int* p = malloc(3*sizeof(*p));
?
Le fait d'avoir 3 qui est volant. Si c'est une constante, on peut faire par exemple :
#define NB_POTATOES 3
int* p = malloc(NB_POTATOES*sizeof(*p));
Un tableau est quasiment comme un pointeur
Un tableau statique ou un tableau déclaré dans une fonction est considéré comme un tableau : il a une taille et sizeof(tableau)
renvoie le nombre d'octets utilisés pour stocker tout le tableau.
Mais si on passe un tableau à une fonction, ça devient un pointeur. Les signatures suivantes sont équivalentes :
void f(char* p)
void f(char p[])
void f(char p[3])
Dans f
, sizeof(p)
renvoie 8 octets (64 bits).
Exercice : tableau dynamique
realloc
permet de réallouer une zone mémoire. Voir TD.
Arithmétique des pointeurs
Addition d'un pointeur et d'un entier
Considérons le pointeur p
tableau de 3 int
:
avec
p++
on avance de 1 case int
dans le tableau (i.e. de 4 octets dans la plage mémoire) :
De la même manière, on peut faire p += 5
et on avance de 5 cases du tableau (5 fois 4 octets).
Différence de pointeurs
int* p;
int* q;
...
int nbCasesTableauEntrePetQ = q - p;
Sur le dessin, q - p
vaut int
)
La différence de pointeurs est un nombre relatif.
Dans l'exemple p - q
vaut
Marrant !
int a[3] = {0, 1, 42};
Que vaut a[2]
?
Que vaut 2 [a]
?
En fait a[i]
est une macro pour *(a+i)
.
Pointeurs vers un tableau 2D
Prenons l'exemple d'un tableau 2D d'entiers. Une façon de faire est de considérer un pointeur de pointeurs vers des entiers :
int **p;
Exercice à faire en TD
- Implémenter une fonction qui alloue un tableau 2D de taille n x n.
Un tableau 1D énorme qui simule un tableau 2D
typedef char* array2d_t;
array2d_t array2d_create(size_t sizeX, size_t sizeY) {
char *array = malloc(SIZEX * SIZEY * sizeof(char));
return array;
}
void array2d_free(array2d_t A) {
free(A);
}
char array2d_get(array2d_t A, size_t x, size_t y) {
return A[x*SIZEY + y];
}
void array2d_free(array2d_t A) {
free(A);
}
Un tableau 1D de pointeurs vers des tableaux 1D
typedef char** array2d_t;
array2d_t array2d_create(size_t sizeX, size_t sizeY) {
char **array = malloc(SIZEX * sizeof(char *));
for (int i = 0; i < SIZEX; i++)
array[i] = malloc(SIZEY * sizeof(char *));
return array;
}
void array2d_free(array2d_t A) {
for (int i = 0; i < SIZEX; i++)
free(array[i]);
free(A);
}
/*
array2d_t A = array2d_create(64, 32);
... on utilise A[x][y]...
array2d_free(A);
*/
Un tableau 1D de pointeurs vers des endroits dans un seul tableau 1D
typedef char** array2d_t;
array2d_t array2d_create(size_t sizeX, size_t sizeY) {
char **array = malloc(SIZEX * sizeof(char *));
array[0] = malloc(SIZEX*SIZEY);
for (int i = 1; i < SIZEX; i++)
array[i] = array[0] + (SIZEY * i);
return array;
}
void array2d_free(array2d_t A) {
free(A[0]);
free(A);
}
/*
array2d_t A = array2d_create(64, 32);
... on utilise A[x][y]...
array2d_free(A);
*/
Mot clé Const
En C, le mot clé const
s'applique sur ce qu'il y a à sa gauche. Il veut dire "je suis une constante".
Pointeur vers un (ou des) caractères en lecture seule
char const * pointer1 = malloc(1);
*pointer1 = 'a'; //non car le char est une constante
pointer1 = malloc(1); //yes
Par convention, on met souvent le mot-clé const
tout à gauche :
const char * pointer1 = malloc(1);
*pointer1 = 'a'; //no
pointer1 = malloc(1); //yes
const char* p = malloc(4);
p[0] = 'a'; // no
p[1] = 'a'; // no
p = malloc(4); // yes
Pointeur en lecture seule sur des caractères
Dans l'exemple suivant, le "je suis une constante" s'applique sur l'étoile, autrement dit sur le pointeur.
char* const q = malloc(4);
q[0] = 'a'; //yes
q = NULL; // non car on ne peut pas modifier le pointeur
Pointeur en lecture seule sur des caractères en lecture seule
const char* const r = malloc(4);
r[0] = 'a'; //no
r = NULL; //no
Réallocation
void * realloc( void * pointer, size_t memorySize );
Calloc
void* calloc( size_t num, size_t size );
int* A = calloc(NB_PATATES, sizeof int);
## Exercices
- Implémenter un tableau dynamique