Vous êtes sur la page 1sur 45

1re anne LF IAG Semestre 2 2012/2013

Atelier de programmation II

Par Dr. Slim BECHIKH

Facult des Sciences Economiques et de Gestion de Nabeul (FSEGN)


Dr. Slim BECHIKH 1 Atelier de programmation II

Plan
Les types de donnes structures. Pointeurs et allocation dynamique de la mmoire. Les Listes:
simplement chanes, doublement chanes.

Les arbres:
n-aires, binaires, quilibrs.

Dr. Slim BECHIKH

Atelier de programmation II

Rfrence bibliographique

Dr. Slim BECHIKH

Atelier de programmation II

Sance N1: Les types de donnes structures

Dr. Slim BECHIKH

Atelier de programmation II

1) Quest quun type structur en C?


Nous continuons notre tude des structures de donnes qui sont prdfinies dans la plupart des langages de programmation. La structure tableau permet de regrouper un certain nombre de donnes de mme type. Les types structurs vont nous permettre de manipuler des donnes structures dont les types des lments peuvent tre diffrents.

Une structure, appele enregistrement dans d'autres langages (comme PASCAL), est une variable contenant plusieurs variables, appeles champs. Si une structure S contient un char et un int, chacun de ces champs portera un nom, par exemple Ch et Ent. Dans ce cas, S.Ch dsignera le char de S et S.Ent dsignera le int de S.
Dr. Slim BECHIKH 5 Atelier de programmation II

1) Quest quun type structur en C?


Tableau versus Structure int int int int int

20 18

int char [30]

06895612 Ahmed

7
19

char [50]
char [100] int

Chaouachi
Expert comptable

16

98 122 155
Structure Personne.

Tableau dentiers.

Dr. Slim BECHIKH

Atelier de programmation II

2) Comment dclarer une structure en C?


Syntaxe de dclaration
struct nom_du_type { type_champ_1 nom_champ_1; type_champ_2 nom_champ_2; ... type_champ_n nom_champ_n; };
/*Exemple*/ struct Personne { int num_cin; char [30] prenom; char [50] nom; char [80] metier; int num_tel; }; // Ne pas oublier ce point virgule main ( ) {. . . }
7 Atelier de programmation II

Nous avons cr un nouveau type appel struct Personne

Dr. Slim BECHIKH

3) Comment accder aux lments dune structure?


Syntaxe daccs aux lments dune structure
nom_variable.nom_champ
/*Exemple*/ #include <stdio.h> struct Point { double abs; double ord; }; main ( ) { struct Point x; x.abs = 2; x.ord = x.abs + 1; printf ("x = (%.3f, %.3f) \n", x.abs, x.ord); }

Dr. Slim BECHIKH

Atelier de programmation II

4) Loprateur typedef
Nous pouvons nous dbarrasser du mot cl struct en renommant le type via lutilisation de loprateur typedef :
/*Exemple*/ #include <stdio.h> typedef struct Point // typedef nous a permis de crer un synonyme du { double abs; // type struct Point appel T_Point double ord; } T_Point; main ( ) { T_Point x; // Nous avons limin le terme struct x.abs = 2; x.ord = x.abs + 1; printf ("x = (%.3f, %.3f) \n", x.abs, x.ord); }
Dr. Slim BECHIKH 9 Atelier de programmation II

4) Tableau de structures
Ecrire un programme C qui remplie un tableau de 10 lments de type Point de sorte que les points appartiennent la droite dfinie par les points (0, 0) et (1, 1). Par la suite, afficher ce tableau.
#include <stdio.h> for (i = 0; i < 10; i++) typedef struct Point { printf ("P [%d] = (%.3f, %.3f) \n", i, P[i].abs, { double abs; P[i].ord); double ord; } } T_Point; } main ( ) { T_Point P [10]; int i; for (i = 0; i < 10; i++) { P [i].abs = i; P [i].ord = i; }
Dr. Slim BECHIKH 10 Atelier de programmation II

