Les structures

N'hésitez pas à donner vos avis par rapport à ce tutoriel : Commentez Donner une note à l'article (0)

Article lu   fois.

L'auteur

Profil Pro

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Structure

I-A. Qu'est-ce qu’une structure ?

La structure en programmation est un type de données qui permet de regrouper en une seule unité plusieurs variables éventuellement de types différents. C'est UNE variable qui est un ensemble de variables. C'est très utile pour composer des objets complexes qui réunissent différentes facettes. Par exemple, si l'on veut faire un carnet de rendez-vous, chaque rendez-vous suppose des informations du genre :

  • un libellé ;
  • un lieu ;
  • une date ;
  • un horaire de début ;
  • un horaire de fin ;
  • une catégorie (bureau, perso, loisir, etc.) ;
  • etc.

Toutes ces informations peuvent être regroupées au sein d'une structure et plusieurs structures permettront d'avoir plusieurs rendez-vous. L'intérêt ensuite est de pouvoir avoir un nombre illimité de rendez-vous. Autre exemple dans un jeu vidéo en 2D un ennemi est défini par une position, un déplacement, un type (rampant, grouillant, serpentant, plombant, assommant), un taux d'agressivité, une couleur, une ou plusieurs images, etc.

Pour chacune de ces informations, il s'agit premièrement de choisir un type de variable approprié et ensuite de regrouper toutes ces informations au sein d'une structure « ennemi » afin de pouvoir gérer un ou plusieurs ennemis dans le jeu. Chaque élément de la structure est appelé un « champ ». Notre structure rendez-vous a au moins six champs et la structure ennemie au moins huit champs (position et déplacement horizontaux et verticaux, type…).

I-B. Disposer d’une structure dans un programme

I-B-1. Définir un type de structure

À la base pour définir une structure, on utilise le mot-clé struct suivi d’une liste de déclarations de variables (sans initialisation) entre accolades et d'un point-virgule :

 
Sélectionnez
struct {
float x,y; // attention pas possible d'initialiser
float dx,dy; // ses variables lors de la définition
int color; // de la structure
char lettre;
};

Tel quel c'est bien un type de structure, mais comme il n'a pas de nom, il n'est pas possible de l'utiliser dans tout le programme. Pour nommer son type de structure, il suffit d'ajouter le nom voulu après le mot-clé struct :

 
Sélectionnez
struct entite { // nommer son type de structure
float x,y;
float dx,dy;
int color;
char lettre;
};

Nous venons de définir le type de structure « struct entite ». Attention c'est un nom de type, cela ne correspond pas à une variable, mais à un type de variable.

I-B-2. Où placer sa définition de structure

En général la définition d'un type de structure se place en global. Au début du fichier juste après les includes si le programme tient sur un seul fichier C. S'il y a plusieurs fichiers C cette définition sera placée dans un fichier d'en-tête .h et ce fichier d'en-tête sera inclus dans tous les fichiers C de code qui ont besoin de cette définition pour fonctionner.

Il est possible de définir un type de structure dans une fonction, mais dans ce cas, ce type ne sera connu que dans le bloc de la fonction et invisible partout ailleurs.

I-B-3. Déclarer ses variables structure

Après avoir défini un type de structure, pour avoir des variables de ce type, c'est identique aux autres variables. Il faut indiquer le type, donner un nom pour la variable et clore avec un point-virgule.

Pour avoir des variables du type struct entite défini ci-dessus, nous écrirons quelque part dans le programme :

 
Sélectionnez
struct entite e1, e2;

e1 et e2 sont deux variables du type struct entite.

Remarque 

Le nom du type de la structure est indépendant de celui de la variable de ce type et il est possible d'avoir une variable du même nom :

 
Sélectionnez
struct entite entite; // fonctionne

Par ailleurs il est possible de combiner une définition de type de structure et des déclarations de variables de ce type de structure. La définition de la structure pix ci-dessous peut être suivie d’une suite de déclarations de variables :

 
Sélectionnez
struct pix{
int x, y;
int color;
}P1, P2, toto;

