Вы находитесь на странице: 1из 8

Langage C

Séance 8 : Structures


1  Structures
1.1  Introduction

Structures : nouveau type de variable permettant de regrouper


différents champs (ou enregistrements) de types différents ou pas.
Exemples :

 nombres complexes : couple de deux variables float;


 dates : 3 informations, jour (int), mois (chaine de caractères), année (int).
 étudiant : nom, prénom, date de naissance.

Dans le dernier exemple, la structure "étudiant" contiendra une structure "date".


Avantage : regrouper des informations liées pour éviter de multiplier les variables
et bien faire apparaitre la logique du traitement : il est plus simple de comprendre
un programme qui manipule des dates qu'un programme qui manipule trois
variables de types différents.

1.2  Déclaration d'un type structure en langage C

En langage C, on créera d'abord un nouveau type de variables structures auquel on


donnera un nom ("date", "etudiant", ...) et pour lequel on spécifiera la liste des
champs (nom et type de chaque champ).
Le type structure est déclaré en dehors des fonctions, en général dans un fichier
d'en-tête .h.
Le mot clef typedef commence la déclaration d'un nouveau type :
typedef struct { 
    float x; /* partie reelle */
    float y; /* partie imaginaire */
} complexe;

Il est d'usage de commenter chaque champ pour expliciter l'information qu'il va


contenir.
Autre exemple :
typedef struct date {
    int  jour;     /* entre 1 et 31 */
    char mois[20]; /* nom du mois "janvier", "fevrier", ... */
    int  annee;    /* 1999, 2000, ... */
} date;

Notez que l'on pourrait choisir une autre représentation pour les dates; par exemple,
le mois pourrait être codé par un nombre entier compris entre 1 et 12.
Un structure peut contenir une autre structure, qui doit avoir été déclarée avant :
typedef struct {
    char nom[32];
    char prenom[32];
    date date_naissance;
} etudiant;

Les champs peuvent donc être de n'importe quel type connu : types de bases,
tableaux, pointeurs ou autre structure.

1.3  Déclaration d'une variable structure

Après avoir déclaré un type structure, on peut l'utiliser pour déclarer des variables
de ce type dans nos fonctions C. Le nouveau type s'utilise comme un type de base.
void main(void) {
  int          n; /* un entier */
  etudiant     E; /* un etudiant */
  etudiant     Robert; / un autre etudiant */

  ...
}

On peut aussi déclarer un pointeur sur une structure :


  int         *pn;  /* un pointeur sur un entier */
  etudiant    *pE;  /* un pointeur sur un etudiant */

Lors de la déclaration de la variable, on peut initialiser les champs, avec une


notation semblable à celle utilisée pour les tableaux :
  complexe Z = { 12, 0.5 }; /* Z =  12 + 0.5 i */

1.4  Accès aux champs d'une structure

 Si E est une variable de type structure (déclarée


comme etudiant E), E.nom représente le champ nom de la structure E.

E.nom s'utilise
comme une variable ordinaire (dans cet exemple c'est un
tableau de caractères).

 Si on a un pointeur sur une structure, comme par exemple etudiant *pE, on


