Vous êtes sur la page 1sur 33

Les structures de Données en langage C- Eléments de cours -1-

Saloua Guezguez
Les Tableaux en C

Un tableau est un ensemble de données de même type.

Déclaration :
int A[10] ; //tableau de 10 entiers maximum
float B[5] ; //tableau de 5 réels au maximum
char C[20] ; //tableau de 20 caractères

Ce qui est spécifié entre [ ], c’est la capacité maximale du tableau, c'est-à-dire le nombre d’adresses
mémoire qui sont réservées pour le tableau. Ces adresses mémoire sont consécutives et l’accès aux
éléments se fait en précisant l’indice de l’élément en question.
En C, ces indices varient de 0 à n-1 pour un tableau de n valeurs.

Remplissage et affichage
Le squelette d’un programme C manipulant un tableau peut être le suivant :
#define max 20 //définition d’une constante qui sert à spécifier la taille maximale des tableaux
void main()
{
int tab[max], n, i;
//saisie du nombre de valeurs à stocker dans le tableau
//à condition de ne pas dépasser la capacité max
do
{
printf (« combien de valeurs ? ») ;
scanf (« %d », &n) ;
}while ((n<=0)||(n>max)) ;

//remplir les n valeurs du tableau


for(i=0 ;i<n ;i++) //attention le compteur va de 0 à n-1
{
printf (« T[%d] = »,i) ;
scanf(« %d »,&tab[i]) ;
}

//traitements sur le tableau rempli


……..
//affichage du tableau
for(i=0 ;i<n ;i++)
printf (« %d”,tab[i] ) ;
}
Traitements usuels :
1- Saisir un tableau
void saisirTab (int *T, int n)
{
int i ;
for(i=0 ;i<n ;i++)
{
printf (« T[%d] = »,i) ;
scanf(« %d »,&T[i]) ;
}
}
Les structures de Données en langage C- Eléments de cours -2-
Saloua Guezguez
2- Afficher un tableau

void affichTab(int *T, int n)


{
for(i=0 ;i<n ;i++)
printf (“ %d|”,T[i] ) ;
}

La fonction main devient :


void main()
{
int tab[max], taille, i;
//saisie du nombre de valeurs à stocker dans le tableau
//à condition de ne pas dépasser la capacité max
do
{
printf (« combien de valeurs ? ») ;
scanf (« %d », &taille) ;
}while ((taille<=0)||(taille>max)) ;
//remplir le tableau
saisirTab (tab, taille) ;
//traitements sur le tableau rempli
……..
//affichage du tableau
affichTab(tab, taille) ;
}

3- Rechercher une valeur

Données :
- un tableau de n valeurs entières
- une valeur x à rechercher
Problème :
- retourner la position de la première occurrence de x s’il existe ou bien -1 si x n’existe pas
Comment faire ?
Comparer successivement les valeurs du tableau avec la valeur recherchée et arrêter la recherche
dès que x est trouvé ou bien quand on atteint la fin du tableau

Fonction
int recherche(int *T, int n, int x)
{
i=0 ;
while ((i<n)&&(T[i] !=x))
i++;
if (i<n) //on est sorti de la boucle car on a trouvé x à la position i
return i ;
return -1 ;
}
Les structures de Données en langage C- Eléments de cours -3-
Saloua Guezguez
Et voilà une nouvelle fonction main qui effectue une recherche dans un tableau
void main()
{
int tab[max], taille, i, x;
//saisie du nombre de valeurs à stocker dans le tableau
do
{
printf (« combien de valeurs ? ») ;
scanf (« %d », &taille) ;
}while ((taille<=0)||(taille>max)) ;
//remplir le tableau
saisirTab (tab, taille) ;
//saisie de x
printf(« donner la valeur à rechercher ») ;
scanf(« %d »,&x) ;
//recherche de x
i=recherche (tab, taille , x) ;
if (i !=-1)
printf (« %d existe à la position %d », x, i) ;
else
printf(« %d n’existe pas », x) ;
}

4- compter les occurrences d'une valeur x donnée


Données :
- un tableau tab de n valeurs entières
- une valeur x à rechercher
Problème :
- chercher toutes les occurences de x
Comment faire ?
Parcourir le tableau entièrement et comparer successivement les valeurs du tableau avec la valeur
recherchée, à chaque fois que la valeur de x est trouvée on incrémente le nombre d’occurences

Fonction
int occurrences (int *T, int n, int x)
{
int i=0 , nb=0 ;
for( i=0; i<n ;i++)
{
if (T[i]==x)
nb++ ;
}
return nb ;
}

5- Insérer une valeur donnée à un indice donné


Données :
- un tableau tab de n valeurs entières
- une valeur x à insérer
- une position d’insertion i
Les structures de Données en langage C- Eléments de cours -4-
Saloua Guezguez
Problème :
- Insérer x à la position i sans écraser les informations déjà contenues dans le tableau
Condition :
- la taille actuelle du tableau doit être inférieure à la capacité maximale
Comment faire ?
- Décaler toutes les valeurs du tableau vers la droite en commençant par la dernière valeur qui
est affectée à la case suivante (vide) et en effectuant le même traitement jusqu’à la valeur
qui est dans la case i.
- Une fois la case i libérée, on insère la valeur x
- Ne pas oublier d’incrémenter la taille du tableau !!
Fonction
void inserer (int *T, int *n, int x, int i)
{
int j ;
if((*n)<max)
{
//décalage vers la droite
for (j=(*n) ;j>=i+1 ;j--)
tab[j]=tab[j-1] ;
//insertion
tab[i]=x ;
//mise à jour de la taille
(*n)++ ;
}
else
printf(« ajout impossible\n ») ;
}
Une autre fonction main
void main()
{
int tab[max], taille, i, x;
//saisie du nombre de valeurs à stocker dans le tableau
do
{
printf (« combien de valeurs ? ») ;
scanf (« %d », &taille) ;
}while ((taille<=0)||(taille>max)) ;
//remplir le tableau
saisirTab (tab, taille) ;
//affichage du nouveau tableau avant insertion de x
affichTab(tab, taille) ;
//saisie de x
printf(« donner la valeur à insérer ») ;
scanf(« %d »,&x) ;
//saisie de i
printf(« donner la position d’insertion ») ;
scanf(« %d »,&i) ;
//insertion
inserer (tab, &taille, x, i) ;
//affichage du nouveau tableau après insertion de x
affichTab(tab, taille) ;
}
Les structures de Données en langage C- Eléments de cours -5-
Saloua Guezguez
6- Supprimer une valeur dans un tableau

Données :
- un tableau tab de n valeurs entières
- une valeur x à supprimer

Problème :
- Supprimer la première occurrence de x du tableau

Condition :
- x doit exister