La définition de la structure struct pix est suivie des déclarations des variables P1, P2 et toto qui sont trois variables de type struct pix.

I-B-4. Utiliser un typedef

Lorsque l'on utilise des structures en environnement C, il est fastidieux de toujours devoir ajouter le mot-clé struct. Le typedef permet de s'en débarrasser.

La commande typedef donne la possibilité de définir ses propres types à partir des types de base. Le principe est simple : déclarer une variable du type voulu, ajouter typedef devant… et le nom de la variable devient synonyme du type de cette variable. Par exemple :

 
Sélectionnez
typedef int toto;

permet de définir le type « toto » dans un programme ; toto devient synonyme de int et peut être utilisé à la place dans le programme :

 
Sélectionnez
#include <stdio.h>
#include <stdlib.h>
typedef int toto; // création du type toto
int main()
{
toto test = 80;
printf("la variable test vaut : %d\n", test);
system("PAUSE");
return 0;
}

L'intérêt de pouvoir rebaptiser ses types dépend de certaines situations, par exemple créer un langage en français. Mais dans un environnement C typedef est utilisé systématiquement avec les structures afin de faire disparaître le mot-clé struct.

Soit par exemple le type struct ennemi dans un programme :

 
Sélectionnez
struct ennemi{
char type; // type de l'ennemi (une lettre)
float nuisance; // potentiel de nuisance
float x,y,px,py; // position et déplacement
int force; // indicateur de force pour les combats
};

En ajoutant le mot-clé typedef devant, on peut définir un synonyme de struct ennemi de la façon suivante :

 
Sélectionnez
typedef struct ennemi{
char type;
float nuisance;
float x,y,px,py;
int force;
}t_ennemi;

et de façon plus concise, on peut définir directement son type de structure :

 
Sélectionnez
typedef struct{
char type;
float nuisance;
float x,y,px,py;
int force;
}t_ennemi;

t_ennemi devient nom de type pour la structure dans les deux cas du fait de l'utilisation de typedef et t_ennemi peut être utilisé partout dans le programme :

 
Sélectionnez
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
t_ennemi E;
int i;
srand(time(NULL));
E=init_ennemi();
affiche_ennemi(E);
return 0;
}

Le préfixe t_ est pratique. Il permet de préciser qu'il s'agit d'un type et non d'un nom de variable. Cela n'a rien d'obligatoire.

Déclarer ses variables structure en C++

Dans un environnement C++, c’est-à-dire sur un fichier de code .cpp, la définition d’une structure est la même :

 
Sélectionnez
struct entite {
float x,y;
float dx,dy;
int color ;
char lettre;
};

Mais le mot-clé struct est inutile lors de la déclaration d'une structure, il y a en quelque sorte l'utilisation implicite d'un typedef. Au lieu d'écrire comme en C :

 
Sélectionnez
struct entite e1;

nous pouvons écrire directement :

 
Sélectionnez
entite e1;

Jusqu'au chapitre sur le C++ nous restons dans cet ouvrage en C pur et d'une façon générale nous supprimons le mot-clé struct à la déclaration d'une structure avec l'utilisation d'un typedef.

I-C. Utiliser une structure

I-C-1. Accès aux éléments avec l'opérateur point

Toutes les variables d’une structure, c'est-à-dire tous les champs de la structure, sont accessibles via l’opérateur « . » dit « point » de la façon suivante :

 
Sélectionnez
struct pix p;
p.x = 0;
p.y = 50;
p.color = 255;

La première ligne déclare une structure du type struct pix nommée p. Les trois lignes suivantes initialisent chacun des champs de la variable p. Le champ x prend la valeur 0, le champ y prend la valeur 50 et le champ color la valeur 255.

I-C-2. Priorité de l'opérateur point

Priorité maximum, tous les autres opérateurs passent après dans l'évaluation d'une expression (cf. Annexe Priorité et associativité des opérateurs).

I-C-3. Une structure comme champ dans une structure