5) Structures et sous-programmes
1) Ecrire un sous-programme Init_Point qui permet dinitialiser un Point par des valeurs passes comme paramtres.

2) Ecrire un sous-programme Affiche_Point qui permet dafficher un point.


3) Ecrire le programme principal main qui permet de: (a) initialiser un point (0,0) au niveau de la dclaration des variables, (b) changer sa position travers le sous-programme init_Point et (c) afficher le point avant et aprs lappel de Init_Point.

Dr. Slim BECHIKH

11

Atelier de programmation II

5) Structures et sous-programmes (suite)


#include <stdio.h> main () typedef struct Point { T_Point p = {0,0}; { int abs; int a, o; int ord; printf ("Saisir les coordonnees du point:\n"); } T_Point; printf ("\nAbscisse = "); scanf("%d", &a); //Procdure Init_Point printf ("\nOrdonne = "); scanf("%d", &o); void Init_Point (T_Point p, int a, int o) //Affichage avant appel de Init_Point { p.abs = a; printf ("\nAffichage avant appel de Nous p.ord = o; avons besoin dun passage parInit_Point:\n"); } Affiche_Point (p); adresse et non pas dun passage par //Procdure Affiche_Point //Affichage aprs appel de Init_Point valeur. void Affiche_Point (T_Point p) Init_Point (p, a, o); { printf ("Ce point se trouve a la position printf ("\nAffichage apres appel de (%d, %d) \n", p.abs, p.ord); Init_Point:\n"); } Affiche_Point (p); printf ("\n\n\n"); }
Dr. Slim BECHIKH 12 Atelier de programmation II

5) Structures et sous-programmes (suite)


#include <stdio.h> main () typedef struct Point { T_Point p = {0,0}; { int abs; int a, o; int ord; printf ("Saisir les coordonnees du point:\n"); } T_Point; printf ("\nAbscisse = "); scanf("%d", &a); //Procdure Init_Point printf ("\nOrdonne = "); scanf("%d", &o); void Init_Point (T_Point* p, int a, int o) //Affichage avant appel de Init_Point { (*p).abs = a; printf ("\nAffichage avant appel de Lorsque (*p).ord = o; le paramtre va recevoir un Init_Point:\n"); } rsultat, nous utilisons un passage Affiche_Point (p); par //Procdure Affiche_Point //Affichage aprs appel de Init_Point adresse. void Affiche_Point (T_Point p) Init_Point (&p, a, o); { printf ("Ce point se trouve a la position printf ("\nAffichage apres appel de (%d, %d) \n", p.abs, p.ord); Init_Point:\n"); } Affiche_Point (p); printf ("\n\n\n"); }
Dr. Slim BECHIKH 13 Atelier de programmation II

6) Evaluation
1) Dfinir un type structur permettant de reprsenter un tudiant comportant son nom, son prnom et sa date de naissance.
#include <stdio.h> typedef struct date { int jour; //entre 1 et 31 char mois[20]; //nom du mois "janvier", "fevrier", etc. int annee; //1999, 2000, etc. } date; typedef struct etudiant { char nom [32]; char prenom [32]; date date_naissance; } etudiant;

Dr. Slim BECHIKH

14

Atelier de programmation II

6) Evaluation (suite)
2) Ecrire une fonction test qui permet de tester si deux tudiants sont identiques ou non.
int test (etudiant a, etudiant b) { int identique =1; if (strcmp (a.nom, b.nom) != 0) {return 0;} if (strcmp (a.prenom, b.prenom) != 0) {return 0;} if (strcmp (a.date_naissance.mois, b. date_naissance.mois) != 0) {return 0;} if (a.date_naissance.jour != b.date_naissance.jour) {return 0;} if (a.date_naissance.annee != b.date_naissance.annee) {return 0;} return identique; }

Dr. Slim BECHIKH

15