Comment faire ?
- il faut préalablement passer par une étape de recherche
- si x n’existe pas afficher un message correspondant
- sinon récupérer sa position i
- effectuer un décalage vers la gauche en commençant par la valeur qui est à la position i qui
est remplacée par la valeur suivante et en répétant le traitement jusqu’à l’avant dernière
valeur du tableau
- ne pas oublier de décrémenter la taille !!

Fonction
void supprimer(int *tab, int *n, int x)
{
int i, j ;
//recherche de x
i=recherche (tab, *n, x) ;
if(i !=-1)
{
//décalage vers la gauche
for (j=i ;j<=(*n)-2 ;j++)
tab[j]=tab[j+1] ;
//mise à jour de la taille
(*n)-- ;
}
else
printf(« %d n’existe pas\n », x) ;

Une autre fonction main

void main()
{
int tab[max], taille, i, x;
//saisie du nombre de valeurs à stocker dans le tableau
do
{
printf (« combien de valeurs ? ») ;
scanf (« %d », &taille) ;
}while ((taille<=0)||(taille>max)) ;
Les structures de Données en langage C- Eléments de cours -6-
Saloua Guezguez
//remplir le tableau
saisirTab (tab, taille) ;
//affichage du tableau avant suppression de x
affichTab(tab, taille) ;
//saisie de x
printf(« donner la valeur à supprimer ») ;
scanf(« %d »,&x) ;
//suppression
supprimer (tab, &taille, x) ;
//affichage du nouveau tableau après suppression de x
affichTab(tab, taille) ;
}

7- Supprimer toutes les occurrences d’une valeur dans un tableau

Données :
- un tableau tab de n valeurs entières
- une valeur x à supprimer

Problème :
- Supprimer toutes les occurrences de x du tableau

Comment faire ?
- Parcourir le tableau entièrement
- A chaque fois qu’on trouve la valeur x on effectue le décalage et on met à jour la taille
- Attention aux valeurs qui se suivent…

Fonction
int supprimerTout (int *T, int *n, int x)
{
int i,j ;
for(i=0 ;i<*n ;i++)
{
while (T[i]==x) //la boucle while permet de supprimer aussi les valeurs consécutives de x
{
//décalage vers la gauche
for (j=i ;j<=(*n)-2 ;j++)
T[j]=T[j+1] ;
//mise à jour de la taille
(*n)-- ;
}
}
}

Une autre fonction main


Les structures de Données en langage C- Eléments de cours -7-
Saloua Guezguez
void main()
{
int tab[max], taille, i, x;
//saisie du nombre de valeurs à stocker dans le tableau
do
{
printf (« combien de valeurs ? ») ;
scanf (« %d », &taille) ;
}while ((taille<=0)||(taille>max)) ;
//remplir le tableau
saisirTab (tab, taille) ;
//affichage du tableau avant suppression de x
affichTab(tab, taille) ;
//saisie de x
printf(« donner la valeur à supprimer ») ;
scanf(« %d »,&x) ;
//suppression
supprimerTout (tab, &taille, x) ;
//affichage du nouveau tableau après suppression de x
affichTab(tab, taille) ;
}
Les structures de Données en langage C- Eléments de cours -8-
Saloua Guezguez
Les tableaux à deux dimensions

Déclaration
int A[2][3] ; //déclaration d’un tableau à 2 lignes et 3 colonnes de valeurs entières
float B[4][4] ; //déclaration d’un tableau à 4 lignes et 4 colonnes de valeurs réelles

dans un tableau de n lignes et m colonnes le nombre de valeurs qui peuvent être stockées est égal à
nxm ; par exemple dans le tableau A on peut avoir jusqu’à 6 entiers, et dans le tableau B on peut
avoir jusqu’à 16 réels.

L’accès aux éléments se fait en spécifiant deux indices à la fois : le numéro de la ligne entre []et le
numéro de la colonne entre [] ; par exemple A[1][2] désigne l’entier qui est stocké à la ligne 1,
colonne 3 du tableau A.
Dans un tableau à n lignes et m colonnes, les indices des lignes varient de 0 à n-1 et ceux des
colonnes varient de 0 à m-1.

Remplissage et affichage
Le squelette général d’un programme C manipulant un tableau à deux dimensions peut être le
suivant :

#define max 10 // constante qui sert à spécifier la taille maximale des lignes et des colonnes
void main()
{
int tab[max][max], n, m, i, j;
//saisie du nombre de lignes
do //ne pas dépasser la capacité max
{
printf (« combien de lignes ? ») ;
scanf (« %d », &n) ;
}while ((n<=0)||(n>max)) ;

//saisie du nombre de colonnes


do
{
printf (« combien de colonnes ? ») ;
scanf (« %d », &m) ;
}while ((m<=0)||(m>max)) ;
//remplir les nxm valeurs du tableau, il faut deux boucles
//imbriquées : la 1ère fixe la ligne, l’autre parcourt les colonnes
for(i=0 ;i<n ;i++) //attention le compteur va de 0 à n-1
{
for(j=0 ;j<m ;j++)
{
printf (« T[%d,%d] = »,i,j) ;
scanf(« %d »,&tab[i][j]) ;
}
}
//traitements sur le tableau rempli
……..
//affichage du tableau
for(i=0 ;i<n ;i++)
{
Les structures de Données en langage C- Eléments de cours -9-
Saloua Guezguez
for(j=0 ;j<m ;j++)
printf (« %d”,tab[i][j] ) ;
printf(“\n”); //un retour à la ligne avant la ligne suivante
}
}
Les structures de Données en langage C- Eléments de cours - 10 -
Saloua Guezguez
Les pointeurs en C

Définition, déclaration et utilisation des pointeurs


Un pointeur est une variable dont le contenu est une adresse mémoire. Le type d’un pointeur
dépend du type de l’adresse à stocker dans le pointeur.
Ainsi :
int *p ; correspond à la déclaration d’un pointeur p qui est destiné à contenir l’adresse mémoire
d’une variable de type entier. (p est de type int *)
float *p1 ; est une déclaration d’un pointeur p1 qui est destiné à contenir l’adresse mémoire d’une
variable de type réel. (p1 est de type float *)
char *p2 ; est une déclaration d’un pointeur p2 qui est destiné à contenir l’adresse mémoire d’une
variable de type caractère. (p2 est de type char *)

Pour stocker l’adresse d’une variable dans un pointeur, il suffit d’utiliser l’opérateur & (qu’on connaît
déjà par son utilisation dans la fonction scanf). Appliqué à une variable, l’opérateur & permet
d’obtenir l’adresse de cette variable.

Exemples :
int * p ; //p est un pointeur sur entier
int x=10 ; // x est une variable de type entier
p=&x ; //on a stocké dans le pointeur p l’adresse mémoire de la variable x

si on schématise la mémoire :
@ variable contenu
…..
80
82
84 x 10
86
88
90
92 p 84 (adresse de x)
94
96
….

p contient l’adresse de la variable x, on dit alors que p pinte sur x (ou alors que p est un pointeur sur
x)
on peut faire de même sur des variables de type réel ou caractère.
float * pf ;
float y=0.1 ;
pf = &y ;

A l’aide de ce lien entre le pointeur et la variable pointée, il est possible de modifier la valeur de la
variable à travers le pointeur, et ce grâce à l’opérateur *
L’opérateur * (appliqué à une variable de type pointeur) permet d’accéder à la case mémoire dont
l’adresse est stockée dans un pointeur. Ainsi, si p contient l’adresse mémoire de x alors *p désigne
l’entier x (la variable pointée par p).

Examinons l’exemple suivant :


Les structures de Données en langage C- Eléments de cours - 11 -
Saloua Guezguez

int x=10 ; //x est un entier qui contient la valeur 10


int *p =&x ; //p est un pointeur qui contient l’adresse de x
(*p)++ ; //on incrémente x !!!
Printf(« %d », x) ; //on affiche « 11 », on a ainsi modifié la valeur de la variable x à travers le pointeur
p.

Attention : l’opérateur * est différent du symbole * qu’on met devant le type lors de la déclaration
du pointeur !!!

Soit la suite d’instructions suivante :


int * p1 , *p2 ; //déclaration de deux pointeurs p1 et p2 sur entier
int x=3, y=4, z=5 ; //déclaration de 3 entiers x, y et z
p1=&x ; //p1 pointe sur la variable x
p2=&y ; //p2 pointe sur y
1) *p1=*p2+5 ;//*p1 désigne la case mémoire pointée par p1 (x)
2) (*p2)-- ; //*p2 désigne la case mémoire pointée par p2 (y)
3) p1=&z ;//p1 pointe sur z
4) *p1=*p2 ;//regardez l’état de la mémoire pour savoir ce que fait cette instruction
printf(« %d,%d,%d »,x,y,z) ;