L'imbrication de structures est possible. Une structure peut avoir une autre structure comme champ à condition que son type soit connu au moment de la définition de la structure. Par exemple :

 
Sélectionnez
typedef struct rgb{ // valeur de rouge, de vert et de bleu
int r,g,b; // pour avoir une couleur
}rgb;
typedef struct coord{
int x, y; // pour stocker une position en 2D
}coord;
typedef struct rectangle{
coord hg; // coord du coin haut gauche
coord bd; // coord du coin bas droite
rgb color; // couleur du rect
}rectangle;

La structure rectangle permet de stocker les informations de rectangles colorés. La structure rgb concentre les informations de couleurs avec trois champs, un entier pour le rouge, un entier pour le vert et un entier pour le bleu (en RGB - red, green, blue - une couleur est obtenue par un mélange de rouge, de vert et de bleu). La structure coord permet de stocker les coordonnées d’un point dans un espace à deux dimensions. Pour dessiner un rectangle nous avons besoin de deux points, le point en haut et à gauche et le point en bas et à droite :

Image non disponible

La structure finale pour stocker les informations d’un rectangle comprend une structure rgb pour sa couleur et deux structures coord pour chacun des points haut gauche (hg) et bas droite (bd).

Dans cet exemple les structures rgb et coord doivent absolument être définies avant la structure rectangle pour y être connues au moment de sa définition. Dans le cas contraire, il y aura une erreur à la compilation.

L’accès aux champs d’une structure se fait avec l’opérateur . (point) et rien ne change si le champ est lui-même une structure. L’opérateur point sera utilisé une nouvelle fois pour accéder aux champs de la structure élément de la façon suivante :

 
Sélectionnez
rectangle r1;
    r1.hg.x = 0;
    r1.hg.y = 0;
    r1.bd.x = 100;
    r1.bd.y = 50;
    r1.color.r = 255;
    r1.color.g = r1.color.b = 0;

Le type de l’expression r1.hg par exemple est une structure du type coord et on accède à chacun de ses champs en utilisant une nouvelle fois l’opérateur point, soit les expressions e1.hg.x et e1.hg.y et les parenthèses sont inutiles.

I-C-4. Initialiser une structure à la déclaration

Une structure peut être initialisée à la déclaration en lui affectant une suite de valeurs entre accolades closes par un point-virgule. Chaque valeur est affectée à un champ correspondant dans l'ordre et doit en respecter le type. Soit la structure test :

 
Sélectionnez
typedef struct test {
    float x, y;
    int px, py;
    char lettre;
}test;

et une déclaration suivie d’une initialisation dans le programme :

 
Sélectionnez
test t1={ 1.5, 2.0, 150,300,'A'};

Pour la variable t1 de type struct test, 1.5 est affecté au champ x, 2.0 est affecté au champ y, 150 est affecté au champ px, 300 au champ py et le champ lettre prend la valeur 'A'.

Dans le cas de structures imbriquées, il y a le choix entre une seule liste pour les valeurs affectées ou le détail entre accolades pour chaque structure, par exemple :

 
Sélectionnez
typedef struct date{
    int jour, mois, annee;
}date;
typedef struct time{
    int heure, minute, seconde;
}time;
typedef struct moment{
    date date;
    time time;
}moment;

Dans le programme, un exemple de déclaration suivie d’une initialisation :

 
Sélectionnez
moment m1={ 25,12,2006,13,45,30};

Les champs de m1 valent respectivement 25 pour jour, 12 pour mois, 2006 pour année, 13 pour heure, 45 pour minute et 30 pour seconde.

On peut également détailler le contenu de chaque structure imbriquée de la façon suivante :

 
Sélectionnez
moment m1={ {25,12,2006},
        {13,45,30}
    };