Atelier de programmation II

Sance N2:
Pointeurs et allocation dynamique de la mmoire

Dr. Slim BECHIKH

16

Atelier de programmation II

1) Quest ce quun pointeur?

Toute variable manipule dans un programme est stocke quelque part en mmoire centrale. Cette mmoire est constitue d'octets qui sont identifis de manire univoque par un numro qu'on appelle adresse. Pour retrouver une variable, il suffit donc de connatre l'adresse de l'octet o elle est stocke (ou, s'il s'agit d'une variable qui recouvre plusieurs octets contigus, l'adresse du premier de ces octets). Pour des raisons videntes de lisibilit, on dsigne souvent les variables par des identificateurs, et non pas par leurs adresses. C'est le compilateur qui fait alors le lien entre l'identificateur d'une variable et son adresse en mmoire. Toutefois, il est parfois trs pratique de manipuler directement une variable par son adresse. [INRIA 2013]

Dr. Slim BECHIKH

17

Atelier de programmation II

1) Quest ce quun pointeur? (suite)


Dfinition: Un pointeur est une variable qui contient ladresse dune autre variable. Syntaxe de dclaration: type * nom-du-pointeur; Exemples de dclarations: int * p; char * s; float * f; Exemple illustratif:
int * p; // pointeur sur un entier int i = 3; // variable initialise 3 p = &i; // p reoit ladresse de i
p i

Variable i p

Adresse 480600 480604

Valeur 3 480600

480600
480604

3
480600

Dr. Slim BECHIKH

18

Atelier de programmation II

2) Comment accder au contenu dune variable pointe?


L'oprateur unaire d'indirection * permet d'accder directement au contenu de la variable pointe. Ainsi, si p est un pointeur vers une variable entire i, *p dsigne la valeur de i.
#include <stdio.h> main ( ) { int *p; int i = 3; p = &i; printf ("Contenu de i = %d \n", i); printf ("Contenu de p = %x \n", p); printf ("Adresse de i = %x \n", &i); printf ("Adresse de p = %x \n", &p); printf ("Contenu de la variable pointe par p = %d \n\n", *p); }

Affichage en format hexadcimal. Nous pouvons afficher en mode dcimal car les adresses sont des entiers.
Dr. Slim BECHIKH 19 Atelier de programmation II

2) Comment accder au contenu dune variable pointe? (suite)


Conclusion 2: *p == i

Conclusion 1: p == &i

Rcapitulation: 1) *p se lit contenu de la variable pointe par le pointeur p , 2) &i se lit adresse de la variable i .
Dr. Slim BECHIKH 20 Atelier de programmation II

3) Arithmtique des pointeurs?


La valeur d'un pointeur tant un entier, on peut lui appliquer un certain nombre d'oprateurs arithmtiques classiques. Les seules oprations arithmtiques valides sur les pointeurs sont: 1) l'addition d'un entier un pointeur. Le rsultat est un pointeur de mme type que le pointeur de dpart; 2) la soustraction d'un entier un pointeur. Le rsultat est un pointeur de mme type que le pointeur de dpart; 3) la diffrence de deux pointeurs pointant tous deux vers des objets de mme type. Le rsultat est un entier.
NB1: Notons que la somme de deux pointeurs n'est pas autorise. NB2: Les oprateurs de comparaison sont galement applicables aux pointeurs condition de comparer des pointeurs qui pointent vers des objets de mme type.
Dr. Slim BECHIKH 21 Atelier de programmation II

3) Arithmtique des pointeurs? (suite)


L'utilisation des oprations arithmtiques sur les pointeurs est particulirement utile pour parcourir des tableaux. Ainsi, le programme suivant imprime les lments du tableau tab dans l'ordre croissant puis dcroissant des indices.
#include <stdio.h> #define N 5 main ( ) { int tab [5] = {1, 2, 6, 9, 18}; int *p; printf("\nOrdre croissant:\n"); for (p = &tab[0]; p <= &tab[N-1]; p++) { printf (" %d \n",*p); } printf ("\nOrdre decroissant:\n"); for (p = &tab[N-1]; p >= &tab[0]; p--) { printf (" %d \n",*p); } }
Dr. Slim BECHIKH 22 Atelier de programmation II

