1
Algorithmique et programmation II
Année Universitaire 2018/2019
Niveau : Tronc Commun
Semestre2
Sana REFAI
sana.refai@gmail.com
1
Plan du cours
2
Chapitre 1: Pointeurs et allocation
dynamique
Chapitre 2: Les listes chaînées
Chapitre 3: Les piles
Chapitre 4: Les files
Chapitre 5: Les arbres
2
Chapitre 1: Les pointeurs
3
Introduction(1/2)
Inconvénients des variables statiques
Les variables « classiques », déclarées avant l'exécution d'un
programme sont des variables statiques, c'est à dire que la place
qui leur est réservée en mémoire est figée durant toute l'exécution
du programme.
Ceci a deux conséquences :
• Risque de manquer de place si la place réservée (par exemple le
nombre d'éléments d'un tableau) est trop petite. Il faut alors que le
programme prenne en charge le contrôle du débordement.
• Risque de risque de gaspiller de la place si la place réservée est
beaucoup plus grande que celle qui est effectivement utilisée par
le programme.
Un cahier, dont le nombre de pages est fixé a priori, fournit une
bonne image d'une variable statique.
4
Introduction(2/2)
Introduction des variables dynamiques
Les variables dynamiques vont permettre :
• de prendre la place en mémoire au fur et à
mesure des besoins, celle-ci étant bien sûr limitée
par la taille de la mémoire,
• de libérer de la place lorsqu'on n'en a plus
besoin.
Un classeur dans lequel on peut ajouter ou
retirer des pages est une bonne image d'une
variable dynamique.
5
Le pointeur
 Un pointeur est une variable dont le contenu est une
adresse mémoire, elle sert à pointer sur une zone
mémoire donnée contenant une variable d’un type bien
précis sans tenir compte de sa valeur.
 Exemple:
P P^
@100C
« Kélibia"
 P pointe sur une chaine de caractère, le contenu de la
case mémoire pointée par P est P^ sa valeur est
« Kélibia »
6
Notation et déclaration
P : ^ entier : Définit un pointeur sur un entier.
Q : ^ Objet : Définit un pointeur sur une
structure.
P^, T^ : Définit le contenu de P et le contenu
de T.( autre présentation *P et *T)
En algorithmique En C
Syntaxe Variables:
Nom_var: ^nom_type
nom_type *Nom_var;
Exemple Variables:
Ptr1,Ptr2: ^entier
Ptr3:^reel
Int *Ptr1,*Ptr2;
Float * Ptr3;
7
Allocation / désallocation (1/4)
5
 On définit un type t.
 On déclare : ptr : pointeur_sur_t ou ^t.
Création d'une variable dynamique de type t :
allouer(ptr)
 réserve un emplacement mémoire de la
taille correspondant au type t,
 met dans la variable ptr l'adresse de la zone
mémoire qui a été réservée. L'emplacement
pointé par ptr sera accessible par ptr^.
8
Allocation / désallocation (2/4)
6
Exemple:
ptr : ^t
allouer(ptr)
ptr
ptr ptr^:t
9
Allocation / désallocation (3/4)
7
Libération de la place occupée par une
variable dynamique
desallouer(ptr)
 libère la place de la zone mémoire dont
l'adresse est dans ptr (et la rend disponible
pour l'allocation d'autres variables)
 laisse la valeur du pointeur en l'état
(n'efface pas l'adresse qui est dans la
variable pointeur).
10
Allocation / désallocation (4/4)
Exemple:
desallouer(ptr)
ptr
ptr ptr^:t
En algorithmique En C
Syntaxe allouer(ptr) ptr=(type*)malloc(sizeof(type));
Exemple desallouer(ptr) free(ptr);
Remarque : si on fait appel au pointeur
désalloué, il renvoie une information qui n'a
aucun sens.
11
Affectation entre pointeurs (1/2)
7
 Les pointeurs peuvent être impliqués dans des
affectations au cours desquelles des adresses
sont assignées aux pointeurs.
 Pour « vider » un pointeur, c'est à dire annuler