Si le nombre des valeurs de la liste est supérieur au nombre des champs, il y a une erreur de compilation. En revanche, si le nombre des valeurs de la liste est inférieur, les champs restants sont initialisés à 0. Ce test permet de le vérifier :

 
Sélectionnez
#include <stdio.h>
#include <stdlib.h>
struct date{
    int jour, mois, annee;
};
struct time{
    int heure, minute, seconde;
};
struct moment{
    struct date date;
    struct time time;
};
int main()
{
struct moment m={{1}, {3,4}};
    printf("m.date.jour=%d\n",m.date.jour);
    printf("m.date.mois=%d\n",m.date.mois);
    printf("m.date.annee=%d\n",m.date.annee);
    printf("m.time.heure=%d\n",m.time.heure);
    printf("m.time.minute=%d\n",m.time.minute);
    printf("m.time.seconde=%d\n",m.time.seconde);
    system("PAUSE");
    return 0;
}

Résultat :

 
Sélectionnez
m.date.jour=1
m.date.mois=0
m.date.annee=0
m.time.heure=3
m.time.minute=4
m.time.seconde=0

I-C-5. Copier une structure

Les copies et les affectations de structure à structure de même type sont autorisées, par exemple :

 
Sélectionnez
coord pt1, pt2;
    pt1.x=100;
    pt1.y=200;

    pt2=pt1;

La structure pt1 est initialisée avec les valeurs 100 et 200, ensuite la structure pt1 est affectée à la structure de même type pt2. Les valeurs de pt1 sont recopiées dans pt2.

I-D. Mise en pratique : définir, déclarer, initialiser des structures

Exercice 1

Une menuiserie industrielle gère un stock de panneaux de bois. Chaque panneau possède une largeur, une longueur et une épaisseur en millimètres ainsi que le type de bois. Il y a trois types de bois : pin (code 0), chêne (code 1), hêtre (code 2).

  • Définir une structure panneau contenant toutes les informations relatives à un panneau de bois ;
  • Dans un programme initialiser deux panneaux à la déclaration et deux panneaux avec des valeurs aléatoires. Afficher les valeurs.

Exercice 2

Un grossiste de composants électroniques vend quatre types de produits :

  • des cartes mères (code 1) ;
  • des processeurs (code 2) ;
  • des barrettes mémoire (code 3) ;
  • des cartes graphiques (code 4).

Chaque produit possède une référence, qui est un nombre entier, un prix en euros et une quantité disponible. Définir une structure produit qui code un produit et dans un programme initialiser deux produits à la déclaration et deux produits avec des valeurs entrées par l'utilisateur. Afficher les valeurs et cloner le produit le plus cher.

Exercice 3

Soit un programme affichant des flocons de neige qui tombent du haut de la fenêtre de la console. Chaque flocon est une lettre. Donner une structure de données qui permet de coder un flocon. Dans un programme, déclarer quatre flocons. Initialiser un flocon à la déclaration et un autre avec des valeurs aléatoires. Copier chaque flocon et afficher les valeurs des quatre flocons de façon claire.

Exercice 4

Le monde où se trouve le player est parcouru par des ennemis. Donner les caractéristiques essentielles d'un ennemi à imaginer et la structure de données la mieux adaptée. Initialiser un ennemi à la déclaration et un autre avec des valeurs aléatoires. Afficher les valeurs de cet ennemi. Faire un clone.

II. Structures et fonctions

II-A. Retourner une structure

Comme la copie de structure est autorisée, les structures peuvent être prises comme

valeur de retour. Soit la structure coord :

 
Sélectionnez
typedef struct coord{
    int x, y;
}coord;

Voici typiquement une fonction qui permet d'initialiser une structure après sa déclaration n'importe où dans le programme :

 
Sélectionnez
coord init_point1()
{
coord t0;
    t0.x = rand()%1024;
    t0.y = rand()%768;
    return t0;
}

Dans la fonction :

  • une structure du type souhaité est déclarée ;
  • chacun de ses champs est initialisé avec des valeurs aléatoires ou calculées ;
  • pour finir, la structure résultante est retournée au contexte d'appel.

Bien sûr des valeurs peuvent être transmises en paramètres, cela donne par exemple :

 
Sélectionnez
coord init_point2(int x, int y)
{
coord t0;
    t0.x = x;
    t0.y = y;
    return t0;
}