4) Allocation dynamique de la mmoire?


Avant de manipuler un pointeur, et notamment de lui appliquer l'oprateur d'indirection *, il faut l'initialiser. Sinon, par dfaut, la valeur du pointeur est gale une constante symbolique note NULL dfinie dans <stdio.h>. En gnral, cette constante vaut 0. Le test (p == NULL) permet de savoir si le pointeur p pointe vers un objet.
On peut initialiser un pointeur p par une affectation sur p. Par exemple, on peut affecter p l'adresse d'une autre variable. Il est galement possible d'affecter directement une valeur *p. Mais pour cela, il faut d'abord rserver *p un espace-mmoire de taille adquate. L'adresse de cet espace-mmoire sera la valeur de p. Cette opration consistant rserver un espace-mmoire pour stocker l'objet point s'appelle allocation dynamique. Elle se fait en C par la fonction malloc de la librairie standard <stdlib.h>. Sa syntaxe est:

malloc (nombre-octets)

Dr. Slim BECHIKH

23

Atelier de programmation II

4) Allocation dynamique de la mmoire? (suite)

La fonction malloc retourne un pointeur de type char * pointant vers un objet de taille nombre_octets octets. Pour initialiser des pointeurs vers des objets qui ne sont pas de type char, il faut convertir le type de la sortie de la fonction malloc l'aide d'un cast. L'argument nombre-octets est souvent donn l'aide de la fonction sizeof//Exemple ( ) qui renvoie le nombre d'octets utiliss pour stocker un objet. Ainsi, pour initialiser un pointeur vers un entier, on crit : #include <stdio.h> #include <stdlib.h> #include <stdlib.h> Main ( ) main() { int *p; { int i = 3; p = (int*) malloc (sizeof (int)); int *p; *p = 25; p = (int*) malloc (sizeof (int)); } *p = i; printf ("*p = %d\n",*p); }

Dr. Slim BECHIKH

24

Atelier de programmation II

4) Allocation dynamique de la mmoire? (suite)

Enfin, lorsque l'on n'a plus besoin de l'espace-mmoire allou dynamiquement (c'est--dire quand on n'utilise plus le pointeur p), il faut librer cette place en mmoire. Ceci se fait l'aide de l'instruction free qui a pour syntaxe:

free (nom-du-pointeur);

Dr. Slim BECHIKH

25

Atelier de programmation II

5) Pointeurs et tableaux?
L'usage des pointeurs en C est, en grande partie, orient vers la manipulation des tableaux. Tout tableau en C est en fait un pointeur constant. Dans la dclaration int tab[10]; tab est un pointeur constant (non modifiable) dont la valeur est l'adresse du premier lment du tableau. Autrement dit, tab a pour valeur &tab[0]. On peut donc utiliser un pointeur initialis tab pour parcourir les lments du tableau. On accde l'lment d'indice i du tableau tab grce l'oprateur d'indexation [ ], par l'expression tab[i]. Cet oprateur d'indexation peut en fait s'appliquer tout objet p de type pointeur. Il est li l'oprateur d'indirection * par la formule: tab[i] = *(p + i)

Dr. Slim BECHIKH

26

Atelier de programmation II

5) Pointeurs et tableaux? (suite)


//Exemple #include <stdio.h> #define N 5 main() { int i; int *p; int tab[5] = {1, 2, 6, 0, 7}; p = tab; // p = &tab [0]; for (i = 0; i < N; i++) printf ("%d \n", *(p+i)); // *(p+i) est quivalent tab[i] eq. *(tab+i) }

Dr. Slim BECHIKH

