• Aucun résultat trouvé

Passage d’arguments à la fonction main : la ligne de commande

Le programme principal, qui correspond à la fonction MAIN en C, peut recevoir des paramètres venant de l’extérieur au moment du lancement du programme. Ces paramètres sont transmis au MAIN par l’intermédiaire de la ligne de commande.

Par exemple, si votre exécutable s’appelle prog_test, la ligne de commande … prog_test 1 25 durant

… envoie les chaînes de caractères « 1 », « 25 », et « durant » au programme principal.

Pour ce mécanisme, le MAIN doit être écrit de la manière suivante : void main (int argc, char* argv[])

argc : nombre d’arguments passés au main, nom du programme compris

argv : tableau de pointeurs sur chaîne de caractères contenant chacun des arguments.

Le premier élément du tableau ARGV (c’est à dire argv[0]) contient le nom du programme exécutable, ce qui correspond dans notre exemple à prog_test.

16

C

HAPITRE

16 L

A RÉCURSIVITÉ

16.1 Définition

De même que chaque sous programme peut en appeler un autre, chaque sous programme peut s’appeler lui-même.

En langage C, toute fonction a la possibilité de s’appeler elle-même, ce qui en fait une fonction

récursive. Il est donc possible d’écrire des fonctions récursives comme par exemple la fonction

factorielle ci-dessous.

Exemple :

long int fact(int n) {

if (n= =0) return 1 ; else return (n*fact(n-1)) ; }

Cette fonction peut également être écrite de manière plus concise :

long int fact(int n) { return( n ? n*fact(n-1) : 1) ;}

16.2 Utilité

Le récursif est un mode de pensée. Tout programme récursif aura un algorithme équivalent en mode itératif (classique). L’inverse n’est pas vrai.

Un algorithme récursif est souvent très concis en termes de lignes de code. Il est par contre plus gourmand en place mémoire.

La récursivité s’applique lorsque le traitement à effectuer concerne un ensemble d’objets, et que le traitement d’un des objets de l’ensemble réduit l’ensemble des objets à traiter jusqu’à l’ensemble vide. (Relisez bien le paragraphe précédent pour en digérer le contenu ;-)

Un exemple pour vous aider :

Trier en récursif un ensemble d’entiers en ordre croissant consiste à rechercher le plus petit entier de l’ensemble, puis à trier l’ensemble des entiers privé de cet élément. Et ce jusqu’à ce qu’il n’y ait plus d’entier à trier.

16.3 Notion de clone

De même qu’appeler un sous programme revient à se mettre en attente et à lui confier le processeur, lorsqu’un sous-programme s’appelle lui-même, il se met en attente (pause) et génère un « clone » qui prend la main du processeur. A sa terminaison, le clone rendra la min à son parent afin que celui-ci poursuive son exécution à partir de son point de mise en attente.

Chaque clone étant identique à son parent, il va lui-même générer un autre clone après s’être mis en pause. La chaîne de clone va ainsi s’agrandir indéfiniment si elle n’est pas contrôlée par une condition d’arrêt.

Chaque point de mise en attente de chacun des clones est stockée dans une « pile d’adresse » afin de permettre à chacun de reprendre correctement son exécution lorsqu’il récupèrera la main sur le processeur.

16.4 Condition d’arrêt

Cette condition est une instruction (souvent un test) permettant à un clone de ne pas généré de successeur. Il va alors se terminer normalement sans se mettre en attente. Il va donc rendre la main à son parent qui pourra à son tour poursuivre son exécution et se terminer… rendant ainsi la main à son parent…etc.

Le dépilement des clones peut alors commencer et se dérouler correctement jusqu’à l’initiateur de la chaîne de récursion.

16.5 Procédure récursive

Exemple : 1. Binarisation récursive à 4 voisins. 2. Tri de tableau d’entiers.

16.6 Fonction récursive

Exercice : (à corriger en TD)

Ecrivez un programme permettant de calculer l’élévation d’un nombre a à une puissance b : puissance (a,b). Vous le décomposerez en sous-programmes.

17

C

HAPITRE

17 -

L

ES STRUCTURES ET LES UNIONS

17.1 Les Structures