@ @ @ @ @
….. ….. ….. ….. …..
80 y 4 80 y 4 80 y 80 y 3 80 y 3
82
3
82 82 82 82
84 p2 80 84 p2 80 84 p2 80 84 p2 80
86 84 p2 80
86 86 86 86
88 x 3 88 x 88 x 9 88 x 9
90 9 88 x 9
90 90 90 90
92 p1 88
92 p1 88 92 p1 88 92 p1 100 92 p1 100
94
94 94 94 94
96
96 96 96 96
98
98 98 98 98
100 z 5
100 z 5 100 z 5 100 z 5 100 z 3
102
…… 102 102 102 102
Etat initial …… …… …… ……
Instruction 1 Instruction 2 Instruction 3 Instruction 3

En résumé, si on a une variable entière et un pointeur sur entier :


int x =20 ;
int *p=&x ;//attention ici le symbole * est utilisé dans la déclaration, ce n’est pas un opérateur
en fait cette instruction désigne à la fois une déclaration et une initialisation du pointeur p
Les structures de Données en langage C- Eléments de cours - 12 -
Saloua Guezguez
le tableau suivant résume toutes les utilisations possibles du pointeur et de la variable entière :

variable type signification contenu


p int * pointeur sur x Adresse de x
x int Variable de type entier 10
*p int La case mémoire pointée par p, c'est-à-dire la variable x 10
*x faux L’opérateur * ne peut être appliqué à x (sauf si on veut faire
une multiplication entre deux entiers)
&p int ** Adresse de p, p étant une variable, elle possède elle-même Adresse de p
une adresse en mémoire
&x int * Adresse de x Adresse de x

Pointeurs et tableaux
En langage C, il y a une forte relation entre pointeurs et tableaux, en fait un tableau est un pointeur,
mais comment ?

Considérons la déclaration suivante : int A[5] ;


la question est : comment A est déclaré en mémoire ? est-ce que c’est un entier ? comment sont
déclarées les 5 cases du tableau est quelle est leur relation avec A ?
En fait A est une variable de type pointeur sur entier (int *), qui contient la première des 5 adresses
qui sont réservées pour le tableau. Ce qui peut correspondre au schéma mémoire suivant :

@
…..
80
82
84 A[0] Case réservée pour le tableau
86 A[1] Case réservée pour le tableau
88 A[2] Case réservée pour le tableau
90 A[3] Case réservée pour le tableau
92 A[4] Case réservée pour le tableau
94
96
98
100
102 A 84
104
…..

Si A contient l’adresse de A[0], alors en appliquant le même principe que précédemment, *A désigne
la case mémoire pointée par A, c'est-à-dire A[0]. Les 5 adresses mémoires étant consécutives, A[0]
ayant son adresse stockée dans A, on peut en déduire que A[1] possède l’adresse A+1, A[2] possède
l’adresse A+2, et ainsi de suite.
Ce qui signifie que A[1] peut être interprété comme *(A+1), qui n’est autre que le contenu de la case
mémoire d’adresse A+1, et de manière plus générale, étant donné un indice i, *(A+i) désigne la case
A[i] du tableau A.

En fait, c’est ainsi qu’un tableau est vu par le compilateur, à chaque accès à un élément d’indice i, le
compilateur effectue l’opération A+i, applique l’opérateur * sur cette adresse et on obtient ainsi
l’élément de type entier. Les crochets désignent donc une manière plus simple et plus conviviale
Les structures de Données en langage C- Eléments de cours - 13 -
Saloua Guezguez
d’accéder aux éléments du tableau, mais en réalité un calcul d’adresse est systématiquement
effectué par le compilateur.

Ainsi, la boucle d’affichage suivante est équivalente à la boucle qu’on a l’habitude d’écrire en
utilisant les crochets :
for(i=0 ; i<5 ; i++)
printf(« %d », *(A+i)) ;

Allocation dynamique de mémoire


La déclaration d’un tableau avec une dimension figée a plusieurs inconvénients, d’un côté, on prévoit
souvent une dimension supérieure à nos besoins réels, ce qui peut être vu comme du gaspillage de
mémoire, d’un autre côté, cette dimension déclarée peut être inférieure à la taille demandée par un
utilisateur et dans ce cas il est impossible d’avoir plus de mémoire.

Pour éviter ces deux extrêmes, le tableau peut être déclaré comme un pointeur, sans spécifier sa
dimension, et suivant le besoin exprimé dans le programme, on peut créer dynamiquement autant
d’adresses mémoires.

La fonction malloc (Memory Alloc)


C’est une fonction de la bibliothèque <stdlib.h>, elle permet de créer une ou plusieurs adresses
mémoires.
Sa syntaxe est la suivante :
(type d’adresse) malloc (taille en octet du bloc mémoire à créer)
La fonction crée une ou plusieurs adresses mémoire du type spécifié, et ayant la taille spécifiée en
paramètre. Elle fournit en retour la première de ces adresses créées.