l'adresse qu'il contient, on lui affecte une valeur
prédéfinie nommée Nil (ou Null).
 Attention :le fait de mettre Nil dans un pointeur
ne libère pas l'emplacement sur lequel il
pointait. L'emplacement devient irrécupérable
car le lien vers cet emplacement a été coupé
par la valeur Nil. Il faut désallouer avant
d'affecter le pointeur avec Nil. ptr ← Nil
Règle de bonne programmation : dès
qu'on a désalloué un pointeur, il faut lui
affecter la valeur Nil, pour qu'il ne
conserve pas une adresse mémoire qui
n'a plus d'existence physique.
12
Affectation entre pointeurs (2/2)
7
 On peut affecter un pointeur avec tout autre
pointeur de même type.
 Après cette affectation, deux pointeurs
désignent la même zone de mémoire.
Exemple
ptr1, ptr2 : pointeur sur t
allouer(ptr1)
ptr2 ← ptr1
Pour libérer la zone mémoire on désalloue ptr1 ou
(exclusif) ptr2, puis on met la valeur Nil dans ptr1
et dans ptr2.
ptr2
ptr1
13
Accès à la variable pointée
7
 Une fois la variable ptr déclarée et allouée,
l'accès en écriture ou lecture à la variable
pointée par ptr se fait avec l'identificateur ptr^.
On peut appliquer à ptr^ les mêmes
instructions qu'à une variable simple. ptr1, ptr2
: pointeur sur t.
ptr^ ← <expression de type t>
lire(ptr^)
écrire(ptr^)
14
Exercice(1/2)
7
1-Dérouler l’algorithme suivant
en montrant l'état de la mémoire
en plus de ce qui s'affiche à l'écran.
2- Où est l'erreur dans cet
algorithme?
Variables
ptc : pointeur sur chaîne de caractères
ptx1, ptx2 : pointeur sur entier
Début
allouer(ptc)
ptc^ <- ‘ISET’
écrire(ptc^)
allouer(ptx1)
lire(ptx1^)
ptx2<- ptx1
écrire(ptx2^)
ptx2^<- ptx1^ + ptx2^
écrire(ptx1^, ptx2^)
Ptx1<- Nil
écrire(ptx2^)
désallouer(ptx2)
Ptx2<- Nil
Ptc<- Nil
Fin
15
Exercice(2/2)
7
ptc ptx1 ptx2
ISET
Variables
ptc : pointeur sur chaîne de caractères
ptx1, ptx2 : pointeur sur entier
Début
allouer(ptc)
ptc^ <- ‘ISET’
écrire(ptc^)
allouer(ptx1)
lire(ptx1^)
ptx2<- ptx1
écrire(ptx2^)
ptx2^<- ptx1^ + ptx2^
écrire(ptx1^, ptx2^)
Ptx1<- Nil
écrire(ptx2^)
désallouer(ptx2)
Ptx2<- Nil
Ptc<- Nil
Fin
ISET ISET
ISET 100
ISET 100
100
ISET 200
200 200
ISET 200
200
ISET
ISET
ISET
ERROR: on a coupé l'accès à la
zone de mémoire sans la
désallouer. Elle est irrécupérable
16
Pointeur et enregistrement (1/3)
7
 Il est très courant d’utiliser un pointeur pour
mémoriser l’adresse d’un enregistrement.
17
Type
tpersonne = enregistrement
nom : chaine
tel : chaine
finenreg
Var
pers: tpersonne
pointpers : ^tpersonne
Début
pers.nom <- "Mohamed"
pers.tel <- "0145698521"
pointpers <- &pers
Ecrire (pointpers^.nom) //donne à l’écran Mohamed
Ecrire (pointpers^.tel) //donne à l’écran 0145698521
…
Fin
Pointeur et enregistrement (2/3)
7
 Dans un enregistrement, un des champs peut très bien être un
