ASD2 OlfaHamrouni
ASD2 OlfaHamrouni
ASD2 OlfaHamrouni
I. INTRODUCTION
Une chaîne de caractères est considérée comme un tableau de caractères. Elle est
délimitée par 2 guillemets. Une chaîne vide est représentée par 2 guillemets accolés.
La déclaration d'une chaîne de caractères se fait suivant la syntaxe suivante:
<Nom_Variable_Chaine>: chaine [longueur]
1 sur 64
Par: mme Olfa HAMROUNI JEMLI
"Bonjour"
2 sur 64
Par: mme Olfa HAMROUNI JEMLI
3 sur 64
Par: mme Olfa HAMROUNI JEMLI
III. APPLICATION
Écrire un algorithme qui:
- lit une chaîne de caractère dont la longueur ne dépasse pas 50 caractères
- calcule et affiche le nombre de caractères alphanumériques, de lettres, de chiffres, de
caractères majuscules, de caractères minuscules et d'espaces.
4 sur 64
Par: mme Olfa HAMROUNI JEMLI
1. DEFINITION
Une structure ou encore un enregistrement ets classé parmi les types avancés. Il
contient un ou plusieurs champs groupés sous le même nom pour être traités comme
une seule entité. Ces champs sont hétérogènes dans la mesure où leurs types sont
différents.
Les champs d'une structure sont appelés membres et ils peuvent avoir l'un des types
déjà définis y compris les tableaux et les structures.
2. STRUCTURES SIMPLES
1. DEFINITION
On définit le type structure comme suit:
<Nom_Structure>: structure
Membre 1: type
…
Membre n: type
Fin structure
Exemples:
Définition de la structure Etudiant: Définition de la structure Date
Etudiant: structure Date: structure
Nom: chaine (50) Jour: entier
Prenom: chaine (25) Mois: entier
Adresse: chaine (50) Annee: entier
DateNaiss: chaine (10) Fin structure
Fin structure
5 sur 64
Par: mme Olfa HAMROUNI JEMLI
6 sur 64
Par: mme Olfa HAMROUNI JEMLI
La variable P
prod1 Le champ code
Chaise
Le champ Désignation
15
Le champ Prix
3. STRUCTURES COMPOSEES
Revenons à l'exemple de la structure Etudiant et supposons que l'adresse n'est pas une
chaîne de caractères mais elle est une structure qui est définie comme suit:
Adr: structure
Rue: entier
Cite chaine (20)
Gouvernorat: chaine (50)
CodePostal: entier
Pays: chaine (50)
Fin structure
Supposons de même qu'on recourt à la structure Date déjà défini pour définir le champ
DateNaiss. La structure Etudiant serait alors définie comme suit:
Etudiant: structure
Nom: chaine (50)
Prenom: chaine (25)
Adresse: Adr
DateNaiss: Date
Fin structure
Exercice:
Ecrire un algorithme permettant de créer une variable de type Etudiant et de l'affecter les
informations suivantes: (Bensaleh, Karim, (5, rue abdellah ibn raweha, kairouan, 3199,
Tunisie), (12,12,1977))
ALGORITHME Essai2
DEBUT
Adr: structure
Rue: entier
Cite chaine (20)
Gouvernorat: chaine (50)
CodePostal: entier
Pays: chaine (50)
7 sur 64
Par: mme Olfa HAMROUNI JEMLI
Fin structure
Date: strucure
Jour: entier
Mois: entier
Annee: entier
Fin structure
Etudiant: structure
Nom: chaine (50)
Prenom: chaine (25)
Adresse: Adr
DateNaiss: Date
Fin structure
E: Etudiant
Copier_Chaine (e.Nom, "Bensaleh")
Copier_Chaine (e.Prenom, "Karim")
e.adresse.Rue5
Copier_Chaine (e.adresse.Cite, " rue abdellah ibn raweha")
Copier_Chaine (e.adresse.Gouvernorat, " Kairouan")
e.adresse.CodePotal 3199
Copier_Chaine (e.adresse.Pays, " Tunisie")
e.DateNaiss.jour 12
e.DateNaiss.mois 12
e.DateNaisse.annee 1977
Fin
Dans la mémoire centrale, la variable e de structure Etudiant sera représentée comme
suit:
8 sur 64
Par: mme Olfa HAMROUNI JEMLI
La variable e
e.Nom
BenSaleh
e.Prenom
Karim
e.adresse.Rue
5
e.adresse.Cite
Rue abdellah ibn raweha
Kairouan e.adresse.Gouvernorat
3199
e.adresse.CodePostal
Tunisie
e.adresse.Pays
12
e.DateNaiss.jour
12
e.DateNaiss.mois
1977
e.DateNaiss.annee
4. TABLEAUX DE STRUCTURES
La syntaxe de définition d'un tableau de structures est la suivante:
<Nom_Tableau>: tableau [1..<Nombre_Elements>] de <Nom_structure>
Exemple
Définir un tableau de 5 étudiants en se référant à la structure Etudiant déjà définie.
SOLUTION
ListeEtudiants: tableau [1..5] de Etudiant
La représentation, dans la mémoire centrale, de ce tableau est:
1 2 3 4 5
Nom Nom Nom Nom Nom
Prenom Prenom Prenom Prenom Prenom
Adresse Adresse Adresse Adresse Adresse
Rue Rue Rue Rue Rue
Cite Cite Cite Cite Cite
Gouvernorat Gouvernorat Gouvernorat Gouvernorat Gouvernorat
CodePostal CodePostal CodePostal CodePostal CodePostal
Pays Pays Pays Pays Pays
DateNaiss DateNaiss DateNaiss DateNaiss DateNaiss
Jour Jour Jour Jour Jour
Mois Mois Mois Mois Mois
Annee Annee Annee Annee Annee
9 sur 64
Par: mme Olfa HAMROUNI JEMLI
5. APPLICATION
Soit un tableau de structure produit. Le nombre de produits maximum est 100. Un
produit est défini par sa référence, son libellé, sa couleur, son prix et sa quantité en
stock.
Écrire un algorithme qui permet de:
- demander de l'utilisateur de lire un nombre n<=100
- remplir le tableau avec n produits dont les caractéristiques sont entrées par
l'utilisateur.
- Calculer et afficher la quantité moyenne stockée
- Calculer et afficher la référence du produit qui a le plus grand prix
10 sur 64
Par: mme Olfa HAMROUNI JEMLI
Chapitre 9: LA RECURSIVITE
Objectif du chapitre: Savoir écrire des versions récursives de sous-programmes.
Plan du chapitre:
I. Introduction
II. Exemples
a. Exemple 1: la factorielle d'un entier
b. Exemple 2: le PGCD de deux entiers
1. Introduction
On appelle un sous-programme récursif un sous-programme qui s'appelle, soit lui-même,
soit par l'intermédiaire d'un autre sous-programme. La récursivité est un domaine très
intéressant de l'informatique, un peu abstrait, mais très élégant; elle permet de résoudre
certains problèmes d'une manière très rapide, alors que si on devait les résoudre de
manière itérative, il nous faudrait beaucoup plus de temps et de structures de données
intermédiaires.
La récursivité utilise toujours la pile du programme en cours. On appelle "pile" une zone
mémoire réservée à chaque programme. Son rôle est de stocker les variables locales et
les paramètres d'un sous-programme.
Supposons que nous sommes dans une procédure "proc1" dans laquelle nous avons des
variables locales. Ensuite nous faisons appel à une procédure "proc2"; comme le
microprocesseur va commencer à exécuter "proc2" mais qu'ensuite il reviendra continuer
l'exécution de "proc1", il faut bien stocker quelque part les variables de la procédure en
cours "proc1"; c'est le rôle de la pile. Tout ceci est géré de façon transparente pour
l'utilisateur.
Dans un sous-programme récursif, toutes les variables locales sont stockées dans la pile,
et empilées autant de fois qu'il y a d'appels récursifs. Donc la pile se remplit
progressivement, et si on ne fait pas attention on arrive à un "débordement de pile".
Ensuite, les variables sont désempilées.
11 sur 64
Par: mme Olfa HAMROUNI JEMLI
Procédure recursive(paramètres);
// Déclaration des variables locales
Début
si (TEST_D'ARRET) alors
Instructions du point d'arrêt
sinon //----- exécution
instructions;
recursive(paramètres changés); // appel récursif
instructions;
fin si
Fin
2. Exemples
a. Exemple 1: la factorielle d'un entier
L'exemple de fonction récursive le plus utilisé est fourni par la fonction mathématique
factorielle qui peut se définir ainsi:
F(0)=1
F(1)=1
F(n)=n * F(n - 1) pour n>1
La 3ème ligne comporte à son tour une référence à la fonction, d'où la récursivité. Cette
récursivité permet d'aboutir à un résultat si on l'applique après un nombre fini de fois.
La version récursive de la fonction F en écriture algorithmique est:
FONCTION F (n: entier):entier
DEBUT
Si ((n=0) ou (n=1)) Alors
Retourner (1)
Sinon
Retourner (n * F (n - 1))
Fin Si
FIN
On suppose écrire l'algorithme principal suivant:
Algorithme Test
var x:entier
Début
x=F(5)
Fin
Essayons de faire une exécution à la main:
12 sur 64
F(4)
Paramètre: n=4 Retourner 6
Retourner: 4*F(3)
Par: mme Olfa HAMROUNI JEMLI
F(3)
Paramètre: n=3 Retourner 2
Retourner Retourner: 3*F(2)
120 F(5)
Et la valeur Paramètre:n=5 Retourner 24
de x dans F(2)
Retourner:5*F(4)
l'algorithme Paramètre: n=2 Retourner 1
est: 120 Retourner: 2*F(1)
F(1)
Paramètre: n=1
Retourner: 1
13 sur 64
Par: mme Olfa HAMROUNI JEMLI
Début
x=PGCD(12,7)
Fin
Essayons de faire une exécution à la main:
Retourner PGCD(12,7)
1
Et la valeur Paramètres: m=12, n=7
de x dans Retourner PGCD(7,5) Retourner 1
l'algorithme
est: 1 PGCD(7,5)
Paramètres: m=7, n=5
Retourner PGCD(5,2) Retourner 1
PGCD(5,2)
Paramètres: m=5, n=2
Retourner PGCD(2,1) Retourner 1
PGCD(2,1)
Paramètres: m=2, n=1
Retourner PGCD(1,0) Retourner 1
PGCD(1,0)
Paramètres: m=1, n=10
Retourner 1
14 sur 64
Par: mme Olfa HAMROUNI JEMLI
1. Introduction
Le traitement des données exige leur présence en mémoire pendant l'exécution du
programme concerné. Mais, la plupart du temps, il faut également que ces données
soient conservées de manière durable. Comme exemple, on peut citer les données
relatives aux clients d'une entreprise. De telles données (code client, nom client et
adresse client) sont le plus souvent exploitées sur une longue période. Elles doivent
pouvoir être rappelées à tout moment et, en particulier, mises à jour au moment voulu.
Pour atteindre l'objectif escompté, ces données seront écrites dans un fichier qui sera
stocké sur une mémoire de masse et accessible au programme manipulant ces données.
2. Définition
Un fichier est appelé en anglais file. Il s'agit d'un ensemble structuré de données
stockées en général sur un support de masse (disquette, disque dur, disque optique,
etc.). On manipule plusieurs types de fichiers:fichier texte, fichier d'enregistrements, etc.
On distingue généralement deux types d'accès:
- Accès séquentiel
Il consiste à accéder aux informations de manière séquentielle, càd suivant l'ordre où
elles apparaissent dans le fichier. Un fichier à accès séquentiel présente les
caractéristiques suivantes:
Pas de cellule vide
On accède à une cellule quelconque en se déplaçant depuis la cellule de départ
L'ajout d'une cellule se fait à la fin de fichier
- Accès direct
Il consiste à accéder à n'importe quel enregistrement repéré par son numéro d'ordre.
Un fichier à accès direct a les caractéristiques suivantes:
Cellule vide possible
On peut directement accéder à une cellule
On peut modifier voir détruire n'importe quelle cellule
15 sur 64
Par: mme Olfa HAMROUNI JEMLI
Exemple:
Écrire un algorithme qui permet d'ouvrir un fichier séquentiel nommé xyz.dat pour
lecture. Le fichier existe sous c: dans un répertoire nommé Travaux. L'algorithme permet
de tester si le fichier est ouvert ou non.
16 sur 64
Par: mme Olfa HAMROUNI JEMLI
Algorithme Exp1
Début
Fich:FICHIER
Fich=ouvrir ("c:\Travaux\xyz.dat", "r", "séquentiel");
Si (Fich=NULL) écrire ("Fichier non ouvert")
Sinon écrire ("Fichier ouvert")
Fin si
Fin
Exemple:
Algorithme Exp2
Début
Fich:FICHIER
Fich=ouvrir ("c:\Travaux\xyz.dat", "r", "séquentiel")
Si (Fich=NULL) écrire ("Fichier non ouvert")
Sinon
écrire ("Fichier ouvert")
fermer (Fich)
Fin si
Fin
17 sur 64
Par: mme Olfa HAMROUNI JEMLI
La fonction fermerTous permet de fermer tous les fichiers ouverts dans un programme.
Le prototype de la fonction est:
fermerTous()
La fonction retourne une valeur qui présente le nombre de fichiers fermés.
18 sur 64
Par: mme Olfa HAMROUNI JEMLI
lues à partir du clavier. Sachant qu'un étudiant est défini par: un numéro de carte et un
téléphone.
Solution:
Etudiant=enreg
int nce;
int tel;
Fin enreg
#include <stdio.h>
typedef struct
{
int nce;
int tel;
}Etudiant;
FILE* Remplir()
{
FILE* f;
19 sur 64
Par: mme Olfa HAMROUNI JEMLI
Etudiant Etud;
int i;
f=fopen("D:/TEST_C/xyz.dat","a");
if (f==NULL)
{
printf("Fichier non ouvert");
}
else
{
for(i=1;i<=2;i++)
{
printf("Donner le nce du %d eme etudiant:",i);
scanf("%d",&Etud.nce);
printf("\nDonner le tel du %d eme etudiant:",i);
scanf("%d",&Etud.tel);
fwrite(&Etud, sizeof(Etud),1,f);
}
}
fclose(f);
return (f);
}
void main()
{
FILE * Fich;
Fich=Remplir();
}
Exemple: Soit le fichier xyz.dat déjà vu dans l'exemple précédent et rempli par 5
étudiant, écrire une fonction nommée Affichage qui affiche le contenu du fichier xyz.dat.
Solution:
Fonction Affichage(f:FICHIER)
20 sur 64
Par: mme Olfa HAMROUNI JEMLI
Début
i:entier
E:Etudiant
f=ouvrir("D:/TEST_C/xyz.dat","r")
Si (f=NULL)
écrire ("Fichier non ouvert")
Sinon
Tant que (non finFichier(f)) faire
fLire(E,sizeof(E),1,f)
écrire("ETUDIANT", i)
écrire("NCE:",E.nce)
printf("TEL:", E.tel)
Fin tant que
Fin si
Fermer(f)
Fin
void Affichage(FILE* f)
{
int i;
Etudiant E;
f=fopen("D:/TEST_C/xyz.dat","r");
if (f==NULL)
{
printf("Fichier non ouvert");
}
else
{
While(!feof(f))
{
fread(&E,sizeof(E),1,f);
printf("ETUDIANT %d\n",i);
printf("NCE:%d\n",E.nce);
printf("TEL:%d\n", E.tel);
}
}
fclose(f);
21 sur 64
Par: mme Olfa HAMROUNI JEMLI
22 sur 64
Par: mme Olfa HAMROUNI JEMLI
si (F=NULL)
écrire ("Fichier non ouvert")
sinon
fRechercher (F, 2 * sizeof(Etudiant), 0);
fLire( &E, sizeof(Etudiant), 1, F);
écrire ("Le bloc numéro 3 est l'étudiant dont le nce est E.nce et le tel est: E.tel")
fseek (F, 0,0);
fLire( &E, sizeof(Etudiant), 1, F);
écrire ("Le bloc numéro 1 est l'étudiant dont le nce est E.nce et le tel est: E.tel")
fin si
fermer(F)
Fin
#include <stdio.h>
typedef struct
{
int nce;
int tel;
}Etudiant;
void main()
{
FILE * F; Etudiant E;
F=fopen("D:/TEST_C/xyz.dat", "r");
if (F==NULL)
{ printf("Fichier non ouvert"); }
else
{
fseek (F, 2 * sizeof(Etudiant), 0);
fread( &E, sizeof(Etudiant), 1, F);
printf("Le bloc numéro 3 est l'etudiant dont le nce est %d et le tel est: %d\n\n",
E.nce,E.tel);
fseek (F, 0,0);
fread( &E, sizeof(Etudiant), 1, F);
printf("Le bloc numéro 1 est l'etudiant dont le nce est %d et le tel est: %d",
E.nce,E.tel);
}
Fclose(f);
}
23 sur 64
Par: mme Olfa HAMROUNI JEMLI
Exemple:
fDebut(F)
rewind (F);
Remarque: l'expression rewind (F) est équivalente à: fseek(F, 0, 0);
24 sur 64
Par: mme Olfa HAMROUNI JEMLI
1. Définition
Un pointeur est une donnée constante ou variable qui mémorise l'adresse d'une variable.
On dit que le pointeur fait référence à la variable. Il s'agit d'un type de donnée dont les
valeurs sont les adresses des objets de différents types de donnée. Ces valeurs sont
l'ensemble des adresses de la mémoire centrale auquel on ajoute une adresse nulle.
2. Déclaration de pointeurs
La syntaxe générale de déclaration d'un pointeur en langage C est:
<Type> * <Nom_Pointeur>;
Exemple:
int * ptre;
ptre est un pointeur sur un entier. La variable ptre contiendra l'adresse ou la
référence d'une variable de type entier.
char * ch;
ch est une chaîne de caractères. La variable ch contiendra l'adresse ou la
référence du premier caractère d'une variable de type chaîne de caractères.
3. Gestion de pointeurs
3.1. Initialisation d'un pointeur
Si on suppose les déclarations suivantes et on se base sur les déclarations précédentes:
int x;
char chaine[]="Hello";
ptre=&x;
ch=&chaine;
On déduit que ptre pointe vers la variable x. En outre, on déduit que ch fait référence à
la variable chaine.
25 sur 64
Par: mme Olfa HAMROUNI JEMLI
26 sur 64
Par: mme Olfa HAMROUNI JEMLI
Programmes système
Programmes système
27 sur 64
Par: mme Olfa HAMROUNI JEMLI
#include <stdio.h>
main()
{
char * ch="Bonjour";
ch=ch+5;
printf ("%c", *ch);//Affichage du caractère u
ch=ch-2;
printf ("%c", *ch);//Affichage du caractère j
}
Incrémentation
#include <stdio.h>
main()
{
char * ch="Bonjour";
printf ("%c", *ch);//Affichage du caractère B
ch=ch++;
printf ("%c", *ch);//Affichage du caractère o
}
Décrémentation
#include <stdio.h>
main()
{
char * ch="Bonjour";
printf ("%c", *ch);//Affichage du caractère B
ch=ch+3;
printf ("%c", *ch);//Affichage du caractère j
ch=ch--;
printf ("%c", *ch);//Affichage du caractère n
}
Comparaison
La comparaison de 2 pointeurs ne renseigne l'égalité que si les deux pointeurs pointent
vers la même variable.
Exemple:
int x=10 ; int y = 10; int z = 20;
int * px = &x; int * py=&y; int * pz=&z;
px != py
px != pz
py != pz
28 sur 64
Par: mme Olfa HAMROUNI JEMLI
5. Gestion dynamique
La déclaration d'un pointeur devrait être suivie d'une réservation d'espace mémoire. Au
cours des chapitres précédents, les déclarations des variables étaient d'une manière
statique. Ceci peut causer une saturation de la mémoire centrale et un plantage des
programmes qui manipulent beaucoup de variables. En effet, avec cette réservation
statique, le programmeur ne peut pas gérer l'espace mémoire (allouer et libérer de
l'espace mémoire au cas de besoin) d'où la nécessité d'une gestion dynamique.
Voici un exemple montrant le besoin d'une allocation et mettant en relief les avantages
des pointeurs par rapport aux tableaux.
A la rentrée universitaire de l’année 2003/2004, on dispose de 4000 étudiants. Dans le
service scolarité, les étudiants sont enregistrés dans un tableau pour être gérés plus
tard. Durant le semestre, les problèmes suivants sont rencontrés :
- 3 nouveaux étudiants se sont orientés vers notre institution. Que faire et notre tableau
est plein et ne contient plus d’espace libre?
- 10 étudiants sont partis pour une autre institution donc ils ne devront plus figurer dans
le tableau => ils devront être supprimés du tableau et ceci va causer des trous qui ne
peuvent plus être exploités.
Avec ces deux cas de figure, il est clair que la gestion statique cause des problèmes
pourrant être remédiés par la gestion dynamique. Cette dernière assure l’allocation
d’espace mémoire et la libération d’espace mémoire au cas de besoin.
En langage C, les fonctions qui permettent d’allouer dynamiquement de l’espace mémoire
sont :
- malloc ( Memory ALLOCation)
- calloc (Contiguous ALLOCation)
- realloc (REALLOCation)
29 sur 64
Par: mme Olfa HAMROUNI JEMLI
a. Fonction malloc
La fonction malloc alloue dynamiquement un emplacement formé d’un nombre d’octets
consécutifs. Pour cela, on transmet comme paramètre de fonction, un nombre entier
exprimant la dimension du bloc mémoire que l’on désire réserver. La fonction malloc
retourne au programme un pointeur vers l’adresse du début de ce bloc si l’opération est
réussie et le pointeur NULL sinon.
Le résultat fourni par malloc est un pointeur générique qui peut être converti en un
pointeur de type quelconque.
La syntaxe de la fonction malloc est :
Void * malloc (taille en octets) ;
Exemple 1 :
Allouer dynamiquement de l’espace mémoire pour 20 entiers
Ptre= malloc (20 * sizeof (int)) ;
Ptre est l’adresse du bloc mémoire alloué pour les 20 entiers en cas de réussite
d’opération.
Ptre est la valeur NULL en cas d’échec d’opération s’il y a insuffisance d’espace mémoire.
Exemple 2
Ecrire un programme qui déclare une suite de 7 entiers et l’initialise par des 0
#include <stdlib.h>
main()
{
int * ptre ; int i;
ptre=malloc(7 * sizeof (int));
for (i=1;i<=7;i++)
{
*ptre=0;
ptre++;
}
}
Le bloc mémoire alloué par ce programme peut être représenté comme suit :
30 sur 64
Par: mme Olfa HAMROUNI JEMLI
ptre
0 0 0 0 0 0
0
b. Fonction calloc
Elle réserve un bloc mémoire dont la taille est réservée d’avance et retourne au
programme, en cas de succès de l’opération, l’adresse du début de ce bloc et le pointeur
NULL en cas d’échec. A la différence de malloc, calloc admet deux paramètres. La
syntaxe générale est :
Void * calloc (nombre, taille en octets) ;
Les deux fonctions malloc et calloc se différencient non seulement par le nombre de
paramètres mais également par le contenu du bloc réservé.
Avec une allocation faite par malloc, tous les octets du bloc alloué contiennent des
valeurs aléatoires. En revanche, calloc initialise chaque octet du bloc par la valeur 0.
Exemple 1 0
#include <stdlib.h> 0
#include <stdio.h> 0
0
main()
0
{ 0
int * ptre ; int i; 0
ptre=calloc(7 , sizeof (int));
for (i=1;i<=7;i++)
{ printf (“%d\n”, *ptre); ptre++ ; }
}
b. Fonction free
Elle assure la libération d’espace mémoire dont l’adresse de début est fournie en
paramètre. La syntaxe générale est :
void free (void * adr) ;
Exemple 1
#include <stdlib.h>
#include <stdio.h>
main()
{ int * ptre ; int i; int * p;
ptre=calloc(7 * sizeof (int));
31 sur 64
Par: mme Olfa HAMROUNI JEMLI
p=ptre;
for (i=1;i<=7;i++)
{ printf (“%d\n”, *ptre); ptre++ ; }
free (p) ;
}
c. Fonction realloc
Par sa nature, la fonction free libère toujours un emplacement dans sa totalité. La
fonction realloc peut pallier ce défaut. Elle permet de libérer une partie d’une zone
préalablement allouée. En outre, elle permet d’accroître un emplacement donné tout en
conservant son contenu.
La syntaxe générale est :
Void * realloc (void * adr, taille en octets) ;
Deux cas seront rencontrés : le cas de réduction de la taille et le cas d’augmentation de
la taille d’un emplacement.
6. pointeurs et structures
Supposons déclarée une structure telle que :
Struct article
{
32 sur 64
Par: mme Olfa HAMROUNI JEMLI
33 sur 64
Par: mme Olfa HAMROUNI JEMLI
{
char Code [5];
char Libelle [20] ;
float Prix ;
};
struct article * Pa ;
Pa = malloc (sizeof (struct article));
Strcpy (Pa code, "P1");
Strcpy (Pa libelle, "Chaise");
Pa prix = 15.25;
}
Exemple 2
En se basant sur les mêmes déclarations, afficher le contenu de la variable pointée par
Pa.
Solution
#include <stdlib.h>
#include <stdio.h>
main()
{
Struct article
{
char Code [5];
char Libelle [20] ;
float Prix ;
};
struct article * Pa ;
Pa = malloc (sizeof (struct article));
Strcpy (Pa code, "P1");
Strcpy (Pa libelle, "Chaise");
Pa prix = 15.25;
Printf ("Le code est:%s, le libellé est:%s et le prix est:%f", Pa code, Pa libelle, Pa
prix);
}
b. Application
Etant donné qu'une personne est définie par un NCIN, un nom, un prénom, un âge et
une adresse, écrire un programme qui permet de définir une suite de 20 personnes, de la
34 sur 64
Par: mme Olfa HAMROUNI JEMLI
remplir par des données entrées à partir du clavier et enfin de chercher le nombre de
personnes qui portent le prénom Mohamed.
Solution
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
main()
{
struct Personne
{
char NCIN[8];
char Nom[20];
char Prenom[15];
int Age;
char Adresse[30];
};
struct Personne * SuitePers;
struct Personne * P;
int i; int cpt;
SuitePers=malloc(2*sizeof(struct Personne));
P=SuitePers;
for (i=1;i<=2;i++)
{ printf ("Donner le NCIN:");
gets(P->NCIN);
printf("Donner le nom:");
gets(P->Nom);
printf("Donner le prénom:");
gets(P->Prenom);
printf("Donner l'age:");
scanf("%d",&P->Age);
printf("Donner l'adresse:");
gets(P->Adresse);
P++;
}
P=SuitePers;
cpt=0;
for (i=1; i<=2;i++)
{
35 sur 64
Par: mme Olfa HAMROUNI JEMLI
if (!strcmp(P->Prenom,"Mohamed")) cpt++;
P++;
}
printf("Le nombre de personne de prenom Mohamed est:%d",cpt);
}
7. Tableaux de pointeurs
On définit les tableaux statiques de pointeurs comme les autres tableaux statiques. Lors
de leur définition, on indique le type des éléments du tableau, le nom du tableau et le
nombre des éléments.
Exemples
int * TabE[20]
Définit un tableau nommé TabE de 20 pointeurs, chacun d'entre eux pointe vers une
donnée de type int.
Supposons définir une variable int x=10;
Alors l'instruction TabE[0]=&x range l'adresse de x dans le premier élément du tableau
de pointeurs TabE.
char * TabChaine[20];
Définit un tableau de 20 pointeurs vers des chaînes de caractères.
Application
Soit un tableau de 10 pointeurs vers des articles (utiliser la structure article déjà vu)
- Ecrire un programme en C qui remplit le tableau par des données entrées à partir
du clavier
- Ecrire un programme en C qui trie le tableau selon le tri par sélection (le critère
est le code et l'ordre est croissant)
Ecrire un programme en C qui permet d'afficher le tableau
36 sur 64
Par: mme Olfa HAMROUNI JEMLI
1. Définition
Une liste est un ensemble d'objets de même type constituant les éléments de la liste. Les
éléments sont chaînés entre eux de sorte qu'on puisse ajouter ou extraire ou éliminer
un ou plusieurs éléments(s). Une liste simple est une structure de données telle que
chaque élément contient:
- des informations caractéristiques de l'application (les caractéristiques d'une
personne ou d'un article par exemple)
- Un pointeur vers un autre élément ou une marque de fin de liste s'il n'y a pas
d'élément successeur.
En mathématiques, une liste correspond à une suite et elle vérifie les propriétés
suivantes:
- elle a un unique premier élément appelé: tête de liste
- elle a un unique dernier élément appelé: queue de liste
- chaque élément possède un unique successeur sauf le dernier
- chaque élément possède un unique prédécesseur sauf le premier
37 sur 64
Par: mme Olfa HAMROUNI JEMLI
38 sur 64
Par: mme Olfa HAMROUNI JEMLI
f. Autres opérations
- L'opération de création de liste: la fonction CreerListe.
- L'opération de renvoie de la taille d'une liste (le nombre d'éléments dans la liste): la
fonction TailleListe
- L'opération de passer l'élément courant vers l'élément qui le suit: la fonction Suivant
- L'opération de passer l'élément courant vers l'élément qui le précède: la fonction
Précédent
- L'opération de positionnement sur le premier élément de la liste: la fonction
OuvrirListe
- L'opération de vérification si on est en tête de liste: la fonction DebutListe
- L'opération de vérification si on est en fin de liste: la fonction FinListe
- L'opération de vérification si la liste est vide: la fonction EstVide
- L'opération de destruction de la liste: il consiste à supprimer tous ses éléments: la
fonction DetruireListe
- L'opération d'affichage des informations de tous les éléments de la liste: la fonction
AfficherListe
39 sur 64
Par: mme Olfa HAMROUNI JEMLI
12 9 -1 0 NULL
40 sur 64
Par: mme Olfa HAMROUNI JEMLI
41 sur 64
Par: mme Olfa HAMROUNI JEMLI
void AfficherListe(Tliste * L)
{
if (EstVide(*L)) printf ("Liste Est Vide");
else
{
OuvrirListe(L);
while(L->courant != NULL)
{
printf("\n%d",L->courant->e);
L->courant=L->courant->suivant;
}
}
OuvrirListe(L);
}
/****************************************************************/
void AjoutEnFin (Tliste * L, int x)
{
PElement ptr;
ptr=malloc(sizeof(Element));
ptr->e=x;
if (L->tete==NULL)
L->tete=ptr;
else
L->queue->suivant=ptr;
ptr->suivant=NULL;
L->queue=ptr;
L->courant=ptr;
}
/*****************************************************************/
int ConsulterCourant(Tliste L)
{
if (EstVide(L)) printf ("Liste EstVide");
else return (L.courant->e);
}
/*****************************************************************/
void MAJCourant(Tliste * L,int x)
{
if (EstVide(*L)) printf ("Liste EstVide");
42 sur 64
Par: mme Olfa HAMROUNI JEMLI
else
L->courant->e=x;
}
/*****************************************************************/
int DebutListe(Tliste L)
{
if (EstVide(L)) printf ("Liste EstVide");
else if (L.courant==L.tete) return (1);
else return (0);
}
/*****************************************************************/
int FinListe(Tliste L)
{
if (EstVide(L)) printf ("Liste EstVide");
else if (L.courant==L.queue) return (1);
else return (0);
}
/*****************************************************************/
void suivant (Tliste * L)
{
if (EstVide(*L)) printf ("Liste EstVide");
else
if (FinListe(*L)) L->courant = L->tete;
else
L->courant=L->courant->suivant;
}
/*****************************************************************/
void precedent(Tliste * L)
{
PElement ptr;
if (EstVide(*L)) printf ("Liste EstVide");
else
if (DebutListe(*L)) L->courant = L->queue;
else
{
ptr=L->tete;
while (ptr->suivant!=L->courant)
ptr=ptr->suivant;
43 sur 64
Par: mme Olfa HAMROUNI JEMLI
L->courant=ptr;
}
}
/*****************************************************************/
int TailleListe(Tliste * L)
{
int cpt=0;
OuvrirListe(L);
while (L->courant!=NULL)
{
cpt=cpt++;
L->courant=L->courant->suivant;
}
OuvrirListe(L);
return(cpt);
}
/*****************************************************************/
int Recherche(Tliste * L, int x)
{
OuvrirListe(L);
while (L->courant != NULL)
{if (L->courant->e==x) return (1);
else
L->courant=L->courant->suivant;
}
return(0);
}
/*****************************************************************/
void SupprimerCourant(Tliste * L)
{
PElement p;
if (EstVide(*L)) puts("Impression impossible car liste vide");
else
if ((L->courant==L->tete)&&(L->courant==L->queue))
{
free(L->queue);
L->tete=NULL;
L->queue=NULL;
44 sur 64
Par: mme Olfa HAMROUNI JEMLI
L->courant=NULL;
}
else
if (L->courant==L->tete)
{
L->courant=L->courant->suivant;
free(L->tete);
L->tete=L->courant;
}
else
{
p=L->tete;
while (p->suivant!=L->courant)
p=p->suivant;
p->suivant=L->courant->suivant;
free(L->courant);
if (L->courant==L->queue)
{
L->queue=p;
L->courant=p;
}
else
L->courant=p->suivant;
}
}
/*****************************************************************/
void DetruireListe(Tliste * L)
{
PElement p;
OuvrirListe(L);
while (L->courant->suivant!=NULL)
{
p=L->courant->suivant;
SupprimerCourant(L);
L->courant=p;
}
SupprimerCourant(L);
}
45 sur 64
Par: mme Olfa HAMROUNI JEMLI
/*****************************************************************/
void AjoutApresCourant(Tliste * L, int x)
{
PElement p,ptr;
ptr=malloc(sizeof(PElement));
ptr->e=x;
if (EstVide(*L))
{
L->courant=ptr;
L->queue=ptr;
L->tete=ptr;
L->courant->suivant=NULL;
}
else
if (L->courant==L->queue)
AjoutEnFin(L, x);
else
{
p=L->courant->suivant;
L->courant->suivant=ptr;
ptr->suivant=p;
L->courant=ptr;
}
}
/*****************************************************************/
void AjoutAvantCourant(Tliste * L, int x)
{
PElement p,ptr;
ptr=malloc(sizeof(PElement));
ptr->e=x;
if (EstVide(*L))
{
L->courant=ptr;
L->queue=ptr;
L->tete=ptr;
L->courant->suivant=NULL;
}
else
46 sur 64
Par: mme Olfa HAMROUNI JEMLI
if (L->courant==L->tete)
AjoutEnTete(L,x);
else
{
p=L->tete;
while (p->suivant!=L->courant)
p=p->suivant;
p->suivant=ptr;
ptr->suivant=L->courant;
L->courant=ptr;
}
}
47 sur 64
Par: mme Olfa HAMROUNI JEMLI
48 sur 64
Par: mme Olfa HAMROUNI JEMLI
L'implémentation du fichier file.h est élaborée dans le fichier source file.c suivant:
#include <stdio.h>
#include <stdlib.h>
#include "file.h"
49 sur 64
Par: mme Olfa HAMROUNI JEMLI
ptr=malloc(sizeof(Element));
ptr->e=N;
if (F->tete==NULL)
F->tete=ptr;
else
F->queue->suivant=ptr;
ptr->suivant=NULL;
F->queue=ptr;
}
}
///////////////////////////////////////////////
void ListerFile(TFile F)
{
PElement ptr;
ptr=F.tete;
while (ptr!=NULL)
{printf("\n%d", ptr->e);
ptr=ptr->suivant;
}
}
///////////////////////////////////////////////
int Defiler (TFile * F)
{
PElement aux;
int Elem;
if (EstVideFIle(*F)) puts("Liste vide");
else
if (F->tete==F->queue)
{
Elem=F->tete->e;
free(F->tete);
F->tete=NULL;
F->queue=NULL;
return(Elem);
}
else
{
aux=F->tete;
50 sur 64
Par: mme Olfa HAMROUNI JEMLI
F->tete=F->tete->suivant;
Elem=aux->e;
free(aux);
return(Elem);
}
}
///////////////////////////////////////////////
void DetruireFile(TFile * F)
{
int x;
while(!EstVideFile(*F))
{
x=Defiler(F);
printf("\nLa valeur détruite maintenant est:%d\n",x);
}
printf("Liste detruite");
}
2. Les piles
1.1. Définition
Une pile est une structure de données telle que:
- L'ajout d'un élément se fait au sommet de la pile
- La suppression d'un élément se fait également au sommet de la pile
Cette structure de données est appelée LIFO (Last In First Out= Dernier Entré Premier
Sorti).
Une pile peut être considérée comme une liste, mais une liste à caractère LIFO. La
gestion d'une pile se base sur les actions suivantes:
- Création d'une pile via la fonction CreerPile
- Test si une pile est vide ou non via la fonction EstVidePile
- Empilement d'un élément dans une pile. Il s'agit de l'ajout d'un élément via la
fonction Empiler
- Dépilement d'un élément d'une pile. Il s'agit de la suppression d'un élément via la
fonction Depiler
- Destruction d'une pile via la fonction DetruirePile
- Affichage du contenu de la pile via la fonction ListerPile.
La déclaration d'une pile peut se baser sur la représentation statique (utilisation des
tableaux), ou sur la représentation dynamique (utilisation des pointeurs). Dans ce qui
suit, on se basera sur la représentation dynamique.
51 sur 64
Par: mme Olfa HAMROUNI JEMLI
void CreerPile (TPile * P); //cette fonction crée une pile nommée P
int EstVidePile(TPile P); //cette fonction teste si la pile P est vide(1) ou non(0)
void Empiler (TPile * P, int N); //cette fonction insère un élément N au sommet de la
pile P
int Depiler (TPile * P); //cette fonction renvoie l'élément existant au sommet de la pile
P, //ensuite, elle le supprime
void DetruirePile(TPile * P); //cette fonction supprime tous les éléments de la pile P
void ListerPile(TPile P); //cette fonction affiche tous les éléments de la pile P
L'implémentation du fichier pile.h est élaborée dans le fichier source pile.c suivant:
#include <stdio.h>
#include <stdlib.h>
#include "pile.h"
////////////////////////////////////////
void CreerPile (TPile * P)
{
P->sommet=NULL;
}
////////////////////////////////////////
int EstVidePile(TPile P)
52 sur 64
Par: mme Olfa HAMROUNI JEMLI
{
return(P.sommet==NULL);
}
////////////////////////////////////////
void Empiler (TPile * P, int N)
{
PElement ptr;
ptr=malloc(sizeof(Element));
ptr->e=N;
if (EstVidePile(*P))
{
P->sommet=ptr;
ptr->suivant=NULL;
}
else
{
ptr->suivant=P->sommet;
P->sommet=ptr;
}
}
///////////////////////////////////////
void ListerPile(TPile P)
{
PElement ptr;
ptr=P.sommet;
while( ptr!=NULL)
{
printf("%d\n",ptr->e);
ptr=ptr->suivant;
}
}
///////////////////////////////////////
int Depiler (TPile * P)
{
PElement aux;
int Elem;
if (P->sommet==NULL) puts("Liste vide");
else
53 sur 64
Par: mme Olfa HAMROUNI JEMLI
{
Elem=P->sommet->e;
aux=P->sommet;
P->sommet=P->sommet->suivant;
free(aux);
return(Elem);
}
}
////////////////////////////////////////
void DetruirePile(TPile * P)
{
int val;
while (!EstVidePile(*P))
{
val=Depiler(P);
printf("L'element retire est:%d",val);
}
printf("\nPile rechargée");
}
54 sur 64
Par: mme Olfa HAMROUNI JEMLI
1. Introduction
Un arbre est un ensemble fini d'éléments à un e structure hiérarchique. Chaque élément
est appelé un nœud. Chaque nœud contient l'information spécifique à l'application et des
pointeurs vers d'autres nœuds (d'autres sous-arbres).
Terminologie:
- Une feuille: est un nœud qui ne pointe vers aucun autre nœud.
- Une racine: est le nœud de niveau 1 qui n'est pointé par aucun autre nœud.
- Un niveau: La racine a le niveau 1. les autres nœuds ont un niveau qui est augmenté
de 1 par rapport au nœud dont ils dépendent.
- Une arête: est un lien entre deux meuds.
- Un chemin: est une suite d'arêtes successives.
- Une branche: est un chemin qui se termine par une feuille.
- Une hauteur ou une profondeur: est le niveau maximum atteint par la branche la plus
longue.
- Un degré d'un nœud: est le nombre de successeurs.
- Une taille: est le nombre total de nœuds de l'arbre.
D E F - Le degré de I est: 1
- La taille de l'arbre est: 9
- Exemples d'arêtes: AC, FG, HI
G H - Exemples de branches: FHI, ABE
- Exemples de chemin: ACF, ACFG
I
55 sur 64
Par: mme Olfa HAMROUNI JEMLI
B C
D E F NULL
I NULL
NULL NULL
56 sur 64
Par: mme Olfa HAMROUNI JEMLI
Allocation contiguë
L'allocation peut se faire aussi avec des tableaux:
57 sur 64
Par: mme Olfa HAMROUNI JEMLI
Soit la représentation dynamique et soit la déclaration d'un arbre binaire vue ci-dessus,
les opérations qui s'appliquent sur un arbre binaire sont:
58 sur 64
Par: mme Olfa HAMROUNI JEMLI
59 sur 64
Par: mme Olfa HAMROUNI JEMLI
60 sur 64
Par: mme Olfa HAMROUNI JEMLI
return(N);
}
Le parcours en profondeur
Pour parcourir l'arbre en profondeur, il faut préciser l'ordre de parcours. On distingue
entre le parcours préfixé( en préordre), le parcours infixé( en inordre) et le parcours en
postfixé (en postordre).
1- Le parcours préfixé
Il consiste à traiter la racine, à parcourir en préfixé le sous-arbre gauche et enfin à
parcourir en préfixé le sous-arbre droit.
B C
D I J 61 sur 64
Par: mme Olfa HAMROUNI JEMLI
3- Le parcours postfixé
62 sur 64
Par: mme Olfa HAMROUNI JEMLI
63 sur 64
Par: mme Olfa HAMROUNI JEMLI
BIBLIOGRAPHIE
Kyle LOUDON, traduction d'Eric JACOBONI, ALGORITHMES EN C, O'Reilly &
Associates, Paris 2000,2001, 2002
ISBN: 2-84177-096-6
Peter AITKEN & Bradley L. JONES, LE LANGAGE C, Campus Press, France 2000
ISBN: 2-7440-0838-9
64 sur 64