Pour calculer la taille du bloc mémoire à réserver, on peut utiliser la fonction sizeof du C. Celle-ci
retourne en octet la taille d’un type de données.

Par exemple, on considère le programme C suivant où on va créer un tableau A de 5 éléments


entiers.
void main()
{
int * A ; //le tableau est déclaré comme un pointeur, aucune
//dimension n’est spécifiée
A= (int *) malloc (5*sizeof(int)) ;
//on a besoin de 5 cases mémoire ayant chacune la taille d’un
//entier, la taille du bloc totale est donc égale à 5*la taille d’un
//entier
………
//traitements usuels sur le tableau A (remplissage, affichage…)
}

Que se passe-t-il en mémoire ?


1- il y création de 5 adresses mémoire de type (int *)
2- la première de ces adresses est affectée dans A
ce qui nous donne un schéma mémoire identique à celui qui correspond à la déclaration
int A[5] ;
Les structures de Données en langage C- Eléments de cours - 14 -
Saloua Guezguez
@
…..
80
82
84 A[0] Case réservée pour le tableau
86 A[1] Case réservée pour le tableau
88 A[2] Case réservée pour le tableau
90 A[3] Case réservée pour le tableau
92 A[4] Case réservée pour le tableau
94
96
98
100
102 A 84
104
…..

A la différence près que A dans ce cas est un simple pointeur qui peut à tout moment pointer sur une
autre adresse, et que les 5 cases ont été créées dans le programme et non pas lors de la déclaration
des variables. C’est donc une dimension qui n’est pas figée.

La fonction free
Les adresses mémoire allouées avec malloc peuvent à tout moment être libérées à l’aide de la
fonction free ;

void main()
{
int * A ; //le tableau est déclaré comme un pointeur, aucune
//dimension n’est spécifiée
A= (int *) malloc (5*sizeof(int)) ;
//on a besoin de 5 cases mémoire ayant chacune la taille d’un
//entier, la taille du bloc totale est donc égale à 5*la taille d’un
//entier
………
//traitements usuels sur le tableau A (remplissage, affichage…)
…..
free (A) ;//libère les 5 adresses mémoire qui ont été allouées pour A
}
Les structures de Données en langage C- Eléments de cours - 15 -
Saloua Guezguez
Alors qu’arrive-t-il dans notre schéma mémoire une fois qu’on a libéré ces adresses ?

@
A est un pointeur qui est toujours en
….. mémoire jusqu’à la fin de
80 l’exécution de la fonction où il a été
82 déclaré.
84 Par contre les adresses qui ont été
86 réservées pour le tableau sont
88 libérées (elles ne sont plus
90 réservées).
92 Ce qui veut dire que A est prêt à
94 recevoir une nouvelle adresse (peut
96 être un nouveau tableau avec une
98 dimension différente !!!)
100
102 A
104
…..

Exemple :
soit un programme qui éclate un tableau en 2 tableaux, l’un contient les valeurs d’indice pair et
l’autre les valeurs d’indice impair.

void main()
{
int * tab1, *tabPair, *tabImpair, n, i, j;
//le déclaration de 3 tableaux sans aucune dimension préalable
//les dimensions seront définies par les besoins

//on commence par saisir au clavier la dimension du tableau initial


printf(« combien de valeurs : ») ;
scanf(« %d »&n) ;

//on réserve n addresses mémoires pour tab


tab= (int *) malloc (n*sizeof(int)) ;

//on réserve pour les 2 tableaux la moitié de n, on va ajouter une


//case supplémentaire pour les indices pairs pour le cas où n est //impair
tabPair = (int *) malloc ((n/2+1) * sizeof(int)) ;
tabImpair = (int *) malloc ((n/2) * sizeof(int)) ;

//on effectue la copie des valeurs d’indice pair


for(i=0,j=0 ;i<n ;i+=2,j++)
tabPair[j]=tab[i];

//on effectue la copie des valeurs d’indice impair


for(i=1,j=0 ;i<n ;i+=2,j++)
tabPair[j]=tab[i];

//il suffit alors d’afficher les 2 tableaux résultats


}
Les structures de Données en langage C- Eléments de cours - 16 -
Saloua Guezguez
Les structures de Données en langage C- Eléments de cours - 17 -
Saloua Guezguez
Les fonctions en C

Intérêt :
Les avantages de décomposer un problème en plusieurs sous- problèmes sont multiples :
- Rendre la résolution plus facile, car le fait de réfléchir à un sous- problème est toujours plus
simple que de réfléchir à un problème complexe.
- Faciliter la mise à jour du programme, en effet un programme modulaire est toujours plus
simple à modifier car il suffit de repérer le module à modifier.
- Faciliter la lisibilité du programme
- Pouvoir réutiliser du code, les sous-programmes sont écrits une fois et peuvent être utilisés
plusieurs fois
En langage C
En C, tout sous-programme est appelé fonction.
Exemple :

float puissance (float x, int n) 1- entête de la fonction


{ 2- corps de la fonction
float p=1 ;
int i ;
for(i=1 ;i<=n ;i++)
p*=x ;
return p ; 3- retour de la fonction
}

On peut décomposer l’écriture de cette fonction puissance en 3 parties :

1- entête de la fonction
Elle est composée en général de 3 parties :

float puissance(float x,int n) float puissance(float x,int n) float puissance(float x,int n)

1-1 type de la fonction : 1-2 nom de la fonction 1-3 paramètres de la fonction


Il désigne le type du résultat calculé par c’est un identificateur qui doit être x et n sont dits paramètres formels
la fonction , ie son type de retour, une unique, de préférence significatif, et qui de la fonction puissance. Ils n’ont pas
fonction qui n’a pas de résultat doit obéir aux mêmes règles de syntaxe de valeur, leur seul rôle est
(procédure) possède le type void que les autres identificateurs (variables, permettre la définition de la
etc…). méthode de calcul de xn, (x étant un
Il y a dans tout programme C au moins réel, et n un entier). Les paramètres
une fonction, qui doit être appelée main. formels d’une fonction n’occupent
C’est la fonction principale, par laquelle aucun espace en mémoire, des
commence l’exécution du programme. adresses leur seront réservées plus
L’exécution bascule éventuellement dès tard lors de l’utilisation (appel) de la
qu’on rencontre un appel de fonction. fonction.
La liste des paramètres formels peut
être vide.
Les structures de Données en langage C- Eléments de cours - 18 -
Saloua Guezguez
2- corps de la fonction
Le corps d’une fonction comprend les instructions nécessaires à la résolution du problème. Il peut
être lui-même décomposé en deux parties :
float p=1 ; float p=1 ;
int i ; int i ;
for(i=1 ;i<=n ;i++) for(i=1 ;i<=n ;i++)
p*=x ; p*=x ;