Il arrive très souvent qu'une variable ne se décrive pas seulement par un entier, un réel ou une autre valeur simple mais que sa description demande plusieurs informations de type différents. Par exemple, pour décrire une personne on utilisera des chaînes de caractères (pour le nom et le prénom), des entiers (pour sa date de naissance), … Dans ces cas il est intéressant d'avoir des mécanismes permettant de regrouper un certain nombre de variables de type différents. C'est le concept de structure.

Une structure est un ensemble de données regroupées sous un même nom. Les éléments d'une structure, ou membre d'une structure, peuvent être de types différents. (tableau, autre structure, etc...).

Il ne faut pas confondre la déclaration d'un type de structure avec la déclaration d'une variable de structure.

Rappel sur le typedef :

Nous avons déjà eu l’occasion de voir le mot clef typedef qui s’utilise en bibliothèque personnelle et permet de se définir de nouveau type.

typedef description du type nom_type ;

17.1.1 Déclaration de type structure

La déclaration d'un type de structure se fait dans la bibliothèque personnelle comme suit :

typedef struct nomDeStructure { type1 nomChamp1; type2 nomChamp2; type3 nomChamp3; type4 nomChamp4; ... typeN nomChampN; }nom_du_type; Exemple :

typedef struct personne { char nom[30]; char prenom[40]; int age; char sexe; }t_pers;

Attention : typedef ne réserve pas d'espace mémoire. Le nom est un type, il est donc inaccessible comme variable.

Un type de structure est donc déclaré par le mot clé « typedef » (définition de type) suivi de "struct" suivi d'un nom facultatif, ici "personne". Ce nom est une étiquette qui pourra être ensuite utilisée pour désigner le type de structure. Le nom de type « t_pers » est un alias du type « struct personne » décrit entre accolades. Il permet de faire plus simplement référence au type « struct personne ».

Cette déclaration ne provoque pas d'allocation mémoire; il s'agit uniquement de la définition d'un nouveau type (aussi appelé nouveau concept) dont le nom est « struct personne » ou encore « t_pers ».

17.1.2 Déclaration d'une variable de type structure

La déclaration d'une variable de type structure personne ou t_pers :

struct personne toto1; ou encore

t_pers toto2 ;

Cela permet de créer une variable (on dit aussi instance de type ou objet) nommée toto1 ou toto2 de type "structure personne" précédemment définie. Cette fois ci, contrairement au point 15.1.1, le compilateur alloue de la mémoire pour ces 2 variables.

Pour info :

Une autre manière de déclarer une variable de type structure personne est la suivante (notez ici l’absence du mot clef « typedef ») :

int main() { struct personne { char nom[30]; char prenom[40]; int age; char sexe; } pers1; // début des traitement …

pers1.age = 29 ; ….

return 0 ; }

On déclare ci-dessus simultanément un type de structure défini entre les accolades, et une variable de ce type pers1. Cette déclaration n’est valable qu’à l’intérieur du bloc formé par les accolades où se trouve la déclaration. Ici, le type de structure n'a pas de nom (ou d’alias ou d'étiquette), ce qui gène le passage de structure en paramètre à un sous-programme.

17.1.3 Les données membres d'une structure : les champs

Les membres d'une structure peuvent être de types quelconques, type scalaire de base (char, int, float...), pointeurs, mais aussi tableaux ou encore autres structures. Une structure peut donc comporter plusieurs niveaux hiérarchiques de structures.

Exemple (l’utilisation ou non des typedef ne change rien à cet exemple) struct date { int jour; int mois; int annee; }; struct adresse { int numero; char rue[40]; long codePostal; char localite[16]; }; struct identité { char nom[16]; char prenom[20]; struct adresse adr; struct date naissance; };

17.1.4 Accès aux champs d’un objet structure.

L'accès aux membres de structure se fait en utilisant l'opérateur "." :

L'opérateur "." relie le nom d'une variable de type structure à un de ses membres: nom_de_structure. nom_membre

Exemple : Soit le programme suivant #ifndef COUCOU #define COUCOU typedef struct personne { char nom[30]; char prenom[40]; int age; char sexe; }t_pers ; #endif #include « … » void main( ) { /* déclaration de pers2 */

t_pers pers2 ; // cette variable non-initialisée ne sera pas utilisée dans cet exemple /* déclaration et initialisation immédiate de pers1 */