pointeur, par exemple sur un autre enregistrement.
18
Type
tinstit = enregistrement
nom_ins : chaine
tel : chaine
finenreg
télève = enregistrement
nom_el: chaine
pinstit : ^tinstit
finenreg
Var
instituteur : tinstit
élève1, élève2: télève
Début
instituteur.nom_ins <- "Dupond"
instituteur.tel <- "0123654896"
élève1.nom_el <- "Pierre"
élève1.pinstit <- &instituteur
élève2.nom_el <- "Hakim"
élève2.pinstit <- &instituteur
Ecrire (élève1.pinstit^.nom) // affiche Dupond à l’écran
Ecrire (élève2.pinstit^.nom) // idem
Passage de paramètres par adresse
7
En C, seul le passage de paramètres par valeur est
disponible. Le passage de paramètres résultats (i.e.
paramètres dont la valeur est modifiée par une fonction)
n’est pas supporté. Le seul moyen dont on dispose pour
approcher ce mode de passage est d’utiliser comme
paramètre effectif une adresse.
void incr(int *a)
{ *a = (*a)++ ; }
int main() {
int x = 5;
incr(&x);
printf("%d", x);
return 0 ;
}
19
Tableaux et pointeurs
720
 Par définition: si pa est un pointeur sur un élément d’un
tableau tab 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
 Le nom d’un tableau vaut l’adresse de son 1er élément:
 si pa=tab alors *(pa+i) identique à tab[i]
Exemple en C:
int *pa, a[5];
/*idem pa=a*/
pa = &a[0];
Note : si pa contient 0x10, l’adresse du premier
élément, alors pa+1 ou p++ vaut 0x14 dans le cas où
l’entier signé est codé sur 4 octets.

