Académique Documents
Professionnel Documents
Culture Documents
°COURS Structures de Données en C FPO
°COURS Structures de Données en C FPO
I. Rappel
II. Pointeurs
III. Allocation dynamique de la mémoire
IV. Structures
V. Listes, Piles et files
VI. Les arbres binaires
Exercice 1:
Exercice 2:
Vous pouvez aussi utiliser directement sizeof avec un type, par exemple :
sizeof(int) vaudra 4,
sizeof(double) vaudra 8.
Adressage direct
créer une variable de type int (lui réserver 4 octets dans la mémoire), cette
variable est nommée ab. La valeur de ab est 12.
Le principe de l’adressage direct est de manipuler une variable par son nom.
variable.
Adressage indirect
Définition de pointeur
Un pointeur est une variable qui peut contenir l’adresse mémoire d’une
autre variable.
Déclaration de pointeur
Déclarer une variable nommée P comme étant un pointeur sur des entiers.
Un pointeur doit toujours être initialisé par une adresse ou bien
une valeur NULL.
Exercice :
Créer un pointeur P sur une variable de type entier.
Exercice :
Créer un pointeur P sur une variable de type entier.
Quelques exemples.
Exemple 4:
int *P, X ;
P = &X;
P …………………….
*P …………………….
Y = *P+1 …………………….
*P = *P+10 …………………….
*P += 2 …………………….
++*P …………………….
(*P)++ …………………….
L'opérateur d'indirection * et d’adresse & ont une priorité plus élevée par rapport à
l’addition, soustraction, multiplication et division, et une priorité moins élevée par
rapport à l’incrémentation ++ et la décrémentation --
Exemple 4:
int *P, X ;
P = &X;
P &X
*P X
Y = *P+1 Y = X+1
*P = *P+10 X = X+10
*P += 2 X += 2
++*P ++X
(*P)++ X++
Exemple 5:
Soit les deux programmes suivants
Programme 1 Programme 2
Exemple 5:
Exemple 6:
Quelle est la valeur de a, b et c après exécution du programme suivant ?
Exemple 6:
Quelle est la valeur de a, b et c après exécution du programme suivant ?
A B C P1 P2
int a=1, b=2, c=3; 1 2 3
P1=&a @A
P2=&c @C
*P1=(*P2)++ 3 4
P1=P2 @C
P2=&b @B
*P1 -= *P2 2
++*P2 3
P1 = &b @B
*P1 *= *P2 9
3 9 2 @B @B
Exemple :
Si P est un pointeur sur les entiers et l’adresse contenu dans ce pointeur est
1000. Alors P+2 est égale à l’adresse de P + 2 * taille d’un entier = 1000 +
2*4 = 10008.
L’identificateur (le nom) d’un tableau, lorsqu’il est employé seul (sans
indices à sa suite), est considéré comme un pointeur (constant) sur le début
du tableau.
int t [10] ;
t est équivalente à &t[0].
Un nom de tableau est un pointeur constant. Autrement dit, dit la valeur de t ne doit pas
changer.
Une expression telle que t= t+1 n’est pas valide.
L’instruction:
P = A; est équivalente à P = &A[0];
Exercice 1 :
Exercice 2 :
Soit le programme suivant :
*P+2
*(P+2)
&P+1
&A[4]-3
A+3
&A[7]-P
P+(*P-10)
*(P+*(P+8)-A[7])
A. BOUAIN Structure de données
Pointeurs Pointeurs et tableaux
Exercice 2 :
Soit le programme suivant :
Exemple :
Tab
I : indice de la ligne.
J : indice de la colonne.
TC : Taille réservé pour les colonnes (nombre de colonnes déclaré)
P: Pointeur sur le début du tableau P= (int *) tab.
Exemple :
TC = 5 ;
&M[i][j] = P+i*5+j
&M[1][2] = P+1*5+2 = P+ 7
&M[0][1] = P+0*5+1 = P+1
*P
*(P+10)
*P+5
*tab[1]
*(tab[2]+2)
*P 10
*(P+10) 110
*P+5 15
*tab[1] 50
*(tab[2]+2) 110
Exercice:
&A[I][J] P+I*4+J
« Formule (P+I*TC+J) »
A[I][J] *( P+I*4+J)
Une chaîne de caractères est une suite d'octets en mémoire, terminée par
un caractère nul ('\0').
Dans cette déclaration la chaine de caractères est un tableau (son nom est
un pointeur constant) alors les instructions suivantes sont impossible:
char *A = "Hello";
char *B = "SMI S4";
char* salut ;
A = B;
salut = "coucou" ;
char *A = "Hello";
char *B = "SMI S4";
A = B;
B = "coucou" ;
A est un pointeur qui est initialisé de façon à ce qu'il pointe sur une
chaîne de caractères constante stockée quelque part en mémoire.
Le pointeur peut être modifié et pointer sur autre chaîne.
A=B ;
A= "Une autre chaine"
La chaîne constante peut être lue, copiée ou affichée, mais pas modifiée.
Résumé :
Exercice 1
char mot[25], c;
int i,j,n;
for(i=0,j=n-1;i<n/2;i++,j--)
{
c = mot[i];
mot[i] = mot[j];
mot[j] = c;
}
Exercice 2
#include <stdio.h>
#include <string.h>
main()
{
char mot[21],c;
char *ptr;
int i,nbrOcc = 0;
printf("entrer un mot max.20 caractères : ");
scanf("%s", mot);
printf("entrer un caractère : ");
scanf(" %c", &c);
Fonctions et pointeurs
Exemple de fonction
Exemple de fonction
Exemples :
Affectation :
Ou bien :
Utilisation:
Exemple :
main()
{
int a,b,c;
ptrFonct = addition;
printf("Entrer 2 nombres :");
scanf("%d %d",&a,&b);
c = ptrFonct(a,b);
printf("%d :",c);
}
Confusion à éviter:
Ne pas confondre le pointeur sur une fonction avec une fonction qui retourne un
pointeur sur un type.
Exemple :
Il n’est pas toujours possible de savoir quelle quantité de mémoire sera utilisée par
un programme.
La taille fixée à l’avance est peut-être plus grande que le besoin de
l’utilisateur. – gaspillage de mémoire –
La fonction malloc()
Syntaxe :
- OU:
La fonction malloc()
La fonction malloc()
Il faut donc tester si le pointeur retourné est égal à NULL; si c'est le cas, on ne peut
pas et on ne doit pas l'utiliser:
La fonction free()
Lorsqu'on n'a plus besoin d'un tableau alloué dynamiquement, il est impératif de
libérer la mémoire. Cette opération se fait avec la fonction free().
Syntaxe de free() :
Exercice :
Exercice 2:
void main ()
{
int m,n,i;
int **tab;
printf("Entrez le nombre de lignes : ");
scanf("%d", &m);
printf("Entrez le nombre de colonnes : ");
scanf("%d", &n);
tab = malloc(m * sizeof(int*));
Exemple :
structure voiture (marque, nbr de cylindre, carburant, couleur, prix)
Structure produit( désignation, prix, quantité, date_expiration ).
Structure élève (nom, prénom, âge, moyenBac, codeMassar ).
struct produit
{ int numero ;
int qte ;
float prix ;
} ;
struct eleve
{ int numero ;
char nom[30];
Membres ou champs
char Prenom[30]; de la structure
float MoyenBac;
} ;
Méthode 1:
struct eleve
{
int numero ;
char nom[30];
char Prenom[30];
float MoyenBac;
} ahmed;
struct Point
{
int x, y;
} p1;
struct Point
{
int x, y;
};
int main()
{
struct Point p1;
}
A. BOUAIN Structure de données
Les structures Définition d’une variable de type structure
Exercice
struct Point
{
int x = 0; // ERREUR COMPILATEUR: impossible d'initialiser les membres ici
int y = 0; // ERREUR COMPILATEUR: impossible d'initialiser les membres ici
};
Initialisation séquentielle
{ int numero ;
char nom[30];
char Prenom[30];
float MoyenBac;
};
Initialisation sélective
struct eleve
{
int numero ;
char nom[30];
char Prenom[30];
float MoyenBac;
};
variable.membre
e1.nom;
e1.moyenBac;
Exemple
Tableau de structures
Typedef et structures
Pour créer une variable de type structure vous êtes obligé de suivre la syntaxe suivante :
Par exemple :
Pour ne pas répéter le mot clé strcut à chaque déclaration de variable de type
structure vous pouvez utiliser typedef.
}s_personne;
s_personne P1, P2 ;
}S_personne; }s_personne;
Pointeurs et structures
Comme les types primitifs, nous pouvons avoir un pointeur sur une structure.
typedef struct
{
char nom[20];
float moyenne;
} etudiant;
main()
{
// Allocation dynamique d’une variable
if (PtrE1 ==NULL)
{
printf("\n Allocation dynamique impossible !");
exit(1) ; // on quitte le programme
}
}
A. BOUAIN Structure de données 1
Les structures Allocation dynamique de structures
typedef struct
{
char nom[20];
float moyenne;
} etudiant;
main()
{
int n =10;
if (PtrE1 ==NULL)
{
printf("\n Allocation dynamique impossible !");
exit(1) ; // on quitte le programme
}
} A. BOUAIN Structure de données 1
Les structures Allocation dynamique de structures
Exercice :
Une liste chaînée est une structure de données linéaire, dans laquelle
les éléments ne sont pas stockés à des emplacements de mémoire
contigus. Les éléments d'une liste chaînée sont liés à l'aide de
pointeurs comme indiqué dans l'image ci-dessous:
Tête
Donnée Suivant
Queue
Tête
maillon
Exemple :
• id [] = [1000, 1010, 1050, 2000, 2040].
Pour insérer la valeur 1005 et maintenir l'ordre trié, nous devons déplacer
tous les éléments après 1000 (sauf 1000).
- L'accès aléatoire n'est pas autorisé dans une liste chainée. Nous devons
accéder séquentiellement aux éléments à partir du premier nœud.
Exemple :
• id [] = [1000, 1010, 1050, 2000, 2040].
Pour insérer la valeur 1005 et maintenir l'ordre trié, nous devons déplacer
tous les éléments après 1000 (sauf 1000).
Une liste chaînée est représentée par un pointeur sur le premier nœud
de la liste chaînée. Le premier nœud est appelé la tête. Si la liste
chaînée est vide, la valeur de la tête est NULL.
Tête
struct Maillon
{
int donnee;
struct Maillon* suivant;
};
Tête
maillon
Tête Temp
NULL
Temp
A. BOUAIN Structure de données 1
Les listes chainées
temp = temp->suivant;
}
return false;
Ajouter en tête
Lors d'un ajout en tête, nous allons créer un élément, lui assigner la valeur
que l'on veut ajouter, puis pour terminer, raccorder cet élément à la tète de
la liste passée en paramètre.
Ajouter un élément
Ajouter en tête
Ajouter un élément
Ajouter en fin de liste
•Il nous faut tout d'abord créer un nouvel élément, lui assigner sa valeur,
et mettre l'adresse de l'élément suivant à NULL. En effet, comme cet
élément va terminer la liste nous devons signaler qu'il n'y a plus
d'élément suivant.
•Ensuite, il faut faire pointer le dernier élément de la liste originale sur le
nouvel élément que nous venons de créer. Pour ce faire, il faut créer un
pointeur temporaire qui cherchera le dernier élément de la liste.
•Un élément sera forcément le dernier de la liste si NULL est assigné à
son champ suivant.
Temp
Ajouter un élément
Ajouter en fin de liste
Exemple d’exécution