2-1 déclaration des variables 2-2 Instructions


les variables déclarées dans une fonction sont C’est tout simplement la suite d’opérations
dites locales à la fonction. Une variable locale nécessaires à la résolution du problème posé.
est une variable dont la valeur est visible
uniquement à l’intérieur de la fonction où elle a
été déclarée.

Exemple :
void f()
{
int x=10 ; // x est une variable locale à la fonction f
}

void main()
{
printf(« %d », x) ; //erreur, x n’est pas connue
//dans la fonction main
}

Par opposition, on trouve en C des variables globales, elles sont déclarées à l’extérieur de toutes les
fonctions et possèdent donc une portée globale, c'est-à-dire que leur valeur est visible par toutes les
fonctions du programme.

Exemple :
int x=10 ; //x est une variable gloable, elle est visible par toutes les
//fonctions
void f()
{
Printf(«%d», x) ;//si f est appelée,alors elle affichera la valeur 10
}

void main()
{
x++ ; //n’importe quelle fct a le droit de modifier la valeur d’une
//variable globale, alors attention à l’utilisation de ce genre
//de variable
printf(« %d », x) ; //affichage (11)
}

3- retour de la fonction
L’instruction return permet de retourner le résultat calculé par la fonction vers la fonction
appelante. Elle permet aussi de stopper l’exécution de la fonction si elle est placée autre part qu’à la
Les structures de Données en langage C- Eléments de cours - 19 -
Saloua Guezguez
fin de la fonction. Une fonction de type void ne possède pas d’instruction return à la fin, puisqu’elle
n’a pas de valeur de retour.

Utilisation (appel)

Considérons la fonction précédente :


float puissance (float x, int n)
{
float p=1 ;
int i ;
for(i=1 ;i<=n ;i++)
p*=x ;
return p ;
}

Une utilisation possible de cette fonction peut être la suivante :

void main()
{
float a=5 ;
int b=3 ;
printf («%d», puissance (a,b)) ;
………
}
Les structures de Données en langage C- Eléments de cours - 20 -
Saloua Guezguez
Déroulement de l’exécution

L’exécution de tout programme C démarre à la fonction main, celle-ci garde la main tant qu’il n’y a
pas eu d’appel de fonctions. Le compilateur réserve une zone mémoire pour la fonction main dans
laquelle il va y avoir la déclaration des variables locales à la fonction, et le déroulement de toutes
les instructions présentes dans la fonction. Dès qu’un appel de fonction est rencontré, cette fonction
est chargée en mémoire , ce qui veut dire que l’exécution va basculer vers cette fonction, la
fonction main perd la main et se met en attente de la fin de l’exécution de la fonction appelée pour
reprendre son exécution.

Le chargement d’une fonction en mémoire implique la réservation d’une nouvelle zone mémoire
dans laquelle se déroulera l’exécution de la fonction. Concrètement, dans cette zone mémoire
seront déclarés les paramètres formels de la fonction ainsi que ses variables locales. Les paramètres
formels (s’ils y en a) reçoivent leurs valeurs à partir des paramètres de l’appel, ceux-ci sont dits
paramètres effectifs. Leurs valeurs sont copiées dans les paramètres formels dans l’ordre de l’appel,
ce qui implique bien entendu que le nombre et les types des paramètres effectifs doivent
correspondre à ceux des paramètres formels.

Si on schématise le déroulement de l’appel d’une fonction :

void main()
{
1) float a=5, res;
2) int b=3 ;
3) res= puissance (a,b);//les paramètres d’appel a et b sont dits
//paramètres effectifs
4) printf («%d», res)
………
}
Instruction 3
@ @ @ L’instruction d’affectation contient
comme argument un appel à la
….. ….. ….. fonction puissance, cette affectation
80 80 80 se met donc en attente du résultat de
82 82 l’exécution de la fonction. On bascule
82 vers la fonction puissance qui est
84 84 a 5 84 a 5
chargée en mémoire alors que
86 86 86 l’exécution de la fonction main est
88 88 res 88 res suspendue. L’appel d’une fonction se
déroule en 4 étapes :
90 90 90 1- la fonction est chargée en
92 92 92 mémoire (une nouvelle zone
94 94 94 mémoire lui est réservée)
96 96 96 b 3 2- les paramètres effectifs sont
copiés dans les paramètres
98 98 98
formels (ceux-ci sont donc
100 100 100 effectivement déclarés)
102 102 102 3- exécution de la fonction :
…… …… …… 3-1 déclaration des variables
Réservation Instruction 1 Instruction 2 locales
3-2 exécution des instructions
d’une zone (zone mémoire (zone mémoire de 4- retour vers la fonction
mémoire pour la de la fonction la fonction main) appelante, la zone mémoire est
fonction main main) alors libérée, et la fonction
appelante reprend la main.
Les structures de Données en langage C- Eléments de cours - 21 -
Saloua Guezguez

float puissance (float x, int n)


{
float p=1 ;
int i ;
for(i=1 ;i<=n ;i++)
p*=x ;
return p ;
}

@ @ @ @
….. ….. ….. …..
48 48 48 48
50 50 50 50
52 52 n 3 52 n 3 52 n 3
54 54 54 54
56 56 56 56
58 58 x 5 58 x 5 58 x 5
60 60 60 60
62 62 62 62
64 64 64 i 64 i 4
66 66 66 66
68 68 68 p 1 68 p 125
70 70 70 70
…… …… …… ……
Etape 1 Etape 2 Etape 3 Etape 3
Réservation d’une Copie des Exécution Exécution
zone mémoire pour paramètres
la fonction effectifs dans les
puissance paramètres formels 3-1 déclaration des 3-2 Exécution des
( x reçoit la valeur variables locales p et i instructions
de a et n reçoit la
valeur de b)
Cette étape peut être
vue comme une
déclaration de x et
de n :
float x= a;
int n=b ;
Les structures de Données en langage C- Eléments de cours - 22 -
Saloua Guezguez
@
…..
80
82
84 a 5
86 Etape 4
88 res 125 Retour vers la fonction appelante, l’instruction return a permis de
90 remplacer l’appel de la fonction par la valeur qu’elle a retournée. Celle-ci est
92 donc affectée à la variable res (qui est une variable locale à la fonction main).
94 La zone mémoire réservée à la fonction puissance est libérée, les paramètres
96 b 3 formels ainsi que les variables locales n’ont plus aucune existence en mémoire.
98 Ils seront re déclarés à la suite d’un autre éventuel appel à la fonction.
100
102
……
Les structures de Données en langage C- Eléments de cours - 23 -
Saloua Guezguez
Utilisation des pointeurs lors du passage de paramètres

Considérons l’exemple suivant :


