Académique Documents
Professionnel Documents
Culture Documents
Pointeurs Et Allocation Dynamique
Pointeurs Et Allocation Dynamique
Pointeurs
• Chaque variable a une adresse en mémoire qu’il peut être utile de connaître.
• Pour obtenir cette adresse : opérateur “adresse de“ &
p = &i ; affecte adresse de i dans p
• Exemple :
void main ()
{ int i = 7 ;
printf(“ valeur de i = %d\n “, i);
printf(“ adresse de i = %p\n “, &i);
}
@ memoire:
• Résutat :
> valeur de i = 7 0x03EC 24
> adresse de i = 0x03F0 (1008(10)) 0x03F0 7 i
0x03F4 542
3
Pointeurs
• Un pointeur est une variable pouvant contenir une adresse
mémoire.
Pointeurs
§ Déclaration : en fonction du type de l’objet pointé
Entier : int *i; /* car *i est un entier */ &?
Réel: float *f ; i
Caractère: char *c;
Pointeurs
Opérations sur les objets pointés : les opérations permises sur l’objet
int *pi = &x;
*pi = *pi + 2; /* *pi et x ici interchangeables */
/* <-> x = x + 2 */
y = *pi – 1; /* <-> y = x – 1 */
Opération sans indirection : car les pointeurs sont aussi des variables
int *qi, *pi; &f
&e
avant: qi pi
qi = pi ; /* qi pointe sur même objet que pi */
Pointeurs
• Initialisation : int a,*pi; &? ?
pi a
(1) pi=&a; &a ?
pi a
*pi=3; //ok 3
&a
pi a
*
(2) avec malloc() (voir plus loin)
§ Ne pas utiliser un pointeur non initialisé par l’adresse effective d’une variable !!
§ Déclarer un pointeur réserve un espace mémoire pour stocker une adresse
mais en aucun cas pour l’objet pointé. &?
pi
int *pi;
*pi=3; /* pointeur non initialisé, contient une & aléatoire*/
/* et pas de mémoire réservée pour stocker l’entier &? pointé*/
pi
*
Attention: ce code ne fait pas d’erreur à la compilation
mais une erreur à l’exécution (Segmentation Fault)
7
Pointeurs
xkcd.com
8
Tableaux et pointeurs
• Par définition: si pa est un pointeur sur un élément d’un tableau
alors,
• pa+i pointe sur le i-ème élément du tableau après pa
• pa-i pointe sur le i-ème élément avant pa
Tableaux et pointeurs
Ainsi a[i] identique à *(pa+i), si pa pointe sur le premier élément:
*pa = *(pa+2);
&a[0] 12 ? 12 ? ?
/* noter l’importance
des parenthèses */ pa a[0] a[1] a[2] a[3] a[4]
Tableaux et pointeurs
• Le nom d’un tableau vaut l’adresse de son 1er élément: a ≈ &a[0]
fondamental!
Donc, *(a+i) identique à a[i] a a+1 a+2 …
? ? ? ? ?
a[0] a[1] a[2] a[3] a[4]
int a[5];
pa+1
*a=7; /* affecte 7 à a[0] */
a a+1
*(a+1)=2; /* idem a[1] = 2 */
int *pa = a; /* idem. pa = &a[0]; */
a 7 2
pa a[0] a[1]
Note : pa est une variable donc pa = a; puis pa = b; et pa++; VALIDES,
mais a est juste un nom donc a = pa; et a++ ; INVALIDES.
11
Tableaux et pointeurs
aussi : a+i identique à &a[i]
? ? 12 ? ?
a[0] a[1] a[2] a[3] a[4]
*a = *(a+2);
/* noter l’importance a
des parenthèses sinon :*/
12 ? 12 ? ?
a[0] a[1] a[2] a[3] a[4]
*a = *a + 2 ; a
14 ? 12 ? ?
a[0] a[1] a[2] a[3] a[4]
12
tb+1 …
Accès (similaire au tableau statique) :
tb[i] ou *(tb+i) &bloc ? ? ? ?
tb tb[0] tb[1] …
14
§ void *ptr; définit un pointeur générique, i.e dont le type de l’objet
pointé est indéfini. Avant utilisation, le convertir explicitement:
int *pi;
pi=(int*) ptr; /* pi contient la même adresse que ptr */
/* mais pi pointe sur un entier de taille sizeof(int)
et pi+1 sur l’entier suivant */
15
int main(void)
{ int n, *tab;
printf (“Taille désirée?“);
scanf (“%d“,&n);
tab=(int*) malloc (n*sizeof(int)); /* allocation dyn. de n entiers */
§ Toujours libérée la mémoire dès que l’on en a plus besoin (en fin de
programme ?)
• Note: malloc et free peuvent être utilisés pour allouer un bloc mémoire
une variable du type pointé (un tableau d’1 seul élément).
17
Erreur de Segmentation
Segmentation de la mémoire :
§ Le système d’exploitation alloue de la mémoire à chaque programme.
§ Un programme ne peut accéder (lecture/écriture) à la mémoire d’un autre
programme par sécurité: un programme avec des erreurs ne peut ainsi
corrompre un autre programme.
Erreur de Segmentation
Cause courante d’erreur de segmentation :
§ Avec scanf (““, void *) dont les arguments sont des adresses
où écrire les donnés lues au clavier,
Erreur de Segmentation
Cause commune d’erreur de segmentation :
§ Débordement de tableau statique ou dynamique
Les Structures
regroupe des éléments de types différents
facilite l’organisation et la manipulation de données composées
un composant est appelé un champ ou un membre
Les Structures
Initialisation à la déclaration :
struct coureur c1={“Bolt“,“Usain“,23,9.58};
.“
accès aux champs par l’opérateur “
c1.temps = 9.54 ; c2.dossard = 2 ;
structures et pointeurs
struct coureur *c4 ; /*n’alloue pas de mémoire
pour la structure*/
c4 = (struct coureur *)malloc(sizeof(struct coureur));
typedef
permet de définir des noms de nouveau type de données
Exemple : typdef int Longueur;
/*rend Longueur synonyme de int*/
Longueur i, *j; /* définit 1 variable et 1 pointeur (sur entier)*/
coureur c1 , c2 , *c3 ;
Segmentation Fault
24
Tableaux multidimensionnels
• Un tableau à 2 dimensions (L,C) est un tableau de tableau :
un tableau L éléments (/lignes) contenant chacun un tableau de C éléments.
a[0] a[1]
a: 1 2 3 4 5 6
a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2]
Tableaux multidimensionnels
• Comme pour un tableau 1D: a ≈ &a[0][0]
• ( a[0]est le nom du tableau de la première ligne , a[0] ≈ &a[0][0]
et a[1] ≈ &a[1][0] )
a a[0][0] a[0][1] a[0][2]
a[0] 1 2 3
a[1] 4 5 6
a[1][0] a[1][1] a[1][2]
• Accès aux composantes :
a[1]+1
a[i][j] (à préférer J)
ou *( a[i] + j )
ou encore *( *(a+i) + j )
26
Tableaux multidimensionnels
#include <stdio.h>
void main(void)
{ int m[2][3] = {{11,12,13},{21,22,23}};
*((*m)+1) = -2;
m[1][0]= -1;
printf("%i %i %i \n",
m[0][0], m[0][1], m[0][2]);
printf("%i %i %i \n",
**(m+1), *(*(m+1)+1), *( m[1]+2));
}
Sortie écran:
11 -2 13
-1 22 23
27
Le tableau de pointeurs !
s[2]
s[0]
s[1]
s O n \0
char s[] = "On"; /* idem. char s[3]= .. */
char s1[] = "est"; s1 e s t \0
char s2[] = "jeudi";
s2 j e u d i \0
s[2]
s[0]
s[1]
char * tabs[] = {s, s1, s2}; tabs
/* idem ….= { &s[0], &s1[0], &s2[0] } */ s O n \0
tabs[1][2] = x; s1 e s x \0
/* car idem *( *(tabs+1) + 2)=… */ s2 j e u d i \0
28
Le tableau de pointeurs !
Accès au caractères (toujours pareil):
tabs[i][j] ou *( *(tabs+i)+j )
s[2]
s[0]
s[1]
L’accès (toujours pareil) : tabs s O n \0
ptr_s[1][2] = X; ptr_s s1 e s X \0
ou s2 j e u d i \0
*(*(ptr_s+1)+2) = X;
29
a[2]
a[0]
a[1]
int a[3], b[4], c[3];
int * mat[3] = {a,b,c};
( tab ) a 1 -4 0
ptr_m b 7 2 11 1
( int ** ptr_m = tab; ) c -4 6 9
Le tableau int* mat[3] peut être alloué dynamiquement puis remplit avec les noms
(adresses) des tableaux:
&bloc a 1 -4 0
ptr_m b 7 2 11 1
int **ptr_m;
c -4 6 9
ptr_m = (int**) malloc ( 3*sizeof(int*) );
ptr_m[0] = a;
…
On peut encore allouer les tableaux a, b et c dynamiquement: tableau 2D dynamique.
30
ptr_m[0][0]
&bloc &bloc’ ? ? ? ?
ptr_m &bloc’’ ? ? ? ?
&bloc’’’ ? ? ? ?
31
Tableaux multidimensionnels
void main(void)
{ int i; int Lignes = 3,Colonnes = 4;
int ** ptr_m; /* pointeur sur un pointeur */
Tableaux multidimensionnels
• Autre solution: considérer le tableau 2D comme un vecteur
1 2 3 4
Tableaux multidimensionnels
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
int m_toto[6] = {11,12,13,21,22,23}; //matrice 2x3
printf("%i %i %i \n",
m_toto[0*3+0], m_toto[0*3+1], m_toto[0*3+2]);
printf("%i %i %i \n",
*(m_toto+1*3), *(m_toto+1*3+1), *(m_toto+1*3+2));
}
Sortie écran:
11 12 13
21 22 23