Cours algo: Les pointeurs

  • 1.
    1 Algorithmique et programmationII Année Universitaire 2018/2019 Niveau : Tronc Commun Semestre2 Sana REFAI sana.refai@gmail.com 1
  • 2.
    Plan du cours 2 Chapitre1: Pointeurs et allocation dynamique Chapitre 2: Les listes chaînées Chapitre 3: Les piles Chapitre 4: Les files Chapitre 5: Les arbres 2
  • 3.
    Chapitre 1: Lespointeurs 3
  • 4.
    Introduction(1/2) Inconvénients des variablesstatiques Les variables « classiques », déclarées avant l'exécution d'un programme sont des variables statiques, c'est à dire que la place qui leur est réservée en mémoire est figée durant toute l'exécution du programme. Ceci a deux conséquences : • Risque de manquer de place si la place réservée (par exemple le nombre d'éléments d'un tableau) est trop petite. Il faut alors que le programme prenne en charge le contrôle du débordement. • Risque de risque de gaspiller de la place si la place réservée est beaucoup plus grande que celle qui est effectivement utilisée par le programme. Un cahier, dont le nombre de pages est fixé a priori, fournit une bonne image d'une variable statique. 4
  • 5.
    Introduction(2/2) Introduction des variablesdynamiques Les variables dynamiques vont permettre : • de prendre la place en mémoire au fur et à mesure des besoins, celle-ci étant bien sûr limitée par la taille de la mémoire, • de libérer de la place lorsqu'on n'en a plus besoin. Un classeur dans lequel on peut ajouter ou retirer des pages est une bonne image d'une variable dynamique. 5
  • 6.
    Le pointeur  Unpointeur est une variable dont le contenu est une adresse mémoire, elle sert à pointer sur une zone mémoire donnée contenant une variable d’un type bien précis sans tenir compte de sa valeur.  Exemple: P P^ @100C « Kélibia"  P pointe sur une chaine de caractère, le contenu de la case mémoire pointée par P est P^ sa valeur est « Kélibia » 6
  • 7.
    Notation et déclaration P: ^ entier : Définit un pointeur sur un entier. Q : ^ Objet : Définit un pointeur sur une structure. P^, T^ : Définit le contenu de P et le contenu de T.( autre présentation *P et *T) En algorithmique En C Syntaxe Variables: Nom_var: ^nom_type nom_type *Nom_var; Exemple Variables: Ptr1,Ptr2: ^entier Ptr3:^reel Int *Ptr1,*Ptr2; Float * Ptr3; 7
  • 8.
    Allocation / désallocation(1/4) 5  On définit un type t.  On déclare : ptr : pointeur_sur_t ou ^t. Création d'une variable dynamique de type t : allouer(ptr)  réserve un emplacement mémoire de la taille correspondant au type t,  met dans la variable ptr l'adresse de la zone mémoire qui a été réservée. L'emplacement pointé par ptr sera accessible par ptr^. 8
  • 9.
    Allocation / désallocation(2/4) 6 Exemple: ptr : ^t allouer(ptr) ptr ptr ptr^:t 9
  • 10.
    Allocation / désallocation(3/4) 7 Libération de la place occupée par une variable dynamique desallouer(ptr)  libère la place de la zone mémoire dont l'adresse est dans ptr (et la rend disponible pour l'allocation d'autres variables)  laisse la valeur du pointeur en l'état (n'efface pas l'adresse qui est dans la variable pointeur). 10
  • 11.
    Allocation / désallocation(4/4) Exemple: desallouer(ptr) ptr ptr ptr^:t En algorithmique En C Syntaxe allouer(ptr) ptr=(type*)malloc(sizeof(type)); Exemple desallouer(ptr) free(ptr); Remarque : si on fait appel au pointeur désalloué, il renvoie une information qui n'a aucun sens. 11
  • 12.
    Affectation entre pointeurs(1/2) 7  Les pointeurs peuvent être impliqués dans des affectations au cours desquelles des adresses sont assignées aux pointeurs.  Pour « vider » un pointeur, c'est à dire annuler l'adresse qu'il contient, on lui affecte une valeur prédéfinie nommée Nil (ou Null).  Attention :le fait de mettre Nil dans un pointeur ne libère pas l'emplacement sur lequel il pointait. L'emplacement devient irrécupérable car le lien vers cet emplacement a été coupé par la valeur Nil. Il faut désallouer avant d'affecter le pointeur avec Nil. ptr ← Nil Règle de bonne programmation : dès qu'on a désalloué un pointeur, il faut lui affecter la valeur Nil, pour qu'il ne conserve pas une adresse mémoire qui n'a plus d'existence physique. 12
  • 13.
    Affectation entre pointeurs(2/2) 7  On peut affecter un pointeur avec tout autre pointeur de même type.  Après cette affectation, deux pointeurs désignent la même zone de mémoire. Exemple ptr1, ptr2 : pointeur sur t allouer(ptr1) ptr2 ← ptr1 Pour libérer la zone mémoire on désalloue ptr1 ou (exclusif) ptr2, puis on met la valeur Nil dans ptr1 et dans ptr2. ptr2 ptr1 13
  • 14.
    Accès à lavariable pointée 7  Une fois la variable ptr déclarée et allouée, l'accès en écriture ou lecture à la variable pointée par ptr se fait avec l'identificateur ptr^. On peut appliquer à ptr^ les mêmes instructions qu'à une variable simple. ptr1, ptr2 : pointeur sur t. ptr^ ← <expression de type t> lire(ptr^) écrire(ptr^) 14
  • 15.
    Exercice(1/2) 7 1-Dérouler l’algorithme suivant enmontrant l'état de la mémoire en plus de ce qui s'affiche à l'écran. 2- Où est l'erreur dans cet algorithme? Variables ptc : pointeur sur chaîne de caractères ptx1, ptx2 : pointeur sur entier Début allouer(ptc) ptc^ <- ‘ISET’ écrire(ptc^) allouer(ptx1) lire(ptx1^) ptx2<- ptx1 écrire(ptx2^) ptx2^<- ptx1^ + ptx2^ écrire(ptx1^, ptx2^) Ptx1<- Nil écrire(ptx2^) désallouer(ptx2) Ptx2<- Nil Ptc<- Nil Fin 15
  • 16.
    Exercice(2/2) 7 ptc ptx1 ptx2 ISET Variables ptc: pointeur sur chaîne de caractères ptx1, ptx2 : pointeur sur entier Début allouer(ptc) ptc^ <- ‘ISET’ écrire(ptc^) allouer(ptx1) lire(ptx1^) ptx2<- ptx1 écrire(ptx2^) ptx2^<- ptx1^ + ptx2^ écrire(ptx1^, ptx2^) Ptx1<- Nil écrire(ptx2^) désallouer(ptx2) Ptx2<- Nil Ptc<- Nil Fin ISET ISET ISET 100 ISET 100 100 ISET 200 200 200 ISET 200 200 ISET ISET ISET ERROR: on a coupé l'accès à la zone de mémoire sans la désallouer. Elle est irrécupérable 16
  • 17.
    Pointeur et enregistrement(1/3) 7  Il est très courant d’utiliser un pointeur pour mémoriser l’adresse d’un enregistrement. 17 Type tpersonne = enregistrement nom : chaine tel : chaine finenreg Var pers: tpersonne pointpers : ^tpersonne Début pers.nom <- "Mohamed" pers.tel <- "0145698521" pointpers <- &pers Ecrire (pointpers^.nom) //donne à l’écran Mohamed Ecrire (pointpers^.tel) //donne à l’écran 0145698521 … Fin
  • 18.
    Pointeur et enregistrement(2/3) 7  Dans un enregistrement, un des champs peut très bien être un pointeur, par exemple sur un autre enregistrement. 18 Type tinstit = enregistrement nom_ins : chaine tel : chaine finenreg télève = enregistrement nom_el: chaine pinstit : ^tinstit finenreg Var instituteur : tinstit élève1, élève2: télève Début instituteur.nom_ins <- "Dupond" instituteur.tel <- "0123654896" élève1.nom_el <- "Pierre" élève1.pinstit <- &instituteur élève2.nom_el <- "Hakim" élève2.pinstit <- &instituteur Ecrire (élève1.pinstit^.nom) // affiche Dupond à l’écran Ecrire (élève2.pinstit^.nom) // idem
  • 19.
    Passage de paramètrespar adresse 7 En C, seul le passage de paramètres par valeur est disponible. Le passage de paramètres résultats (i.e. paramètres dont la valeur est modifiée par une fonction) n’est pas supporté. Le seul moyen dont on dispose pour approcher ce mode de passage est d’utiliser comme paramètre effectif une adresse. void incr(int *a) { *a = (*a)++ ; } int main() { int x = 5; incr(&x); printf("%d", x); return 0 ; } 19
  • 20.
    Tableaux et pointeurs 720 Par définition: si pa est un pointeur sur un élément d’un tableau tab 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  Le nom d’un tableau vaut l’adresse de son 1er élément:  si pa=tab alors *(pa+i) identique à tab[i] Exemple en C: int *pa, a[5]; /*idem pa=a*/ pa = &a[0]; Note : si pa contient 0x10, l’adresse du premier élément, alors pa+1 ou p++ vaut 0x14 dans le cas où l’entier signé est codé sur 4 octets.

Notes de l'éditeur

  • #3 Rechercher un element ds un tableau
  • #4 Rechercher un element ds un tableau
  • #5 Rechercher un element ds un tableau
  • #6 Rechercher un element ds un tableau
  • #7 Rechercher un element ds un tableau
  • #8 Rechercher un element ds un tableau
  • #9 Rechercher un element ds un tableau
  • #10 Rechercher un element ds un tableau
  • #11 Rechercher un element ds un tableau
  • #12 Rechercher un element ds un tableau
  • #13 Rechercher un element ds un tableau
  • #14 Rechercher un element ds un tableau
  • #15 Rechercher un element ds un tableau
  • #16 Rechercher un element ds un tableau
  • #17 Rechercher un element ds un tableau
  • #18 Rechercher un element ds un tableau
  • #19 Rechercher un element ds un tableau
  • #20 Rechercher un element ds un tableau
  • #21 Rechercher un element ds un tableau