void permut (int x, int y)
{
int temp=x ;
x=y ;
y=temp ;
}

void main()
{
int a=3, b=5 ;
permut(a,b) ;
printf(« a=%d, b=%d », a, b) ;
}
@. @ @ @
….. ….. ….. …..
46 b 5 78 x 3 78 x 5 46 b 5
48 80 80 48
50 82 82 50
52 84 84 52
54 a 3 Appel 86 86 Retour 54 a 3
56 88 88 56
58 90 y 5 90 y 3 58
60 92 92 60
62 94 temp 3 94 temp 3 62
64 96 96 64
66 98 98 66
68 100 100 68
…… …… …… ……
Réservation d’une Zone mémoire de la Exécution de la Il n’y a eu aucune
zone mémoire pour fonction permut : fonction : les valeurs modification dans les
la fonction main, Déclaration des de x et y sont variables appartenant
déclaration des paramètres formels échangées à la zone mémoire de
variables locales et des variables la fonction main !!
locales
La fonction main, en reprenant son exécution va afficher (a=3, b=5). L’appel de la fonction permut,
bien qu’ayant reçu comme arguments les variables a et b, n’a pas permis de modifier les valeurs des
variables a et b. En fait, les paramètres formels ont reçu les valeurs des variables a et b, mais la
modification de x et y n’a eu aucun effet sur a et b. Le problème c’est qu’en mémoire il n’y a aucune
relation entre x et y d’une part et a et b d’autre part.
a et b sont des variables locales à la fonction main, elles ont été déclarées à l’intérieur de la zone
mémoire réservée à cette fonction. L’appel de la fonction permut a provoqué la déclaration de x et y
(paramètres formels) à l’intérieur d’une autre zone mémoire, de la manière suivante :
int x=a (3); //x a reçu la valeur de a lors de la copie
int y=b (5); //y a reçu la valeur de b

Exécution
x=5, y=3 //il y a eu permutation des valeurs de x et y

Retour
Les structures de Données en langage C- Eléments de cours - 24 -
Saloua Guezguez
La zone mémoire de la fonction est libérée (x et y n’existent plus en mémoire)
On retourne donc à la zone mémoire de la fonction main où les valeurs de a et b n’ont pas été
modifiées.

Solution
Il faut créer une relation en mémoire entre les paramètres effectifs et les paramètres formels, de
telle sorte que la modification des paramètres formels entraîne la modification des paramètres
effectifs. On a vu dans le cours sur les pointeurs qu’il est possible de modifier la valeur d’une
variable à travers un pointeur, à condition de stocker l’adresse de la variable dans le pointeur.
Par exemple :
int a =3 ; //variable simple de type entier
int *x=&a ; //pointeur x sur la variable a
*x=5 ; //*x désigne la case mémoire pointée par x (donc a) a=5 !!

En appliquant ce même principe aux fonctions, au lieu de copier dans x et y les valeurs de a et de b,
on va copier les adresses de a et b dans x et y, à condition que x et y soient des pointeurs sur entier.
Ça donne :

void permut (int *x, int *y)


{
int temp=*x ;
*x=*y ;
*y=temp ;
}

void main()
{
int a=3, b=5 ;
permut(&a,&b) ;
printf(« a=%d, b=%d », a, b) ;
}

@ @ @ @
….. ….. ….. …..
46 b 5 78 x 54 78 x 54 46 b 3
48 80 80 48
50 82 82
52 50
84 84
54 a 3 86 86 52
56 Appel 88 88 54 a
58
5
90 y 46 90 y 46 56
60
62 92 92 58
64 94 temp 3 94 temp 3 60
66 96 96 62
68 98 98 64
100 100 66
……
Réservation d’une …… …… 68
zone mémoire pour Zone mémoire de la ……
la fonction main, fonction permut :
déclaration des Déclaration des Exécution de la fonction : les valeurs de *x et *y
variables locales paramètres formels sont échangées, *x n’est autre que la variable a
et des variables de la fonction main et *y n’est autre que b.
locales, x reçoit
l’adresse de a, y
reçoit l’adresse de b
Les structures de Données en langage C- Eléments de cours - 25 -
Saloua Guezguez
Les structures de Données en langage C- Eléments de cours - 26 -
Saloua Guezguez
Les chaînes de caractères en C

Déclaration
En langage C, une chaîne de caractères est un tableau de caractères. La manipulation de ce type de
données est simplifié grâce à des fonctions spécifiques qui permettent de manipuler ces chaînes
comme un tout, en évitant souvent de faire des boucles de parcours, d’affichage etc..

Pour déclarer une chaîne de caractères, on utilise bien évidemment la déclaration des tableaux
classiques.
char A[10] ; // A est une chaîne de 10 caractères au maximum
char B[10]= «bonjour» ; //B est une chaîne de 10 c. initialisée
Une chaîne de caractères contient toujours un caractère spécial noté ‘\0’, c’est le caractère de fin de
chaîne, ainsi la chaîne B déclarée précédemment peut être schématisée comme suit :

‘b’ ‘o’ ‘n’ ‘j’ ‘o’ ‘u’ ‘r’ ‘\0’

Une chaîne de caractères doit donc avoir une case mémoire supplémentaire pour le stockage du
caractère de fin de chaîne.

Ainsi la chaîne de caractères « bonjour » doit être stockée dans un tableau qui contient au moins 8
caractères (la taille de la chaîne+ 1). Donc la déclaration suivante :
char C[7] = « bonjour » ;

donnerait :
‘b’ ‘o’ ‘n’ ‘j’ ‘o’ ‘u’ ‘\0’

le dernier caractère de la chaîne n’a pas pu être stocké et a été remplacé par le caractère de fin de
chaîne.

Une chaîne de caractères peut aussi être déclarée à l’aide d’un pointeur. Exemple : char * A ;

Entrées / Sorties
Il existe dans la bibliothèque standard du C des fonctions d’entrées Sorties spécifiques pour les
chaînes de caractères.
Considérons la chaîne char B[10] ;

Affichage
Une chaîne de caractères peut être affichée à l’écran sans utilisation d’une boucle pour la parcourir.
On peut utiliser la fonction printf avec le format «%s» ou bien utiliser la fonction puts.
La syntaxe est la suivante :
printf («%s», B);//affiche la chaîne B et reste sur la même ligne
ou bien
puts (B);//affiche la chaîne et retourne à la ligne
//équivalent à : printf («%s\n», B) ;

Saisie à partir du clavier


Une chaîne de caractères peut être saisie à partir du clavier sans utilisation d’une boucle pour saisir
caractère par caractère. On peut utiliser la fonction scanf avec le format «%s» ou bien utiliser la
fonction gets.
La syntaxe est la suivante :
scanf («%s», B);//notez l’absence de l’opérateur & car B est une adresse !!
Les structures de Données en langage C- Eléments de cours - 27 -
Saloua Guezguez
ou bien
gets (B); //permet de saisir la chaîne B à partir du clavier
//la fonction gets saisit aussi le ‘\n’ que vous tapez à la fin
//de la saisie, équivalent à : scanf («%s\n», B);