t_pers pers1 = {"DUPONT","RENE",28,'M'}; printf("\n voici les données de pers1 ");

/* désignation de l'élément "nom" et de l'élément "prenom" de la variable pers1 */ printf("\n\n NOM :%s PRENOM : %s", pers1.nom, pers1.prenom);

printf("\n AGE %d", pers1.age);

printf("\n SEXE : %c\n",( pers1.sexe=='M') ? "MASCULIN":"FEMININ"); }

17.1.5 Accès aux champs d’un objet structure via un pointeur

On peut utiliser l'opérateur "->" pour accéder aux membres d'une structure par l'intermédiaire d'un pointeur. Cet opérateur relie le pointeur de la structure au membre que l'on désire atteindre :

pointeur_de_structure -> nom_membre Exemple :

// dans la biblio perso typedef struct adresse { int numero; char rue[40]; long codePostal; char localite[16]; } t_adr; … // dans le code C

struct adresse adr1, *ptad; // ici adr1 est une variable (un objet)de type t_adr, // ptad est un pointeur sur variable (objet)de type t_adr

Attention :

Adr1.numero est équivalent à ptad->numero

Adr1.rue[0] est équivalent à ptad->rue[0]

(*ptad).codePostal est équivalent à ptad->code_postal

Remarque:

Pour adresser par pointeur le code postal de la structure adresse, les parenthèses sont nécessaires car la priorité de l'opérateur "." est plus élevée que celle de l'opérateur *.

17.1.6 Accès aux données membres de structure dans le cas de structures imbriquées

Dans le cas où plusieurs structures sont imbriquées, l'accès à un membre de structure de bas niveau, se fait en utilisant plusieurs fois l'opérateur "." .

Exemple:

typedef struct date {

int jour;

int mois;

int annee;

};

typedef struct identite {

char nom[16]; char prenom[20]; struct date naissance; } t_ident;

main ( ) {

t_ident homme = {"Durand","Marcel",23,12,1915}; if(2000 - homme.naissance.annee >=18)

printf("%s %s est majeur \n", homme.nom, homme.prenom); else printf("%s %s n'est pas majeur \n", homme.nom, homme.prenom); }

17.1.7 Opération sur les structures

Les opérateurs classiques (mathématiques, comparaisons…), utilisés pour les variables simples (scalaires), ne s'appliquent pas aux structures. Seul l'opérateur "&" permet d'obtenir l'adresse de tout objet en C et donc d'une structure.

Les comparaisons se feront donc champ par champ.

17.1.8 Les tableaux de structures

On utilise fréquemment les tableaux de structures; l'instruction ci-dessous permet de déclarer un tableau de 100 structures de type "personne".

struct personne { char nom[30]; char prenom[40]; int age; char sexe; } tabDePersonnes[100];

L'accès à un élément du tableau peut se faire en utilisant un indice compris entre 0 et 99, ou bien encore un pointeur de tableau.

Exemple:

typedef struct personne { char nom[30]; char prenom[40]; int age; char sexe; } t_pers; main () { t_pers tabDePersonnes[100]; int i;

struct personne *ptr = tabDePersonnes;

/* lecture du nom de chaque personne en utilisant l'indice du tableau */ for ( i = 0; i < 100 i++)

scanf("%s", tabDePersonnes[i].nom);

/* impression du nom de chaque personne en utilisant le pointeur */ for ( i = 0; i < 100; i++)

printf ("%s\n",ptr++ -> nom); }

17.1.9 La récursivité et les structures

La récursivité ne peut pas s'appliquer au niveau des structures. Il n'est pas possible de déclarer une structure qui contient un membre désignant directement la structure initiale.

Cependant un membre d'une structure peut toujours référencer une autre structure du même type à l'aide d'un pointeur vers cette structure. C’est le principe des listes chaînées.

struct liste { char nom[16]; char prenom[20]; struct date naissance;

struct liste * suiv;

};

où suiv est le pointeur vers une structure de type liste.

Exemple : La structure liste déclarée précédemment permet de construire les listes chaînées comme

sur le schéma ci-dessous. Chaque élément de cette liste est de type struct liste.

Nous reviendrons en détail sur les listes chaînées dans un prochain chapitre.

Documents relatifs