27

Atelier de programmation II

6) Pointeurs et chane de caractres?


Exercice: que fait le programme suivant?
#include <stdio.h> main() { int i; char *chaine; chaine = "chaine de caracteres"; for (i = 0; *chaine != '\0'; i++) chaine++; printf ("Rsultat = %d\n",i); }

Puisquune chaine de caractres est un tableau de caractres, elle peut tre manipule en utilisant la notion de pointeur.

Dr. Slim BECHIKH

28

Atelier de programmation II

Sance N3:
Listes simplement chanes (Partie 1)

Dr. Slim BECHIKH

29

Atelier de programmation II

1) Quest ce quune liste chane?


Nous avons jusqu prsent utilis les tableaux pour stocker un ensemble de donnes de mme type dune faon linaire. Plusieurs inconvnients se prsentent pour lutilisation des tableaux: 1) La capacit de stockage dun tableau est fixe ce qui engendre des problmes quand le nombre de donnes stocker est dynamique; 2) Les cases dun tableau sont contiges ce qui engendre un manque defficacit au niveau de la rservation de lespace mmoire ncessaire; 3) Lajout et la suppression dun lment dans un tableau ncessitent des oprations de dcalage de cases souvent coteuses.

Prvoir une structure de donnes qui vite ce type dinconvnients: liste chane !
Dr. Slim BECHIKH 30 Atelier de programmation II

1) Quest ce quune liste chane? (suite)


Dfinition: Une liste chane est un ensemble de nuds relis les uns aux autres. Chaque nud contient un champ de donnes et un champs indiquant un lien vers le nud suivant.

Tte: lien vers le premier nud

Donne

Lien vers le nud suivant

Donne

Lien vers le nud suivant

Donne

Lien vers le nud suivant

NULL

Dr. Slim BECHIKH

31

Atelier de programmation II

1) Quest ce quune liste chane? (suite)


Exemple: une liste dentiers: 259 => 321 => 98

Tte

2ffx00

259

2ffx04

321

2ffx08

98

NULL

2ffx00

2ffx04

2ffx08 NULL

1) Une liste chane est accessible par sa tte. La tte est un pointeur qui contient ladresse du premier nud de la liste. 2) Le dernier nud de la liste pointe sur NULL.
Dr. Slim BECHIKH 32 Atelier de programmation II

2) Quelles sont les oprations possibles sur une liste chane?


Insrer un nud Au dbut A la fin Au milieu Supprimer un nud Au dbut A la fin Au milieu Afficher la liste Dtruite la liste Inverser la liste Etc.
Dr. Slim BECHIKH 33 Atelier de programmation II

3) Implmentation dune liste simplement chane en C?


Dfinition de la structure Nud

val

suiv

#include <stdio.h> #include <stdlib.h> /*La structure Noeud contient une partie information (exemple: entier) et une partie pointeur vers le noeud suivant*/ typedef struct Noeud { int val; // Donne struct Noeud * suiv; // Pointeur vers le nud suivant } Noeud;

Dr. Slim BECHIKH

34

Atelier de programmation II

3) Implmentation dune liste simplement chane en C? (suite)


Dclaration de la tte de la liste comme variable globale tout le fichier C /*Dclarer la tte de la liste puisque une liste est accessible par sa tte: il s'agit d'une variable globale tout le fichier*/ Nud * tete;

Tte NULL

Si la tte pointe sur NULL, on dit que la liste est vide.

Dr. Slim BECHIKH

35

Atelier de programmation II

3) Implmentation dune liste simplement chane en C? (suite)


Insertion dun nud au dbut de la liste (juste avant la tte)
void inserer_debut (int info) { Noeud * nouveau; nouveau = (Noeud*) malloc (sizeof(Noeud*)); (*nouveau).val = info; if (tete == NULL) // la liste est vide { tete = nouveau; (*tete).suiv = NULL; } else // la liste nest pas vide { (*nouveau).suiv = tete; tete = nouveau; } }

Nouveau

info
tete Nouveau

suiv

info
tete Nouveau

NULL

tete

info suiv

info suiv

Dr. Slim BECHIKH

36

Atelier de programmation II

3) Implmentation dune liste simplement chane en C? (suite)