Et dans le programme la structure retournée par la fonction est affectée à une structure du contexte d’appel :

 
Sélectionnez
#include <stdio.h>
#include <stdlib.h>
int main()
{
coord pt1, pt2;
    pt1 = init_point1();
    pt2 = init_point2(40, 40);
    printf("pt1.x=%d, pt1.y=%d\n"
        "pt2.x=%d, pt2.y=%d\n",pt1.x,pt1.y,pt2.x, pt2.y);
    return 0;
}

L'appel de init_point1() renvoie une structure coord initialisée avec des valeurs aléatoires et elle est affectée à la variable coord pt1. L'appel de init_point2() renvoie une autre structure coord initialisée avec (40,40) et affectée à la variable coord pt2.

II-B. Structures en paramètre de fonction

Une structure est passée à un paramètre de fonction de même type par valeur comme n’importe quel autre type de variable. La structure passée est copiée dans le paramètre de la fonction.

Attention !

Soit par exemple la fonction ci-dessous, elle permet de faire progresser de 1 la position horizontale d’un point. Si la position dépasse 1000, elle retourne à 0 :

 
Sélectionnez
void modif(coord pt)
{
    pt.x++;
    if (pt.x>1000)
        pt.x=0;
}

Dans un programme l'appel est le suivant :

 
Sélectionnez
#include <stdio.h>
#include <stdlib.h>
int main()
{
coord p={ 10,20};
    printf("p.x=%d, p.y=%d\n", p.x, p.y);
    modif(p);
    printf("p.x=%d, p.y=%d\n", p.x, p.y);
    return 0;
}

Qu'imprime le programme ?

 
Sélectionnez
p.x=10, p.y=20
p.x=10, p.y=20

Il n'y a pas de modification de la structure p. La structure en paramètre de la fonction modif() est locale à la fonction. C'est une autre variable. Au moment de l'appel, l'affectation implicite suivante est réalisée :

 
Sélectionnez
modif(pt = p);

Mais à l'issue de la fonction, la structure p dans le contexte d'appel n'a pas été touchée. Pour avoir une fonction de modification des valeurs contenues dans une structure, il faut passer la structure à modifier en argument et retourner la structure modifiée, ce qui donne :

 
Sélectionnez
coord modif(coord pt)
{
    pt.x++;
    if (pt.x>1000)
        pt.x=0;
    return pt;
}

avec l'appel :

 
Sélectionnez
int main()
{
coord p={10,20};;
    printf("p.x=%d, p.y=%d\n", p.x, p.y);
    p=modif(p);
    printf("p.x=%d, p.y=%d\n", p.x, p.y);
    return 0;
}

Cette fois la copie modifiée dans la fonction est affectée à la structure p locale au

main() et le programme imprime :

 
Sélectionnez
p.x=10, p.y=20
p.x=11, p.y=20

II-C. Mise en pratique : structures et fonctions

Exercice 1

Une menuiserie industrielle gère un stock de panneaux de bois. Chaque panneau possède une largeur, une longueur, une épaisseur en millimètres, un volume et un type de bois. Il y a trois types de bois : pin (code 0), chêne (code 1), hêtre (code 2).

  • Définir une structure panneau contenant toutes les informations relatives à un panneau de bois ;
  • Écrire les fonctions de saisie d'un panneau de bois ;
  • Écrire une fonction d'affichage d'un panneau de bois ;
  • Écrire une fonction qui calcule le volume en mètre cube d'un panneau ;
  • Écrire une fonction qui affiche le volume d'un panneau de bois.

Exercice 2

Un grossiste de composants électroniques vend quatre types de produits :

  • des cartes mères (code 1) ;
  • des processeurs (code 2) ;
  • des barrettes mémoire (code 3) ;
  • des cartes graphiques (code 4) ;

Chaque produit possède une référence, qui est un nombre entier, un prix en euros et une quantité disponible.

  • Définir une structure « produit » qui code un produit ;
  • Écrire une fonction de saisie des données d'un produit ;
  • Écrire une fonction d'affichage des données d'un produit ;
  • Écrire une fonction qui permet à un utilisateur de saisir la commande d'un produit.