peut accéder au champs de deux façons :
o (*pE).nom : car *pE représente la structure pointée par pE (autrement
dit, dont l'adresse est pE).
o pE->nom : notation spécialisée équivalente, qui est un raccourci très
pratique. La flèche -> indique que l'on suit le pointeur pour arriver au
champ.

Exemple :
complexe z;  /* un nombre complexe (voir plus haut) */
complexe *pz; = &z; /* un pointeur sur z */

z.x = 1;            /* accede au champ x de z */
z.y = 2;

printf("partie reelle de z = %f\n", pz-> x ); /* affiche 1 */

pz->y = z.x + 3; /* <=> z.y = z.x + 3 */

(*pz).x = 22;    /* <=> pz->x = 22 ou bien z.x = 22 */

1.5  Passage d'une structure en paramètre

Une fonction peut prendre une variable structure en paramètre.


On peut passer par valeur
void Affiche( etudiant E );

ou par adresse :
void Affiche( etudiant *pE );

On préférera toujours la deuxième solution, qui évite la duplication de la structure


sur la pile (opération qui peut être couteuse, voire impossible si la structure occupe
une taille mémoire importante).
Dans la fonction, on utilise alors la notation ->.

1.6  Tableaux de structures

S'utilise exactement comme un tableau normal.


Exemple : un tableau T de 10 nombres complexes :
complexe T[10];
T[0].x = 1; /* la partie reelle du 1er nombre complexe de T */

2  Gestion d'une pile


Afin d'illustrer l'utilisation des structures en langage C, nous allons définir une
petite bibliothèque permettant de définir et manipuler un type "pile".
Une pile est une structure de données qui contient un ensemble d'objets du même
type, sur laquelle on défini deux opérations principales :

 empiler un nouvel objet, qui sera placé au "sommet" de la pile;


 dépiler un objet; le dernier objet empilé (le sommet) est enlevé de la pile et
renvoyé.

Nous avons vu un exemple de pile dans le cours d'Architecture des Ordinateurs.


Ce genre de pile s'appelle pile LIFO, pour Last In First Out : le premier élément
dépilé (first out) est le dernier qui avait été empilé (last in).
La traduction anglaise du mot "pile" est "stack".
En langage C, une pile sera représentée par un structure contenant un tableau de
taille donnée (la capacité maximale de la pile) et un index indiquant la position du
sommet de la pile dans le tableau :
typedef struct {
    float T[100];  /* pile contenant des floats, max 100 */
    int   sommet;  /* index du sommet, -1 si pile vide */
} pile;

Les opérations (réalisées par des fonctions) seront les suivantes :

 void init_pile( pile *p ) : initialise la pile (vide).


 int est_vide( pile *p ) : renvoie 1 si la pile est vide, 0 sinon.
 int est_pleine( pile *p ) : renvoie 1 si la pile est pleine, 0 sinon.
 void empiler( pile *p, float v ) : place la valeur v sur la pile;
 float depiler( pile *p ) : dépile une valeur et la renvoie.
 void afficher( pile *p ) : affiche l'état de la pile (utilisé pour les tests).

Nous donnons à la suite le programme C complet, pour une pile de 100 nombre
réels.

 pile.h :
définition du type pile (struct), et prototypes des fonctions
manipulant ce type.
 pile.c : corps des fonctions (implémentation);
 expile.c : un petit exemple pour tester notre pile.

Remarques

1. Pour définir une pile avec un autre type d'éléments, il suffit de changer le
type du tableau T et les prototypes de quelques fonctions.
2. Les noms de nos fonctions ne sont pas très judicieux, car ils risquent d'être
utilisés par d'autres bibliothèques (files, listes, ...). Il aurait été préférable
d'utiliser des noms plus spécifiques, comme par
exemple pile_init, pile_empiler, etc.
3. L'ensemble formé par la définition d'un type et les fonctions le manipulant,
qui définissent les opérations que l'on peut effectuer sur des variables de ce
type, est ce que l'on appele en informatique un "objet". Nous reviendrons sur
la notion d'objet lors de l'étude du langage JAVA.

Listings des programmes

fichier progs/pile.h
/* -------------------------------------------------------------
 * File.........: pile.h
 * 
 * Author.......: Emmanuel Viennet, GTR1 1999-00
 * 
 * Created......: Tue Jan 18 23:03:17 2000
 * 
 * Description..: Exemple de gestion d'une pile de nombre reels
 * 
 * -------------------------------------------------------------
 */
/* definition de la structure pile : */
typedef struct {
float T[100];  /* pile contenant des floats, max 100 */
int   sommet;  /* index du sommet, -1 si pile vide */
} pile;

void  init_pile( pile *p );
int   est_vide( pile *p );
int   est_pleine( pile *p );
void  empiler( pile *p, float v );
float depiler( pile *p );

void  afficher( pile *p ); /* pour les tests */

fin du fichier progs/pile.h


fichier progs/pile.c
/* ------------------------------------------------------------
 * File.........: pile.c
 * 
 * Author.......: Emmanuel Viennet, GTR1 1999-00
 * 
 * Created......: Tue Jan 18 22:57:06 2000
 * 
 * Description..: Exemple de gestion d'une pile de nombre reels
 * 
 * -------------------------------------------------------------
 */

#include <stdio.h>

#include "pile.h"

void init_pile( pile *p ) {
p->sommet = -1;
}

int est_vide( pile *p ) {
if (p->sommet == -1)
return 1;
else
return 0;
}

int est_pleine( pile *p ) {
if (p->sommet == 99) /* notre pile contient au max 100 elements */
return 1;
else
return 0;
}

void empiler( pile *p, float v ) {
if (est_pleine(p)) {
printf("erreur: empiler: la pile est pleine\n");
return; /* ne fait rien */
}
p->sommet = p->sommet + 1;
p->T[ p->sommet ] = v;
}
float depiler( pile *p ) {
float resultat;
if (est_vide(p)) {
printf("erreur: depiler: la pile est vide\n");
return 0; /* ? renvoie 0 */
/* note: on pourrait appeler exit(1); pour terminer
   le programme */
}
resultat = p->T[ p->sommet ];
p->sommet = p->sommet-1;
return resultat;
}

/* Affiche l'etat de la pile,
   pratique pour les tests 
 */
void  afficher( pile *p ) {
int i;
printf("etat de la pile:\n");

/* on utilise la pile comme un tableau */
for (i=0; i <= p->sommet; i++)
printf("\t[ %3.2f ]\n", p->T[i] );
}

fin du fichier progs/pile.c


fichier progs/expile.c
/* -----------------------------------------------------
 * File.........: expile.c
 * 
 * Author.......: Emmanuel Viennet, GTR1 1999-00
 * 
 * Created......: Tue Jan 18 23:05:06 2000
 * 
 * Description..: Exemple utilisation de pile
 *
 * ------------------------------------------------------
 */

#include "pile.h"

void main(void) {
pile MaPile;

/* on doit toujours initialiser la pile avant tout: */
init_pile( &MaPile );

empiler( &MaPile, 22);
empiler( &MaPile, 314);
empiler( &MaPile, 1000 );
afficher( &MaPile );

printf("on depile %f\n", depiler( &MaPile ) );
afficher( &MaPile );
printf("on depile %f\n", depiler( &MaPile ) );
printf("on depile %f\n", depiler( &MaPile ) );
printf("on depile %f\n", depiler( &MaPile ) );
}
fin du fichier progs/expile.c

EXERCICE 1 - Structures 
1-  Donner les déclarations des structures suivantes :

1. date : numéro du jour, nom du mois, année;


2. point : coordonnées (entières) d'un point;
3. rect : coordonnées d'un rectangle (côtés horizontaux);
4. segment : segment entre deux points.

2-  Écrire le corps d'une fonction AfficheDate affichant la date passée en paramètre.


Prototype : void AfficheDate( date *dp );

3-  Écrire une fonction DemandeDate demandant une date au clavier et remplissant


les champs de la structure passée.
Prototype : void DemandeDate( date *dp );

4-  Écrire une fonction NumeroMois retournant l'entier compris entre 1 et 12


correspondant au numero du mois dont le nom est passé. Si le mois n'existe
pas, NumeroMois doit retourner -1.
Prototype : int NumeroMois( char *nommois ); A l'aide de cette fonction,
améliorer la fonction DemandeDate afin qu'elle vérifie que la date entrée est
correcte.

5-  Écrire une fonction CompareDates prenant deux dates d1 et d2 et retournant -1


si d1 est avant d2, 1 si d1 est après d2, ou 0 si les deux dates sont égales.
Prototype : int CompareDates( date *d1, date *d2 );

EXERCICE 2 - Fichiers textes

1-  Écrire une fonction


 int EnregistreDates( date d[], int N, char *nomfichier );

qui sauvegarde un tableau d de N dates dans un nouveau fichier texte. La fonction


retournera 1 en cas de succès, 0 en cas d'échec (erreur).
Chaque ligne du fichier texte contiendra une date: jour, mois, année.

2-  Écrire une fonction


 int LireDates( date d[], int nbmax, char *nomfichier );

qui relise dans le tableau d les dates sauvegardées dans le fichier spécifié


par nomfichier par EnregistreDates. LireDates retournera le nombre de dates
lues. nbmax spécifie la taille du tableau, donc le nombre maximum d'éléments à lire.
EXERCICE 3 - L'algorithme de tri par sélection permet de trier les éléments d'un
tableau par ordre croissant (ou décroissant). Il peut être décrit comme suit, pour un
tableau T de N éléments :
Pour i = 0 à N-1 faire
         chercher l'élément le plus petit dans l'intervalle i, ..., N et
         l'échanger avec l'élément T[i].

1-  Dérouler à la main l'algorithme sur l'exemple suivant : { 1, 9, 2, 1, 7 }.

2-  Écrire une fonction TriEntiers triant un tableau de N entiers.


Prototype : void TriEntiers( int T[], int N );

3-  Écrire une fonction TriDates triant un tableau de N dates (définies comme dans


l'exercice 1), en utilisant la fonction CompareDates
Prototype : void TriDates( date T[], int N );

File translated from TEX by TTH, version 3.66.


On 17 Jan 2005, 11:37.

http://www-gtr.iutv.univ-paris13.fr/Cours/Mat/LangageC/TD2004/td08.html
http://www-gtr.iutv.univ-paris13.fr/Cours/Mat/LangageC/TD2004/td07.html

Вам также может понравиться