Insertion dun nud la fin de la liste (aprs le dernier nud)
void inserer_fin (int info) { Noeud * nouveau; // nouveau nud insrer Noeud * courant; // nud courant nouveau = (Noeud *) malloc (sizeof (Noeud)); (*nouveau).val = info; if (tete == NULL) // Si la liste est vide, nous crons un premier nud { tete = nouveau; (*tete).suiv = NULL; } else // Si la liste nest pas vide { // Parcourir la liste jusqu'au dernier nud courant = tete; // Initialiser le courant la tte de la liste while ((*courant).suiv != NULL) { courant = (*courant).suiv; } // Lier le nouveau noeud la fin de la liste (*courant).suiv = nouveau; (*nouveau).suiv = NULL; } }
Dr. Slim BECHIKH 37 Atelier de programmation II

3) Implmentation dune liste simplement chane en C? (suite)


Insertion dun nud la fin de la liste (aprs le dernier nud)

Question: Comment schmatiser les diffrents cas en se basant sur le code C du sous-programme inserer_fin ?

Dr. Slim BECHIKH

38

Atelier de programmation II

3) Implmentation dune liste simplement chane en C? (suite)


Calcul de la longueur de la liste

Question: Ecrire le code C relatif la fonction int longueur ( ) ?

Dr. Slim BECHIKH

39

Atelier de programmation II

3) Implmentation dune liste simplement chane en C? (suite)


Calcul de la longueur de la liste
int longueur() { Noeud * courant; int compteur = 0; courant = tete; while (courant != NULL) { courant = (*courant).suiv; compteur++; } return compteur; }

Dr. Slim BECHIKH

40

Atelier de programmation II

3) Implmentation dune liste simplement chane en C? (suite)


Insertion une position donne
void inserer_position (int info, int pos) { int i; Noeud *nouveau, *precedent, *courant; courant = tete; if ((pos > (longueur()+1)) || (pos <= 0)) { printf("\nLa position est invalide\n"); } else { // Si pos == 1 if (pos == 1) { inserer_debut (info); } else { //Si pos >= 1 for (i=1; i<pos; i++) { precedent = courant; courant = (*courant).suiv; } // Allocation du noeud insrer
nouveau = (Noeud*) malloc (sizeof (Noeud));

(*nouveau).val = info; // Raliser l'insertion (*precedent).suiv = nouveau; (*nouveau).suiv = courant; } // end du 2me if } // end du 1er if } // end du sous-programme
41 Atelier de programmation II

Dr. Slim BECHIKH

3) Implmentation dune liste simplement chane en C? (suite)


Insertion une position donne

Question: Comment schmatiser les diffrents cas en se basant sur le code C du sous-programme inserer_position ?

Dr. Slim BECHIKH

42

Atelier de programmation II

3) Implmentation dune liste simplement chane en C? (suite)


Affichage dune liste

Question: Ecrire le code C relatif la procdure void afficher ( ) ?

Dr. Slim BECHIKH

43

Atelier de programmation II

3) Implmentation dune liste simplement chane en C? (suite)


Affichage dune liste
void afficher() { Noeud * courant; courant = tete; if(courant == NULL) { printf ("\nLa liste est vide\n"); } else { printf ("\nContenu de la liste: "); // Parcourir toute la liste while(courant != NULL) { printf(" -> %d ", (*courant).val); courant = (*courant).suiv; } printf ("\n"); } }
Dr. Slim BECHIKH 44 Atelier de programmation II

Sance N4:
Listes simplement chanes (Partie 2)

Dr. Slim BECHIKH

45

Atelier de programmation II