L'utilisateur identifie le produit et saisit la quantité demandée. L'ordinateur affiche toutes les données de la commande y compris le prix.

Exercice 3

Soient les deux types de structure « date » et « personne » :

 
Sélectionnez
typedef struct date{
    int jour, mois, annee;
}date;
typedef struct personne{
    int identifiant;
    struct date date_embauche;
    struct date date_poste;
}personne;
  • Écrire une fonction pour initialiser une structure de type « personne ».
  • Écrire une fonction d'affichage de façon à obtenir soit l'un soit l'autre des deux affichages

ci-dessous :

 
Sélectionnez
Identifiant : 1224
date embauche (jj mm aa) : 16 01 08
date poste = date embauche ? (O/N) : O
Identifiant : 1224
date embauche (jj mm aa) : 16 01 08
date poste = date embauche ? (O/N) : N
date poste (jj mm aa) : 01 09 08

Exercice 4

Soit une entité dans un jeu vidéo en mode console. Elle est définie par une position, un déplacement, un type (rampant, grouillant, serpentant, plombant, assommant), une couleur. L'entité a également un nom (une lettre) qui sert pour son apparence et une série de taux : taux d'agressivité, de colère, de convoitise, de faim, de peur.

Définir la structure de données pour coder une entité. Écrire une fonction d'initialisation, une fonction de mise à 0 (reset) et une fonction d'affichage. Tester dans un programme avec un menu : quitter, afficher, initialiser, reset.

II-D. Expérimentation

L'intérêt des structures est de permettre de regrouper en une seule variable plusieurs variables. Cette propriété donne aux fonctions la possibilité d'innombrables paramètres et valeurs de retour. En recevant une structure en argument la fonction reçoit en une fois un ensemble de valeurs, de même en retournant une structure la fonction retourne en une fois un ensemble de valeurs. Il devient possible de gérer de plus gros ensembles de variables et ça commence à donner de la force aux programmes.

II-D-1. Fourmi 1 : une fourmi mobile à l’écran

L'objectif est de faire circuler une fourmi à l'écran. Elle ne fait que bouger, rien d'autre.

Elle ne se nourrit pas et ne rencontre aucune autre bestiole.

Code complet
CacherSélectionnez

Précisions sur les paramètres et les retours des fonctions

La fonction init() utilise uniquement le mécanisme de retour : une structure fourmi est initialisée dans le corps de la fonction et juste avant de disparaître de la mémoire, elle est recopiée dans une autre en dehors de la fonction, la fourmi qui est déclarée dans le main et qui demeure en permanence jusqu'à la fin du programme.

La fonction avance() utilise les deux mécanismes, une fourmi en paramètre d'entrée et une fourmi en valeur de retour à la sortie. Au moment de l'appel une fourmi du contexte d'appel est recopiée dans le paramètre de type fourmi. Dans le corps de la fonction, les instructions sont exécutées sur la copie et donc la fourmi du contexte d'appel n'est pas modifiée. Pour récupérer cette copie qui est modifiée à l'intérieur de la fonction, la fourmi du contexte d'appel doit recopier cette copie modifiée de la fonction lorsqu'elle est retournée. D'où l'expression :

 
Sélectionnez
f = avance(f);

La fonction affiche() n'utilise qu'un paramètre fourmi. En effet la fonction a besoin des informations de la fourmi à afficher, mais elle ne les modifie pas, ainsi la copie dans le paramètre suffit et il n'y a rien à retourner :

 
Sélectionnez
affiche(f, f.color)

La fonction top() utilise un pointeur et une technique qui est présentée au chapitre Les pointeurs, mais le principe ici n'est pas très compliqué. Un pointeur est une variable qui prend pour valeur une adresse mémoire. En paramètre ça permet de donner l'adresse d'une variable à la fonction et dans le corps de la fonction de pouvoir écrire à cette adresse mémoire (grâce à l'opérateur étoile avec l'expression *start dans la fonction). Cette utilisation des pointeurs permet de transformer le paramètre d'entrée en une entrée+sortie. C'est utile lorsque plusieurs retours sont nécessaires comme dans cette fonction. Le retour classique de type int est utilisé pour le résultat de la fonction ce qui permet de l'appeler directement dans le test :

 
Sélectionnez
if( top (&start, 150) ){ }

