Vous êtes sur la page 1sur 44

Chapitre 4

Pointeurs & Tableaux


Dr. Imen BOUDALI

imen.boudali@gmail.com / imen.boudali@enit.utm.tn

Université Tunis-El Manar

Ecole Nationale d’Ingénieurs de Tunis, Département TIC- ENIT

2020 - 2021
29/10/2020
Plan
• Partie 1: les pointeurs

• Partie 2: les tableaux

• Partie 3: allocation dynamique

29/10/2020
Qu’est ce qu’un pointeur 84

• Un pointeur est une variable dont le contenu pointe vers


une autre variable.

• Un pointeur peut recevoir des valeurs différentes au cours


de l’exécution

• Le contenu est une adresse d’une autre variable

• Appelé aussi variable d’adresse.

29/10/2020
Exemple

L’opérateur d’adresse & permet de trouver l’adresse mémoire d’une variable


Création (allocation) de « a »
à une adresse choisie par l’ordinateur
#include <stdio.h> Attention : Valeur de a quelconque !
int main() {
int a; Affectation de « a »
a=5; Ecriture de la valeur 5 à
printf("Bonjour %d\n", a); l’adresse de « a » en mémoire
printf("La valeur de a est %d \n", a);
printf("L’adresse de a est %p \n", &a); return 0;
}
Affichage de l’adresse de la
variable a

Destruction de « a »
à la fin du « bloc »

29/10/2020
L’opérateur d’adresse « & » 86

Un pointeur est une variable qui contient l'adresse d'une autre


variable.

L'opérateur unaire & donne l'adresse mémoire d'un objet.

L'instruction :
 p = &c; //affecte l'adresse de c à la variable p.

On dit que p pointe sur c.

L'opérateur unaire & s'applique uniquement sur des objets en


mémoire.

29/10/2020
DECLARATION DES POINTEURS 87

Une variable de type pointeur se déclare à l'aide de l'objet pointé