Fonctions spécifiques de la bibliothèque <string.h>


On peut manipuler les chaînes de caractères en utilisant des fonctions prédéfinies, en voici quelques
unes des plus utilisées :

1- longueur d’une chaîne


Il existe une fonction qui calcule la longueur d’une chaîne de caractères. Elle retourne le nombre
de caractères sans compter le ‘\0’, son prototype est le suivant : int strlen (char *) ;

Exemple :
char A[10] = « bonjour » ;
printf(« %d », strlen(A)) ; //le programme affiche « 7 »

Cette fonction sert généralement à parcourir une chaîne, par exemple le programme ci-dessous
permet de calculer le nombre de voyelles et le nombre de consonnes d’une chaîne de caractères.

void voy_cons (char * A, int *nbv, int *nbc)


{
int i, *nbv=0, *nbc=0 ;
for(i=0 ;i<strlen(A) ; i++)
if ((A[i]==’a’)||(A[i]==’e’)||(A[i]==’i’)||
(A[i]==’o’)||(A[i]==’u’)||(A[i]==’y’))
(*nbv)++;
else
(*nbc)++;
}

void main()
{
char chaine[10];
int v,c;
printf(“donner une chaine de caractères:”);
gets(chaine) ;
voy_cons(chaine, &v, &c) ;
printf(« nombre de consonnes =%d\n nombre de voyelles=%d »,c,v) ;
}

2- Copie d’une chaîne dans une autre


La fonction strcpy permet de copier une chaîne source dans une chaîne destination. Cette
fonction écrase le contenu de la chaîne destination, elle est semblable à une affectation dans
d’autres types de données. Sa syntaxe est la suivante : strcpy (char * destination, char *
source) ;
Exemple :
char A[10] = « ABCDE » ;
char B[10] ;
strcpy (B, A) ; //copie la chaîne A dans la chaîne B
puts(B) ; //affiche « ABCDE »
Les structures de Données en langage C- Eléments de cours - 28 -
Saloua Guezguez
La chaîne destination peut être allouée dynamiquement avec la taille exacte de la chaîne source.
Le programme suivant saisit une chaîne au clavier, alloue une deuxième chaîne et réalise la
copie.

void main()
{
char s[10], *d;
printf(“donner une chaine de caractères:”);
gets(s) ;
//réservation de mémoire pour la chaîne d (sa taille doit être au
//moins égale à la taille de s +1 (pour le ‘\0’))
d= (char *) malloc(strlen(s)+1) ; //normalement on multiplie par
//sizeof(char), mais c’est inutile
//car un char occupe un octet
//on réalise la copie
strcpy(d, c) ;
//on affiche la chaîne résultante
puts(« la chaîne copiée est » , d)
}
3- Concaténation de deux chaînes
La fonction strcat permet de concaténer deux chaînes de caractères. Cette opération consiste à
ajouter le contenu d’une chaîne à la suite d’une autre. Sa syntaxe est la suivante : strcat (char *
A, char * B) ; la fonction ajoute le contenu de B à la suite de A (la chaîne A est modifiée). Il faut
donc que la chaîne A soit assez grande pour contenir les deux chaînes.

Exemple :
char A[10] = « ABCDE » ;
char B[10] = « FGH »;
strcat (A,B) ; //ajoute le contenu de B à la fin de A
puts(A) ; //affiche « ABCDEFGH »

4- Comparaison de deux chaînes