Lors de l'appel de la fonction, c'est l'adresse de la variable start qui est passée au pointeur de même nom, soit l'expression :

 
Sélectionnez
&start

Dans la fonction le paramètre pointeur int*start est utilisé afin de pouvoir modifier éventuellement la valeur de la variable start du contexte d'appel si le temps demandé est passé.

II-D-2. Voiture 2 : structure circuit, structure voiture

Grâce aux structures nous pouvons reprendre le programme voiture 1 présenté précédemment et lui ajouter une course à quatre voitures. Rappelons que dans la première version pour une voiture il faut sept variables avec des fonctions dédiées à ces variables déclarées en globale.

 
Sélectionnez
void select_trait (void);
void avancer (int l, int color1, int color2);

Avec quatre voitures, il faut donc 28 variables et des fonctions dédiées pour chaque voiture ou des fonctions généralisées avec un nombre très élevé de paramètres.

En revanche avec un type de structure voiture nous avons quatre voitures, chaque voiture est un ensemble de sept variables. Les mêmes fonctions servent pour chaque voiture. Il suffit de passer la voiture concernée en paramètre, et si des modifications sont opérées, de récupérer la voiture modifiée en valeur de retour.

Comme il y a plusieurs voitures, il faut arrêter la course dès qu'une voiture gagne et le test de la boucle principale doit être modifié. De plus l'initialisation des voitures vaut la peine aussi d'une fonction à part qui permet de donner à chacune des valeurs différentes de façon simple, aisément modifiable dans le code.

Code complet
CacherSélectionnez

L'algorithme est toujours le même que celui du programme voiture 1 vu précédemment. Simplement l'utilisation de structure permet d'avoir plusieurs voitures facilement. Pour avoir 10 voitures, il suffit de déclarer 10 struct voiture, de les initialiser et dans la boucle avoir une fois pour chaque voiture v1,v2…v10 le bloc :

 
Sélectionnez
    if(top(v1)){
        v1.tmps=clock();
        if(v1.pas==0)
        v1=select_trait(v1,c);
        v1=avancer(v1);
    }

Généralisation d'un bloc d'instructions en une fonction

Ce bloc est répété pour chaque voiture. Pour fonctionner, il a besoin d'une voiture et d'un circuit. Sur les deux paramètres, un seul change, c'est la voiture. Alors il faut le généraliser, c'est-à-dire transformer en une fonction qui prend en paramètres une voiture et un circuit, et comme le paramètre voiture peut être modifié, il est retourné en sortie. C'est la fonction :

 
Sélectionnez
voiture bouge (voiture v, circuit c)
{
    if(top(v)){
        v.tmps=clock();
        if(v.pas==0)
        v=select_trait(v,c);
        v=avancer(v);
    }
    return v;
}

Au moment de l'appel, il suffira de préciser de quelle voiture et quel circuit il s'agit.

 
Sélectionnez
v1 = bouge(v1, c);
v2 = bouge(v2, c);
v3 = bouge(v3, c);
v4 = bouge(v4, c);

Comme il y a plusieurs voitures, la course prend fin si une voiture a terminé. Le test aurait pu être mis tel que dans la boucle principale. Mais c'est plus propre d'écrire une fonction qui retourne le résultat. Notre objectif maintenant est de faire tourner 100, 1000 ou 10 000 voitures. Clairement les seules structures ne suffisent plus et il faut leur adjoindre des tableaux, il faut faire des tableaux de structures.

III. Conclusion

IV. Remerciements

Je tiens sincèrement à remercier Vincent VIALE pour la mise au gabarit et Claude LELOUP pour la relecture orthographique.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2014 Frédéric Drouillon. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.