précédé du symbole * (opérateur d'indirection).

char *pc; pc est un pointeur pointant sur un objet de type char

int *pi; pi est un pointeur pointant sur un objet de type int

float *pr; pr est un pointeur pointant sur un objet de type float

29/10/2020
Contenu d’une adresse 88

L'opérateur * désigne aussi le contenu de l'adresse.

char *pc;
*pc = 34 ;
printf("CONTENU DE LA CASE MEMOIRE: %c\n",*pc);
printf("VALEUR DE L'ADRESSE EN HEXADECIMAL: %p\n",pc);

le format d'une adresse est %p (hexadécimal) ou %d


(décimal) dans printf

29/10/2020
Pointeurs multiples 89

• Plusieurs pointeurs peuvent être dirigés vers un même emplacement


mémoire.

29/10/2020
Plan
• Partie 1: les pointeurs

• Partie 2: les tableaux

• Partie 3: allocation dynamique

29/10/2020
Les tableaux
91
Nombre indice
d’éléments
T[0] T[1] T[2] T[3] T[4]
int T[5]; T
Type des Nom
éléments
En C:
int Premiers [4]; 1. Les indices commencent par 0
Premiers [0] = 2;
2. T[i] : i+1ème élément
Premiers [1] = 3;
Premiers [2] = 5;
Premiers [3] = 7;
printf(“Le 3e nombre premier: %d\n”, Premiers [2]);
printf(“Somme du 2e et du 3e: %d”, Premiers[1]+ Premiers[2]);

Le 3e nombre premier: 5
Somme du 2e et du 3e: 8

29/10/2020
Utilisation 92

• Indexation par une variable

int T [4]; L’élément d’indice 3 est 7


int i = 3;
T[0]=2; T[1]=3; T[2]=5; T[3]=7;
printf (“L’élément d’indice %d est %d”, i, T[i]);

Parcours d'un tableau à l'aide d'une boucle

int T [4]; Indice 0: Valeur 2


int i; Indice 1: Valeur 3
T[0]=2; T[1]=3; T[2]=5; T[3]=7; Indice 2: Valeur 5
for (i= 0; i< 4; i++) Indice 3: Valeur 7
{
printf (“Indice %d: Valeur %d\n”, i, T[i]);
}
29/10/2020
Remplir un tableau 93

Remplir un tableau à l'aide d'une boucle

int T [4], i, x;
for (i= 0; i< 4; i++)
{
printf ("Donnez l'élément n°:%d", i);
scanf (“%d”, &x); scanf (“%d”, &T[i]);
T[i] = x;
}
On peut initialiser un tableau lors de sa déclaration

int Tpremiers [4] = {2, 3, 5, 7};

Et même:
int Tpremiers [] = {2, 3, 5, 7};

Par contre, on ne peut pas utiliser l'affectation !

int Tpremiers [4];


Tpremiers = {2, 3, 5, 7};
29/10/2020
Exemple: Copie, comparaison: Attention ! 94

On ne peut pas affecter un tableau à un autre par =

int T1 [4] = {2, 3, 5, 7};


int T2 [4];
T2 = T1;

Ni comparer un tableau avec un autre par ==

int T1 [4] = {2, 3, 5, 7};


int T2 [4] = {2, 3, 5, 7};
if (T1 == T2)
printf ("Tableaux identiques.");
else
printf ("Tableaux différents.");

29/10/2020
Exercice: Comparer le contenu de deux tableaux?
95

#include <stdio.h>
void main ()
{
float T1 [4] = {2, 3, 5, 7}, T2 [4];
int i; int Egaux;

for (i = 0; i<4; i++)


{ T2 [i] = T1 [i]; }

Egaux = 1; i = 0;
while ((i < 4) && (Egaux = = 1))
{
if (T1 [i] != T2 [i])
Egaux = 0;
else
i++;
}
if (Egaux = = 1) printf ("Tableaux identiques.");
else printf ("Tableaux différents.");
}
29/10/2020
Taille des tableaux 96

• C’est l’espace mémoire occupé par un


tableau, comptabilisé en octets.

• Expression 1:
• type Tableau[Taille];
• sizeof(type) * Taille;

• Expression 2: en utilisant uniquement le nom


• type Tableau[Taille];
• sizeof(Tableau);

29/10/2020
Taille des tableaux
97

29/10/2020
Tableaux et pointeurs 98

• En déclarant un tableau, on définit automatiquement un pointeur (on définit


en fait l'adresse du premier élément du tableau).
• Les écritures suivantes sont équivalentes:

• int *tableau; int tableau[10]; // déclaration

• *tableau tableau[0] //le 1er élément

• *(tableau+i) tableau[i] //un autre élément

• tableau &tableau[0] //adresse du 1er élément

• (tableau + i) &(tableau[i]) //adresse d'un autre

29/10/2020
Plan
• Partie 1: les pointeurs

• Partie 2: les tableaux

• Partie 3: allocation dynamique

29/10/2020
Quand l'utiliser ?
100

• Quand on connait à l’avance le nombre d’éléments à stocker


dans un tableau, => Les tableaux sont statiques.

• Si le nombre d’objets à stocker dans le tableau n’est connu


qu’à l’exécution, => il faut avoir recours à l’allocation
dynamique.

• L’allocation dynamique est utilisée aussi :


• Pour les tableaux à plusieurs indices même si les
dimensions sont connues à priori.
• Pour stocker des données volumineuses.

Presentation Title 29/10/2020


La mise en Œuvre 101

Il faut :
1. Une variable normale de type pointeur sur la donnée à
stocker

2. Utiliser la fonction malloc() ou une fonction similaire


pour affecter une adresse à cette variable.

3. Libérer la mémoire lorsqu’on n’en a plus besoin avec la


fonction free() .

Presentation Title 29/10/2020


Allocation dynamique de mémoire
• 4 fonctions sont offertes pour gérer l’espace
mémoire dynamiquement:
 malloc()
 calloc()
 realloc()
 free()
 Fonctions prédéfinies dans la bibliothèque stdlib.h

• Toute allocation dynamique avec malloc(), calloc(),


realloc() nécessite une libération par la suite avec free().

29/10/2020
Fonction malloc()

• Permet d’indiquer la taille de l’emplacement à réserver


en mémoire

• Syntaxe:
#include<stdlib.h>
void* malloc (size_t taille)

Type désignant les tailles en


Pointeur sur un type octets
quelconque

29/10/2020
Fonction malloc()
• Syntaxe:
#include<stdlib.h>
void* malloc (size_t taille)

Type désignant les tailles en


Pointeur sur un type
octets
quelconque

Assure la réservation d’un espace mémoire avec la taille indiquée et


retourne :
• l’adresse de l’espace réservé, en cas de succès;
• NULL en cas d’échec (pas d’espace mémoire suffisant);
N.B.
 pour certains compilateurs le pointeur void* retourné est

automatiquement converti au type de pointeur à gauche de


l’affectation
 Pour d’autres compilateurs, il est nécessaire de faire explicitement la

conversion (cast)
29/10/2020
Exemple:
#include<stdio.h>
#include<stdlib.h>
int main() {
int * ptr = NULL;
int max;
printf("saisir le nombre d’éléments");
scanf("%d", &max);
/* allocation d’un tableau d’entier de taille max*/
ptr = malloc (max * sizeof(int));
/*ou encore ptr = (int*) malloc (max * sizeof(int)); */
if (ptr == NULL)
printf ("Echec d’allocation \n");
else
printf ("succès d’allocation \n");
free (ptr);
return 0;
}

29/10/2020
Fonction calloc()
• Permet de réserver un espace mémoire et l’initialiser à 0

• Syntaxe:
#include<stdlib.h>
void* calloc (size_t nbre, size_t taille)

Nombre de Taille de chaque


Pointeur sur un type
cases case
quelconque

• Retourne l’adresse de l’espace réservé en cas de succès, sinon NULL;

29/10/2020
Exemple:

ptr1[0] = 2345.1, ptr2[0] = 0.0


ptr1[1] = 7890.6, ptr2[1] = 0.0
ptr1[2] = 9875.8, ptr2[2] = 0.0

 Résultats d’exécution
29/10/2020
Fonction realloc()
• Permet de modifier la taille d’un espace déjà réservé à l’aide
de malloc() ou de calloc()

• Syntaxe:
#include<stdlib.h>
void* realloc (void* bloc, size_t taille)

Pointeur sur Nombre total d’octets


Pointeur sur un type souhaité
l’adresse d’un
quelconque espace déjà alloué

• Retourne l’adresse de l’espace réservé en cas de succès,


sinon NULL;

29/10/2020
Remarques

• realloc() peut avoir le même effet que la fonction free


quand taille est égal à 0 :
free(ptr)  realloc(ptr, 0)

• realloc () est équivalente à la fonction malloc() si le 1er


argument transmis est NULL
ptr= realloc (NULL, 10*sizeof(float)) ;

ptr = malloc ( 10*sizeof(float) );

29/10/2020
Exemple:

29/10/2020
111

PASSAGE DE TABLEAUX
DANS LES FONCTIONS

29/10/2020
Principe 112

 Les VALEURS des paramètres effectifs sont copiées dans les


paramètres formels
Int main()
La valeur de a est copiée dans v1
{ int a, b, valmax;
La valeur de b est copiée dans v2
...
valmax = max( a, b);
return 0;
}
L'appel de fonction prend comme valeur,
int max( int v1, int v2) celle renvoyée par l'instruction return
{
int maximum;
if (v1 > v2) maximum = v1;
else maximum = v2;
return maximum;
}

29/10/2020
Exemple de Passage de données

int Fact (int x);


int main()
{
int A, F;
printf (“Entrez un entier positif:“); scanf(“%d”, &A);
F = Fact (A);
printf (“Factorielle de %d : %d”, A, F);
}

int Fact (int x)


{
int i, N = 1;
for (i = 1; i<=x; i++)
N = N * i;

return N;
}

113
29/10/2020
Exemple: Passage d’un tableau en
paramètre
#include <stdio.h>
double MoyenneTableau (int v[], int Taille);
int main()
{
int Valeurs[4] = {2, 4, 3, 8};
double ValeurMoyenne; Taille de v
ValeurMoyenne = MoyenneTableau (Valeurs, 4);
printf(“Moyenne: %f\n”, ValeurMoyenne);
}

double MoyenneTableau (int V[], int Taille)


{
int i, Somme;
Somme = 0;
for (i = 0; i < Taille; i++)
{ Somme = Somme + V[i]; }// somme += *(v+i);
return (double)Somme / Taille;
}
114
29/10/2020
Retourner une adresse 115

Locale

29/10/2020
116

LOCALITÉ DES VARIABLES, PASSAGE


PAR VALEUR ET PAR ADRESSE

29/10/2020
Localité des variables
int main()
{
int a, b, valmax;
printf(“ Tapez deux entiers: “);
scanf(“% d% d”, &a, &b); Visibles : a, b, valmax
valmax = max( a, b); NON visibles : maximum, v1, v2

printf(“Maximum de ces deux valeurs: %d”, valmax);


}

int max( int v1, int v2)


{
Visibles : maximum, v1, v2
int maximum; NON visibles : a, b, valmax
if (v1 > v2) maximum = v1;
else maximum = v2;
return maximum;
}
117
29/10/2020
Passage de paramètres par valeur ou par
copie
Copie des valeurs des paramètres effectifs dans les paramètres formels.

C'est la transmission de paramètres par copie de valeur.

void main () A 5 Copié dans void F1 (int X)


{ B 5 X {
int A; int Y;
int B; Y
A = 5; Y = X;
F1 (A);
B = A; X = 6;
} }

29/10/2020
Passage par valeur

void incremente (int val);


void main()
{ v 12
int v = 12;
incremente ( v); v vaut 12
printf (“v vaut %d”, v);
}
void incremente (int val)
{
val = val + 1;
} val 12
13

29/10/2020
Transmission par adresse
C'est l'adresse de v qui a été copiée

C'est la transmission de paramètres par adresse

Pointe sur
void main () v 12
13
{
&v Adr
int v = 12;
void incremente (int *Adr)
incremente (&v);
{
}
* Adr = *Adr + 1;
}

120
29/10/2020
Passage par adresse :

void incremente (int * val);


void main()
{
int v = 12;
incremente (&v);
v vaut 13
printf (“v vaut %d”, v);
}
void incremente (int * val)
{
*val = *val + 1;
}

29/10/2020
Exercices ?
Que contiennent X, Y et Z à la fin de la fonction main () ?

void F2 (int A, int B, int * C);


void F3 (int K, int L, int * M); X Y Z
void main () 1 2 9
{ int X, Y, Z;
X= 1; Y = 2; Z = 9; X Y Z
F2 (X, Y, &Z); 1 2 7
}
void F2 (int A, int B, int * C) A B *C
{ 1 2 4
9
*C = 4;
F3 (A, B, C); A B *C
A = 4; 4 2 7
}
void F3 (int K, int L, int * M) K L *M
{ 1 2 4
K = 5;
*M = K + L; K L *M
} 122 5 2 7
29/10/2020
Passage de paramètres : résumé

Qu'il y ait code retour ou pas, une fonction peut avoir


des paramètres
• Passés par copie de valeur  pas de modification(input)
• Passés par adresse  altération (in/output)

• Attention aux tableaux. Ils sont TOUJOURS


(implicitement) transmis par adresse.

123
29/10/2020
Exercices 124

1. Ecrire un programme qui permet de


• allouer un tableau d’entiers d’une taille n saisie
par l’utilisateur.;
• remplir les éléments du tableau sachant que
certains éléments sont nuls.
• parcourir le tableau et afficher les indices des
éléments nuls

Presentation Title 29/10/2020


2. Ecrire un programme qui déclare un tableau Nb_jours qui doit être initialisé
de façon à ce que Nb_jous[i] soit égal au nombre de jours du ième mois de
125
l’année, pour i de 1 à 12 (Nb_jours[0] sera inutilisé)

• Ecrire une procédure d’initialisation de Nb_jours qui utilisera la démarche


suivante :
• Si i vaut 2, le nombre de jours est de 28
• Sinon, si i est pair et i<=7 ou i impair et i>7, alors le nombre est 30
• Sinon le nombre de jours esrt de 31

• Ecrire une fonction Affichage qui assure l’affichage des 12 valeurs utiles de
Nb_jours

• La procédure main se contentera d’appeler les procédures d’initialisation et


d’affichage

• Une variante de ce programme est de réaliser une procédure Affichage_V2


qui pour un mois i donné par l’utilisateur, permet d’afficher le nombre de jours
correspondant

Presentation Title 29/10/2020

Vous aimerez peut-être aussi