La fonction strcmp permet de comparer deux chaînes de caractères. Sa syntaxe est la suivante :
int strcmp (char * A, char * B) ;
Elle retourne un entier, qui peut avoir trois états possibles :
- la valeur de retour est égale à 0 : les deux chaînes sont identiques (A=B)
- la valeur de retour est <0 : La chaîne A précède la chaîne B (dans l’ordre lexicographique,
c'est-à-dire celui d’un dictionnaire) (A<B)
- la valeur de retour est >0 : La chaîne A suit la chaîne B. (A>B)
Exemple :
char A[10] = « ABCDE » ;
char B[10] = « AC »; on a alors A<B

char A[10] = « ABCDE » ;


char B[10] = « AAAAAAA »; on a alors A>B

char A[10] = « ABCDE » ;


char B[10] = « ABCDE »; on a alors A=B
Les structures de Données en langage C- Eléments de cours - 29 -
Saloua Guezguez
Les enregistrements en C

Intérêt

En programmation, les données utilisées sont en général composées de plusieurs informations de


types éventuellement différents. Pour manipuler des données composées, il faut commencer par
définir le type de ces données. Ces types composés sont appelés enregistrements (ou structures). Par
exemple, si on désire écrire un programme qui gère une bibliothèque (entrées /sorties de livres,
emprunts, stock…) alors les données manipulées sont de type «livre». Un livre est composé de
plusieurs informations telles que son code (de type entier), son auteur (de type chaîne de
caractères), et son titre (de type chaîne de caractères), etc… De même, dans un programme qui
permet de calculer les salaires des employés d’une entreprise, les données manipulées sont de type
«employé». Un employé est composé de plusieurs informations telles que son matricule (entier), son
nom (chaîne de caractères), son salaire de base (réel), etc…Les exemples sont alors multiples et
divers.

Dans ce qui suit, nous allons considérer le type composé « livre ».

Déclaration d’un type composé


En langage C, un enregistrement est déclaré avec le mot réservé « struct ».
struct livre
{
int code ;
char titre[20] ;
char auteur[20] ;
};

Pour déclarer une variable de type livre il faut alors écrire : struct livre l ;
Il est aussi possible de redéfinir le type composé et de l’appeler simplement livre, pour alléger les
déclarations de variables :

typedef struct
{
int code ;
char titre[20] ;
char auteur[20] ;
} livre;

Pour déclarer une variable de type livre il suffit alors d’écrire : livre l ;

La définition de l’enregistrement n’implique aucune réservation en mémoire. Il s’agît d’indiquer au


compilateur de quoi seront composées les variables de type livre. Par contre l’écriture : livre l ;
entraîne réellement la réservation d’un emplacement mémoire pour la variable l qui va occuper tout
l’espace nécessaire pour l’enregistrement, c'est-à-dire un entier, et deux pointeurs sur deux chaînes
de 20 caractères chacune, comme le montre le schéma mémoire suivant.
Les structures de Données en langage C- Eléments de cours - 30 -
Saloua Guezguez
variable l

…. 58 60 62 64 66 68 70 72 …..
code titre auteur

100 102 104 106 108 110 112 114 116 118 120 122 124 126 128 130 132 134 136 138 140 142

…. 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 …

Chaque variable de type livre est donc constituée d’un code (entier), d’un auteur (pointeur sur un
tableau de 20 caractères) et d’un titre (pointeur sur un tableau de 20 caractères).

Accès aux champs d’un enregistrement


Pour accéder aux champs d’une variable composée, on utilise l’opérateur "."
Ainsi, pour la variable l déclarée précédemment,
l.code désigne le champ code de la variable l
l.titre désigne le champ titre de la variable l
l.auteur désigne le champ auteur de la variable l
Considérons à présent a situation suivante :
livre l ;
livre *p = &l ; //p est un pointeur sur livre, il contient
//l’adresse mémoire de la variable l.

En fait, p n’est pas une variable composée, mais contient l’adresse d’une variable composée. Il est
possible d’accéder aux champs d’une variable composée à travers un pointeur, en utilisant
l’opérateur "->"
Ainsi,
p->code désigne le champ code de la variable pointée par p
p->titre désigne le champ titre de la variable pointée par p
p->auteur désigne le champ auteur de la variable pointée par p

Entrées/Sorties
Les données de type enregistrement peuvent être affichées à l’écran ou saisies à partir du clavier, et
ceci champ par champ. Le mieux c’est de prévoir des fonctions spécifiques pour la saisie et
l’affichage.

Affichage à l’écran

void affichlivre (livre l)


{
printf ("code = %d\n", l.code);
printf ("titre=%s\n",l.titre);
printf ("auteur=%s\n",l.auteur);
}
Les structures de Données en langage C- Eléments de cours - 31 -
Saloua Guezguez

Saisie à partir du clavier

void saisirlivre (livre *l)


{
printf ("code ="); scanf ("%d", &l->code);
printf ("titre="); scanf("%s", l->titre);
printf ("auteur=");scanf ("%s", l->auteur);
}

- le paramètre formel est un pointeur car la fonction va le modifier


- pas de symbole & dans la saisie des deux chaînes de caractères titre et auteur car ce sont
déjà des pointeurs!!

une utilisation possible de ces fonctions :

void main()
{
livre l;
printf("saisir un livre :\n");
saisirlivre (&l);
printf("voici le livre saisi \n");
affichlivre (l);
}

Structures imbriquées
Si on veut ajouter à la structure livre un champ date d'édition, il faut commencer par définir un type
date, composé d'un champ jour, d'un champ mois et d'un champ annee.

typedef struct
{
int jour;
char mois[10];
int annee;
}date;

typedef struct
{
int code ;
char titre[20] ;
char auteur[20] ;
date dat_edition; //champ de type date
} livre;

considérons une variable l de type livre, on a donc :


l.code désigne le champ code de la variable l
l.titre désigne le champ titre de la variable l
l.auteur désigne le champ auteur de la variable l
l.dat_edition désigne le champ dat_edition de la variable l
l.dat_edition.jour désigne le champ jour du champ dat_edition de la variable l
Les structures de Données en langage C- Eléments de cours - 32 -
Saloua Guezguez
l.dat_edition.mois désigne le champ mois du champ dat_edition de la variable l
l.dat_edition.annee désigne le champ annee du champ dat_edition de la variable l

de même, si on considère le pointeur p sur la structure livre, on a :


p->code désigne le champ code de la variable pointée par p
p->titre désigne le champ titre de la variable pointée par p
p->auteur désigne le champ auteur de la variable pointée par p
p->dat_edition désigne le champ dat_edition de la variable pointée par p
p->dat_edition.jour désigne le champ jour du champ dat_edition de la variable pointée par p
p->dat_edition.mois désigne le champ mois du champ dat_edition de la variable pointée par p
p->dat_edition.annee désigne le champ annee du champ dat_edition de la variable pointée par p

la fonction d'affichage devient alors :

void affichlivre (livre l)


{
printf ("code = %d\n", l.code);
printf("titre=%s\n",l.titre);
printf("auteur=%s\n",l.auteur);
printf("date d'edition =%d %s %d\n", l.dat_edition.jour,
l.dat_edition.mois, l.dat_edition.annee);
}

la fonction de remplissage devient :

void saisirlivre (livre *l)


{
printf ("code ="); scanf("%d", &l->code);
printf("titre="); scanf ("%s", l->titre);
printf("auteur="); scanf("%s", l->auteur);
printf("date d'edition :\n");
printf ("jour="); scanf ("%d", &l->dat_edition.jour);
printf ("mois="); scanf ("%s", l->dat_edition.mois);
printf("annee"); scanf ("%d", &l->dat_edition.annee);
}
Tableaux de structures
Une fois le type composé défini, il est possible de stocker un ensemble de données de ce type dans
une structure de données comme un tableau. Il suffit pour cela de déclarer un tableau de type
composé avec une allocation statique ou dynamique.

livre tab[10]; //tab est un tableau où on peut stocker jusqu'à 10 données de type livre.
livre *tab; //le nombre de données stockées peut être déterminé avec une allocation dynamique
chaque case du tableau est de type livre c'est à dire qu'elle est constituée de tous les champs cités
précédemment, ainsi, pour un élément tab[i] du tableau, on a :

tab[i].code désigne le champ code de la case tab[i] du tableau tab


tab[i].titre désigne le champ titre de la case tab[i] du tableau tab
tab[i].auteur désigne le champ auteur de la case tab[i] du tableau tab
tab[i].dat_edition désigne le champ dat_edition de la case tab[i] du tableau tab
tab[i].dat_edition.jour désigne le champ jour du champ dat_edition de la case tab[i] du tableau tab
tab[i].dat_edition.mois désigne le champ mois du champ dat_edition de la case tab[i] du tableau tab
tab[i].dat_edition.annee désigne le champ annee du champ dat_edition de la case tab[i] du tableau
Les structures de Données en langage C- Eléments de cours - 33 -
Saloua Guezguez

Affichage d'un tableau de structures

void affichtablivres (livre *tab, int n)


{
int i;
for(i=0;i<n;i++)
{
printf("voici le livre numero %d:\n", i+1)
affichlivre (tab[i]);
}
}

Remplissage d'un tableau de structures

void saisirtablivre (livre *tab, int n)


{
int i;
for(i=0;i<n;i++)
{
printf("saisir le livre numero %d:\n", i+1)
saisirlivre (&tab[i]);
}
}

deux utilisations possibles :

void main()
{
livre tab[5];
saisirtablivre(tab, 5);
affichtablivre(tab, 5);
}

ou bien avec une allocation dynamique :


void main()
{
livre *tab; int n;
printf("combien de livres :"); scanf ("%d", &n);
tab=(livre *) malloc(n*sizeof(livre));
saisirtablivre(tab, n);
affichtablivre(tab, n);
}

Vous aimerez peut-être aussi