algo

200
Données et Algorithmique - Sommaire INTRODUCTION LES VARIABLES SCALAIRES codage binaire boucles récursivité LES TABLEAUX STATIQUES tableaux unidimensionnels généralités fonctions de base (fichier inclus base_tus) manipulations dans les tableaux (mani_tus) tris généralités (valables également pour d'autres types de données) le tri bulle le tri par insertion Données et Algorithmique Ce document décrit les structures de données et les algorithmes que l'on peut leur associer. Contrairement à beaucoup d'ouvrages d'algorithmique, j'ai préféré mettre l'accent sur le choix des structures de données. Il est avant tout important de définir coment modéliser le problème à traiter, ainsi que ses données. Ce choix fait, on cherchera ensuite l'algorithme optimal, adapté aux types de données choisies. Ce document n'est pas spécifique à un langage (il suffit qu'il soit structuré). Les exemples par contre sont tous donnés en C (ANSI), mais sont facilement transposables dans un autre langage. Vous trouverez les informations nécessaires dans mon document sur le langage C ou, pour un détail particulier, son index. Autres sites sur l'algorithmique : Jean-Jacques Levy (Polytechnique), Jean Beuneu (EUDIL Lille), cours de JL Bienvenu (CNAM Bordeaux), les polycopiés de Jean Fruitet (IUT Marne la Vallée) INTRODUCTION LES VARIABLES SCALAIRES LES TABLEAUX STATIQUES LES TABLEAUX DYNAMIQUES LES LISTES LES PILES ET FILES LES ARBRES LES GRAPHES LES FICHIERS CORRECTION DES EXERCICES Sommaire Données et Algorithmique http://www-ipst.u-strasbg.fr/pat/program/algo.htm (1 of 4) [21-11-2001 17:39:47]

Transcript of algo

Page 1: algo

Données etAlgorithmique- Sommaire

INTRODUCTION●

LES VARIABLESSCALAIRES

codage binaire❍

boucles❍

récursivité❍

LES TABLEAUXSTATIQUES

tableauxunidimensionnels

généralités■

fonctions de base(fichier inclusbase_tus)

manipulationsdans les tableaux(mani_tus)

tris

généralités(valableségalementpourd'autrestypes dedonnées)

le tri bulle■

le tri parinsertion

Données et AlgorithmiqueCe document décrit les structures de données et les algorithmesque l'on peut leur associer. Contrairement à beaucoup d'ouvragesd'algorithmique, j'ai préféré mettre l'accent sur le choix desstructures de données. Il est avant tout important de définir comentmodéliser le problème à traiter, ainsi que ses données. Ce choixfait, on cherchera ensuite l'algorithme optimal, adapté aux typesde données choisies. Ce document n'est pas spécifique à unlangage (il suffit qu'il soit structuré). Les exemples par contre sonttous donnés en C (ANSI), mais sont facilement transposables dansun autre langage. Vous trouverez les informations nécessairesdans mon document sur le langage C ou, pour un détail particulier,son index.

Autres sites sur l'algorithmique : Jean-Jacques Levy(Polytechnique), Jean Beuneu (EUDIL Lille), cours de JLBienvenu (CNAM Bordeaux), les polycopiés de Jean Fruitet (IUTMarne la Vallée)

INTRODUCTION●

LES VARIABLES SCALAIRES●

LES TABLEAUX STATIQUES●

LES TABLEAUX DYNAMIQUES●

LES LISTES●

LES PILES ET FILES●

LES ARBRES●

LES GRAPHES●

LES FICHIERS●

CORRECTION DES EXERCICES●

Sommaire●

Données et Algorithmique

http://www-ipst.u-strasbg.fr/pat/program/algo.htm (1 of 4) [21-11-2001 17:39:47]

Page 2: algo

le tri parsélection

le tri shell■

le tri rapide(QuickSort)

le tri parcréation

d'autres tris■

recherches

larechercheséquentielle

ladichotomie

calculsmathématiques

calculvectoriel

polynômes■

tableauxmultidimensionnels

conclusions❍

LES TABLEAUXDYNAMIQUES

tableauxunidimensionnels en C

la méthode dusuper-tableau

les tableauxmultidimensionnels

matrices pleines(matricesrectangulairesdynamiques :mrd)

tableaux detableaux

Données et Algorithmique

http://www-ipst.u-strasbg.fr/pat/program/algo.htm (2 of 4) [21-11-2001 17:39:47]

Page 3: algo

dynamiques

conclusions❍

LES LISTES

fonctions de base etmanipulations (base_lst)

les tris

le tri bulle■

le tri par insertion■

le tri par sélection■

le tri par création■

les autres tris■

problèmesmathématiques

conclusions❍

LES PILES ET FILES

définition❍

fonctions de base❍

utilisations❍

LES ARBRES

introduction❍

expressionsarithmétiques (arb_expr)

listes triées❍

les arbres généraux❍

LES GRAPHES●

LES FICHIERS

les fichiers séquentiels❍

les fichiers à accèsdirect

l'indexation❍

CORRECTION DESEXERCICES

BOUCLE❍

TUSEXO_A❍

TUSEXO_B❍

Données et Algorithmique

http://www-ipst.u-strasbg.fr/pat/program/algo.htm (3 of 4) [21-11-2001 17:39:47]

Page 4: algo

GAUSS_MRD❍

INSE_TTD❍

recherche dans l'index de mondocument sur le langage C

Données et Algorithmique

http://www-ipst.u-strasbg.fr/pat/program/algo.htm (4 of 4) [21-11-2001 17:39:47]

Page 5: algo

Données et AlgorithmiqueCe document décrit les structures de données et les algorithmes que l'on peut leur associer. Contrairementà beaucoup d'ouvrages d'algorithmique, j'ai préféré mettre l'accent sur le choix des structures de données.Il est avant tout important de définir coment modéliser le problème à traiter, ainsi que ses données. Cechoix fait, on cherchera ensuite l'algorithme optimal, adapté aux types de données choisies. Ce documentn'est pas spécifique à un langage (il suffit qu'il soit structuré). Les exemples par contre sont tous donnésen C (ANSI), mais sont facilement transposables dans un autre langage. Vous trouverez les informationsnécessaires dans mon document sur le langage C ou, pour un détail particulier, son index.

Autres sites sur l'algorithmique : Jean-Jacques Levy (Polytechnique), Jean Beuneu (EUDIL Lille), coursde JL Bienvenu (CNAM Bordeaux), les polycopiés de Jean Fruitet (IUT Marne la Vallée)

INTRODUCTION●

LES VARIABLES SCALAIRES●

LES TABLEAUX STATIQUES●

LES TABLEAUX DYNAMIQUES●

LES LISTES●

LES PILES ET FILES●

LES ARBRES●

LES GRAPHES●

LES FICHIERS●

CORRECTION DES EXERCICES●

Sommaire●

Données et Algorithmique - P.TRAU

http://www-ipst.u-strasbg.fr/pat/program/algo_t.htm [21-11-2001 17:39:57]

Page 6: algo

INTRODUCTIONLorsque l'on désire créer un programme répondant à un cahier des charges bien défini (conditionpréalable évidement nécessaire), il faut déterminer quelles données il va falloir traiter, et comment lestraiter. La première étape est donc de choisir comment représenter en mémoire ces données, et siplusieurs possibilités sont envisageables, choisir la plus appropriée aux traitements qu'il faudra effectuer(c'est à dire celle pour laquelle les algorithmes seront le plus facile à mettre en oeuvre). Dans un grosprogramme (C.A.O. par exemple), on appelle modèle la structure choisie pour stocker les données enmémoire.

Une fois ce modèle défini, le programme doit être écrit de manière structurée, c'est à dire être décomposéen petites entités (sous programmes, fonctions en C), réalisant chacune une tâche bien définie, en ayantbien défini quelles sont les données nécessaires en entrée du sous programme, et quelles seront lesdonnées retournées en sortie du sous programme (arguments ou dans certains cas variables globales). Laréalisation pratique de la tâche doit ne dépendre que de ses entrées et sorties, et n'accéder à aucune autrevariable (par contre elle peut utiliser pour son propre compte autant de variables locales que nécessaire).Ceci permet d'éviter les effets de bord, qui rendent la recherche d'erreurs (débogage) presque impossible.

Le choix d'un modèle est capital : devoir le modifier une fois le programme bien avancé nécessite engénéral la réécriture complète du programme, alors que modifier certaines fonctionnalités du programmecorrespond à ajouter ou modifier des sous programmes sans modifier les autres. C'est un des intérêts de laprogrammation structurée. Par contre, pour pouvoir plus facilement modifier le modèle, il faut desstructures de données hiérarchisées et évolutives (disponibles dans les langages orientés objets). Un autreavantage de la programmation structurée est la possibilité de créer dans un premier temps chaque sousprogramme réalisant une tâche déterminée grâce à un algorithme simple, puis d'optimiser uniquement lessous-programmes souvent utilisés, ou demandant trop de temps de calcul, ou nécessitant trop demémoire.

Parlons encore de l'optimisation d'un programme. On n'optimise un programme (ou du moins certainesparties) que si l'on estime que son fonctionnement n'est pas acceptable (en temps ou en consommation demémoire). On devra choisir un algorithme en fonction des conditions d'utilisation du programme (on netrie pas de la même manière un fichier totalement mélangé et un fichier déjà trié , mais avec quelquesvaleurs non triées en fin de fichier). A partir d'un moment, on ne peut plus optimiser en temps et enmémoire. Il faut alors choisir. Par exemple, un résultat de calcul qui doit être réutilisé plus tard peut êtremémorisé (gain de temps) ou on peut préférer refaire le calcul (gain de mémoire). Par exemple, il est rarede passer par une variable intermédiaire pour utiliser deux fois i+1.

Données et Algorithmique - INTRODUCTION

http://www-ipst.u-strasbg.fr/pat/program/algo01.htm [21-11-2001 17:40:12]

Page 7: algo

Sommaire généralPROGRAMMATION

Vous trouverez ici mes (gros) documents sur la programmation : C, C++, algorithmique, infographie,Pascal). ainsi que la possibilité de télécharger les exemples (bien que le copier - coller sous Netscape ouIE marche également très bien), mais aussi les corrections des exercices, la bibliothèque graphique, desexemples supplémentaires, des sujets de TP, d'examens....

Copyright : utilisation de ces documents libre pour tout usage personnel. Utilisation autorisée pour toutusage public non commercial, à condition de citer son auteur (Patrick TRAU, IPST, Université LouisPasteur Strasbourg, email : ) et de me signaler tout usage intensif. Utilisation commerciale interdite sansaccord écrit de ma part.

Cliquez sur l'icône (à droite) pour voter pour le site n°3464 du TOP Ouaibe (cours enligne de P. TRAU).

vous pouvez accéder à :

Cours sur le C (ANSI) (y compris correction des exercices), qui détaille complètement le langageC

Données et Algorithmes : les différents algorithmes classiques, expliqués, comparés, en fonctiondes types de données choisies. Chaque algorithme est accompagné de sa mise en oeuvre en C

Infographie : comment dessiner sur un matériel (écran, imprimante...) sur lequel on sait au moinsallumer un point. Les tracés de base (droites, courbes...), les remplissages et hachurages, clipping,tracés 3D,... La documentation de la bibliothèque graphique téléchargeable. Les exemples sont enC ANSI.

sommaire et instructions de téléchargement de la disquette d'accompagnement concernant les troisdocuments cités ci-dessus (mais aussi la bibliothèque graphique en version Pascal)

le C++ (ce document suppose que vous connaissez déjà le C)●

Cours de Pascal●

évaluez vous avec mes sujets d'examens (dont certains avec correction) (en particulier en C)●

Plus spécifiquement pour les étudiants d'IUP2 à l'IPST (les autres ont aussi le droit de regarder) :les sujets et correction des TP (97/98 en version détaillée, et ceux de l'année en cours, au fur et àmesure).

Certains points du C expliqués par les étudiants de DEUG TI●

La plupart de ces documents contiennent des frames (écran séparé en deux parties). Pour revenir à cette

page (et quitter les frames), une solution est de cliquer sur le bon (à vous de trouver lequel).

Sommaire général PROGRAMMATION

http://www-ipst.u-strasbg.fr/pat/program/ (1 of 2) [21-11-2001 17:40:27]

Page 8: algo

Bonne lecture !

Pour toute question, envoyez moi un , ou regardez mes FAQ. S'il vous plait, signalez moi toute erreur !

Liens externes : Vous cherchez un compilateur gratuit (C/Pascal) ? utilisez gcc, gpp sous Linux/Unix,Sous DOS regardez l'ABC de la Programmation : Olivier Pecheux vous aide à démarrer (y compris àinstaller le compilateur freeware DJGPP). si vous cherchez d'autres sites sur la programmation, en voicides listes : en français ou en anglais.

Depuis le 20/3/1997, vous êtes le ème lecteur de cette page

P. TRAU, ULP-IPST, 20/3/97

Vous pouvez ici accéder aux autres informations sur ce serveur, normalement ou par carte.

Sommaire général PROGRAMMATION

http://www-ipst.u-strasbg.fr/pat/program/ (2 of 2) [21-11-2001 17:40:27]

Page 9: algo

Données et Algorithmique - SommaireINTRODUCTION●

LES VARIABLES SCALAIRES

codage binaire❍

boucles❍

récursivité❍

LES TABLEAUX STATIQUES

tableaux unidimensionnels

généralités■

fonctions de base (fichier inclus base_tus)■

manipulations dans les tableaux (mani_tus)■

tris

généralités (valables également pour d'autres types de données)■

le tri bulle■

le tri par insertion■

le tri par sélection■

le tri shell■

le tri rapide (Quick Sort)■

le tri par création■

d'autres tris■

recherches

la recherche séquentielle■

la dichotomie■

calculs mathématiques

calcul vectoriel■

polynômes■

tableaux multidimensionnels❍

conclusions❍

LES TABLEAUX DYNAMIQUES●

Données et Algorithmique - Sommaire

http://www-ipst.u-strasbg.fr/pat/program/algo_c.htm (1 of 3) [21-11-2001 17:40:36]

Page 10: algo

tableaux unidimensionnels en C❍

la méthode du super-tableau❍

les tableaux multidimensionnels

matrices pleines (matrices rectangulaires dynamiques : mrd)■

tableaux de tableaux dynamiques■

conclusions❍

LES LISTES

fonctions de base et manipulations (base_lst)❍

les tris

le tri bulle■

le tri par insertion■

le tri par sélection■

le tri par création■

les autres tris■

problèmes mathématiques❍

conclusions❍

LES PILES ET FILES

définition❍

fonctions de base❍

utilisations❍

LES ARBRES

introduction❍

expressions arithmétiques (arb_expr)❍

listes triées❍

les arbres généraux❍

LES GRAPHES●

LES FICHIERS

les fichiers séquentiels❍

les fichiers à accès direct❍

l'indexation❍

CORRECTION DES EXERCICES

BOUCLE❍

TUSEXO_A❍

Données et Algorithmique - Sommaire

http://www-ipst.u-strasbg.fr/pat/program/algo_c.htm (2 of 3) [21-11-2001 17:40:36]

Page 11: algo

TUSEXO_B❍

GAUSS_MRD❍

INSE_TTD❍

recherche dans l'index de mon document sur le langage C●

Données et Algorithmique - Sommaire

http://www-ipst.u-strasbg.fr/pat/program/algo_c.htm (3 of 3) [21-11-2001 17:40:36]

Page 12: algo

Données et Algorithmique - Index

A , B , C , D , E , F , G , I , L , M , N , O , P , Q , R , S ,T , U , V , W

Aaccès●

direct [1]

[2]

séquentiel [1] [2]❍

allocation dynamique [1]●

arbre [1]●

binaire [1]

[2]

argument [1]●

Bbande [1] [2]●

binaire [1]●

bit [1]●

boucles [1]●

Cindex du langage C●

chiffres significatifs [1]●

clef [1] [2]●

Données et Algorithmique - Index

http://www-ipst.u-strasbg.fr/pat/program/algo_i.htm (1 of 6) [21-11-2001 17:40:43]

Page 13: algo

Ddébogage [1]●

décalage [1]●

décalages [1]●

défiler [1]●

dépiler [1]●

define [1]●

deuxaire [1]●

dichotomie [1] [2]

[3]

dimension [1] [2]●

do-while [1]●

dynamique [1] [2]

[3] [4]

Eeffet de bord [1]●

empiler [1]●

encombrement [1]●

enfiler [1]●

Ffeuille [1]●

fichier [1]●

FIFO [1]●

file [1]●

fils [1]●

float [1]●

for [1]●

free [1]●

Données et Algorithmique - Index

http://www-ipst.u-strasbg.fr/pat/program/algo_i.htm (2 of 6) [21-11-2001 17:40:43]

Page 14: algo

GGauss [1] [2]●

graphe [1]●

Iindex [1]●

indexation [1]●

infixé [1] [2]●

insertion [1] [2]

[3] [4] [5]

interpolation [1]●

LLagrange [1]●

largeur de bande [1]●

LIFO [1]●

ligne de ciel [1] [2]●

liste [1] [2]

[3]

Mmalloc [1]●

mathématiques [1] [2]

[3] [4]

matrice [1] [2]

[3]

triangulée [1]❍

modèle [1]●

Données et Algorithmique - Index

http://www-ipst.u-strasbg.fr/pat/program/algo_i.htm (3 of 6) [21-11-2001 17:40:43]

Page 15: algo

Nnoeud [1]●

notation polonaise [1]●

NULL [1] [2]

[3]

Oobjets [1]●

optimisation [1]●

Pparcours [1] [2]

[3]

pile [1] [2]

[3]

pivot [1]●

de Gauss [1]●

pointeur [1] [2]

[3]

polynôme [1] [2]●

postfixé [1] [2]●

préfixé [1] [2]●

Qqueue [1]●

Quick Sort [1]●

Rrécursif [1]●

récursivité [1] [2]●

Données et Algorithmique - Index

http://www-ipst.u-strasbg.fr/pat/program/algo_i.htm (4 of 6) [21-11-2001 17:40:43]

Page 16: algo

[3]

racine [1]●

recherche [1] [2]●

retassage [1]●

Sséquentiel [1] [2]●

sentinelle [1]●

spline [1]●

stable [1]●

(tri) [1]●

stack [1]●

strcmp [1]●

structuré [1]●

suites [1]●

super-tableau [1] [2]●

suppression [1] [2]

[3]

Ttableau [1] [2]

[3] [4] [5] [6] [7]

dynamique [1]❍

multidimensionnel [1]❍

statique [1]❍

ternaire [1]●

tri [1]

bulle [1] [2]❍

tri par●

arbre [1]

comptage [1]❍

création [1] [2] [3]❍

Données et Algorithmique - Index

http://www-ipst.u-strasbg.fr/pat/program/algo_i.htm (5 of 6) [21-11-2001 17:40:43]

Page 17: algo

fusion [1] [2]❍

insertion [1] [2] [3]❍

sélection [1] [2]❍

rapide [1] [2]●

shell [1] [2]●

triangulation [1] [2]●

typedef [1]●

Uunaire [1]●

Vvecteur [1]●

virgule flottante [1]●

Wwhile [1]●

Données et Algorithmique - Index

http://www-ipst.u-strasbg.fr/pat/program/algo_i.htm (6 of 6) [21-11-2001 17:40:43]

Page 18: algo

Langage CLe Langage C

Aujourd'hui, l'informatique est présente dans tous les domaines de la vie courante, mais à des degrésdifférents. Il y a pour cela trois grandes raisons :

- les gains (en temps, argent, qualité) que l'informatique peut apporter,

- le prix abordable des matériels,

- la disponibilité de logiciels dans tous les domaines.

Deux domaines sont pleinement exploités :

- les logiciels généraux, vendus en grande série, et donc relativement bon marché,

- les logiciels spécifiques, d'un coût total important et donc limités à des sujets très pointus, pour de trèsgrosses industries.

Le domaine intermédiaire, qui peut encore se développer, concerne les programmes spécifiques, pour desapplications de moindre importance. Pour cela, il est nécessaire de disposer de langages deprogrammation. Les tableurs et bases de données par exemple disposent désormais de véritables langagesde programmation (souvent orientés objets) qui vont plus loin que les précédents langages demacro-commandes. Pour les autres cas, le C est souvent le meilleur choix. En effet, c'est un langagestructuré, avec toutes les possibilités des autres langages structurés. Mais il permet également (avec sonextension C++) de gérer des objets. A l'inverse, il permet également une programmation proche dulangage machine, ce qui est nécessaire pour accéder aux interfaces entre l'ordinateur et son extérieur.Mais son principal avantage est que ces trois types de programmation peuvent être combinés dans unmême programme, tout en restant portable sur tous les ordinateurs existants. Le langage C a néanmoinsdeux inconvénients majeurs, c'est d'être un peu plus complexe d'utilisation (mais uniquement du fait deses nombreuses possibilités), et d'être séquentiel, ce qui ne lui permettra pas d'être le langage optimalpour les machines massivement parallèles (mais aujourd'hui il n'existe pas encore de langage universelpour ce type de machines qui puisse combiner efficacement des calculs procéduraux et du déclaratif).

Ceci est la première partie du livre "Programmation en C, langage et algorithmes", qui est composé detrois parties.

* La première définit le langage C, avec de nombreux exemples directement dans le texte, et certainssupplémentaires en annexe.

* La seconde partie traite des structures de données et des algorithmes. Elle n'est pas spécifique, seuls lesexemples sont en C, le texte et les algorithmes restent utilisables dans tout langage séquentiel. Lesfonctionnalités du C non disponibles dans d'autres langages sont analysées, le méthodes utilisées pour

Le langage C - cours P.TRAU

http://www-ipst.u-strasbg.fr/pat/program/tpc_t.htm (1 of 2) [21-11-2001 17:40:49]

Page 19: algo

parvenir au même résultat sont précisées (par exemple, gestion d'un liste dynamique à l'aide d'untableau).

* La troisième partie quand à elle traite des algorithmes d'infographie. Elle est importante du fait de lanécessité du graphisme dans les programmes. Mais elle détaille également, pour ces cas pratiques, lesméthodes et moyens utilisés pour optimiser des algorithmes. Une bibliothèque graphique est fournie enannexe.

* Les parties que j'ai prévues, mais pas encore rédigées : utilisation des objets C++, programmationgraphique évennementielle (Microsoft Windows, X-Windows)

Introduction (première partie)●

Connaissances de base●

Fonctions d'entrées/sorties les plus utilisées●

La syntaxe du C●

Les fichiers de données●

Directives du pré-compilateur●

Utiliser Turbo C (3.5 par exemple)●

Correction des exercices●

Autres sites sur le C●

Sommaire●

Le langage C - cours P.TRAU

http://www-ipst.u-strasbg.fr/pat/program/tpc_t.htm (2 of 2) [21-11-2001 17:40:49]

Page 20: algo

Langage C - Index

A , B , C , D , E , F , G , H , I , K , L , M , N , O , P , Q , R , S, T , U , V , W

Aaccès direct [1] [2]●

accès séquentiel [1]●

addition [1]●

adresse [1]●

affectation [1] [2]●

alloc.h [1]●

allocation dynamique [1]●

ANSI [1] [2] [3] [4]●

antislash [1]●

arbre [1]●

argc [1]●

argument [1] [2] [3] [4] [5] [6]

formel [1] [2]❍

réel [1] [2]❍

argv [1]●

associativité [1]●

atof [1]●

atoi [1]●

atol [1]●

auto [1]●

Langage C - Index

http://www-ipst.u-strasbg.fr/pat/program/tpc_i.htm (1 of 9) [21-11-2001 17:40:58]

Page 21: algo

Bbibliothèque [1]●

bibliothèques standard [1]●

bit [1]●

blanc [1]●

bloc [1] [2] [3] [4]●

boucle [1]●

break [1] [2]●

buffer [1]●

Ccalloc [1]●

caractère [1] [2]●

case [1]●

cast [1] [2]●

chaîne [1] [2]●

champ [1]●

char [1] [2]●

classe [1] [2]●

close [1]●

commentaire [1]●

conio.h [1]●

continue [1]●

contrôle [1]●

conversion [1]●

corps [1]●

ctype.h [1]●

Ddéclaration [1] [2] [3]

de type [1]❍

Langage C - Index

http://www-ipst.u-strasbg.fr/pat/program/tpc_i.htm (2 of 9) [21-11-2001 17:40:58]

Page 22: algo

globale [1]❍

locale [1]❍

décrémentation [1]●

default [1]●

define [1] [2] [3]●

deuxaire [1]●

directive [1]●

division [1]●

do while [1]●

double [1]●

durée de vie [1]●

Eelse [1]●

entête [1]●

de fonction [1]●

entier [1] [2]●

entrées/sorties [1]●

enum [1]●

énumération [1]●

EOF [1] [2]●

errno.h [1]●

exit [1]●

expression [1] [2]●

extern [1]●

Ffaire tant que [1]●

fclose [1]●

fcntl.h [1]●

feof [1]●

fflush [1]●

Langage C - Index

http://www-ipst.u-strasbg.fr/pat/program/tpc_i.htm (3 of 9) [21-11-2001 17:40:58]

Page 23: algo

fgetc [1]●

fgets [1]●

fichier [1] [2]●

filelength [1]●

float [1]●

fonction [1] [2] [3]●

fopen [1]●

for [1]●

format printf [1]●

formaté [1] [2]●

fprintf [1]●

fputc [1]●

fputs [1]●

fread [1]●

free [1]●

fscanf [1]●

fseek [1]●

fwrite [1]●

Ggetch [1]●

getchar [1]●

getche [1]●

gets [1]●

goto [1]●

goto calculé [1]●

Hhandle [1]●

heap [1]●

Langage C - Index

http://www-ipst.u-strasbg.fr/pat/program/tpc_i.htm (4 of 9) [21-11-2001 17:40:58]

Page 24: algo

Iidentificateur [1]●

if [1] [2]

imbriqué [1]❍

ifdef [1]●

ifndef [1]●

include [1] [2]●

incrémentation [1]●

instruction [1]●

int [1]●

isalnum [1]●

isalpha [1]●

isdigit [1]●

islower [1]●

isspace [1]●

isupper [1]●

KKernigham [1]●

Llabel [1]●

liste [1]●

long [1] [2] [3]●

longueur d'identificateur [1]●

lseek [1]●

Lvalue [1]●

Mmacro [1]●

main [1]●

Langage C - Index

http://www-ipst.u-strasbg.fr/pat/program/tpc_i.htm (5 of 9) [21-11-2001 17:40:58]

Page 25: algo

malloc [1] [2]●

matrice [1]●

mem.h [1]●

memcmp [1]●

memcpy [1]●

NNULL [1] [2]●

Oopérande [1]●

opérateur [1] [2]●

open [1]●

Pparamètre [1]●

passage d'argument [1]●

pile [1] [2] [3]●

pointeur [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]●

pour [1]●

pré-compilateur [1]●

printf [1] [2]●

priorité [1]●

produit [1]●

prototype [1]●

putch [1]●

puts [1] [2]●

Qquote [1]●

Langage C - Index

http://www-ipst.u-strasbg.fr/pat/program/tpc_i.htm (6 of 9) [21-11-2001 17:40:58]

Page 26: algo

Rrécursivité [1]●

réel [1] [2]●

rand [1]●

read [1]●

realloc [1]●

register [1]●

return [1] [2]●

Ritchie [1]●

Rvalue [1]●

Sséquentiel [1]●

scalaire [1]●

scanf [1] [2]●

short [1] [2]●

si - Sinon [1]●

soustraction [1]●

sprintf [1]●

sscanf [1]●

static [1] [2] [3]●

stdio.h [1] [2]●

stdlib.h [1] [2]●

strcat [1]●

strcmp [1]●

strcpy [1]●

string.h [1]●

strlen [1]●

strncat [1]●

strncpy [1]●

struct [1] [2]●

structuré [1]●

Langage C - Index

http://www-ipst.u-strasbg.fr/pat/program/tpc_i.htm (7 of 9) [21-11-2001 17:40:58]

Page 27: algo

structure [1] [2]●

switch [1]●

Ttableau [1] [2] [3]●

tailles [1]●

tant que [1]●

tas [1]●

ternaire [1]●

tolower [1]●

toupper [1]●

typedef [1] [2] [3] [4]●

Uunaire [1]●

undef [1]●

ungetc [1]●

union [1]●

unsigned [1] [2] [3]●

Vvariable [1] [2]●

variables locales [1]●

visibilité [1]●

visible [1]●

void [1]●

Wwhile [1]●

write [1]●

Langage C - Index

http://www-ipst.u-strasbg.fr/pat/program/tpc_i.htm (8 of 9) [21-11-2001 17:40:58]

Page 28: algo

Langage C - Index

http://www-ipst.u-strasbg.fr/pat/program/tpc_i.htm (9 of 9) [21-11-2001 17:40:58]

Page 29: algo

LES VARIABLES SCALAIREScodage binaire●

boucles●

récursivité●

codage binaireLes seules valeurs que peut traiter l'ordinateur (et d'ailleurs tout système numérique) est le 0 et le 1 (enfait, c'est nous qui représentons par 0 ou 1 le fait que le système numérique ait vu du courant ou non). Unproblème important est que différents types d'informations doivent être codés : instructions machine(lignes de programmes), valeurs numériques, caractères, adresses,... et que rien ne permet de distinguerdans un groupe de 0 et de 1 le type d'information qu'il est censé représenter (10010110 est sur un PC lecode machine permettant d'échanger les contenus des registres SI et AX, mais également le code ducaractère 'û', de l'octet signé décimal -106, du signé 150, l'exposant du flottant 1,23x10-32, etc...). Il estdonc capital d'associer à chaque mémoire que l'on utilise le type de donnée que l'on y mettra. C'est ce quepermet la déclaration des variables dans les langages évolués (explicite en Pascal et en C, implicite enBasic et Fortran). Néanmoins cette erreur reste possible (en C, lors d'une erreur sur des pointeurs, parl'utilisation des unions, ou simplement par erreur de format dans un printf).

Une autre erreur est due à la représentation des nombres négatifs. En effet, le signe ne peut être, lui aussi,représenté que par 0 ou 1. Le codage choisi (pour les entiers 16 bits) fait que l'ajout de 1 à 32767 (le plusgrand entier signé) donne -32768 (cela devait de toute façon donner un nombre car soit il y a du courant,soit il n'y en a pas, il n'est pas prévu de combinaison de 0 et 1 représentant une erreur). La plupart descompilateurs ne signalent pas d'erreur en cas de dépassement de capacité de nombres entiers.

Autre problème, la codification des réels. Représenter la présence ou non d'une virgule par un 0 ou un 1est évidement impossible (comment la reconnaître ?), la première solution envisagée était donc la virgulefixe (un mot pour la partie entière, un autre pour la partie fractionnaire). On utilise désormais la "virguleflottante" (d'où le nom de flottants ou float), représentée par un mot pour la mantisse (qui est un réel envirgule fixe puisque pas de partie entière), un autre (souvent de taille différente) pour l'exposant (entiersigné). Ceci implique deux limitations : le nombre de chiffres significatifs (dû à la taille de la mantisse),et le plus grand réel codifiable (dû à la taille de l'exposant, par exemple 2127=1,7.1038). On chercheradonc à ne combiner que des réels du même ordre de grandeur. Par exemple en mécanique, ajouter à unedimension d'un mètre une dilatation thermique d'un micron n'a de sens que si les flottants possèdent plusde 6 chiffres significatifs, donc par exemple un algorithme cumulatif ne donnera pas de résultat si le pasen température est trop faible.

Dans les deux cas (virgule fixe ou flottante), un problème se pose : en fait, nous ne pouvons représenter

Données et Algorithmique - LES VARIABLES SCALAIRES

http://www-ipst.u-strasbg.fr/pat/program/algo02.htm (1 of 4) [21-11-2001 17:41:05]

Page 30: algo

qu'un sous ensemble des réels (je ne pense pas que les mathématiciens lui aient donné un nom) quicorrespond à la différence, en base 10, entre D et R. En fait on ne peut représenter que les nombrespouvant s'écrire sous forme d'une partie fractionnaire comportant un nombre fini de chiffres (en binaire).Or, comme c'est impossible en base 10 pour 1/3 (qui pourtant s'écrit 0,1 en base 3) la représentation enbinaire de 1/10 donne une suite infinie, qui est donc toujours tronquée (0,1d =0,000100100100100100100...b). donc sur tout ordinateur calculant en binaire, (1/10)*10 donne0,999999999... Cette erreur devient gênante dans le cas où le résultat du calcul précédent est utilisé dansle calcul suivant, pour de grandes suites de calculs.

exemple (flottant):

#include <stdio.h>void main(void) { float x=1000; int i; for (i=0;i<10000;i++)x+=0.1; printf("On obtient %12.4f au lieu de 2000.0000\n",x); }

Ce problème est moins flagrant en C que dans les autres langages, le C effectuant toujours les calculs surdes réels en double précision. Il en résulte néanmoins que, par exemple, il ne faut pas tester dans unprogramme si le résultat d'un calcul flottant est nul mais si sa valeur absolue est inférieure à un petitnombre. On cherchera aussi, autant que possible, à choisir des algorithmes utilisant des entiers plutôt quedes réels, d'autant plus que les calculs sur des flottants sont plus lents que sur des réels.

bouclesTous les langages possèdent des structures permettant de répéter des instructions, les boucles. En général,certaines sont réservées aux cas où l'on connaît à l'entrée le nombre de boucles à effectuer (for en C), etcelles dont on connaît la condition d'arrêt (while et do-while en C). (voir exemples dans la premièrepartie).

Lorsqu'une valeur à calculer C dépend de n calculs intermédiaires Ci (que l'on ne désire pas mémoriser),la méthode la plus simple consiste à initialiser C à la première valeur C1, puis pour i variant de 2 à n,calculer chaque Ci et le cumuler à C. C'est en général la méthode utilisée pour les calculs de sommes,produits, suites...

exemple (boucle_A) : calculer xn :

#include <stdio.h>void main(void) { int n,i,x,result; printf("entrez x et n : ");

Données et Algorithmique - LES VARIABLES SCALAIRES

http://www-ipst.u-strasbg.fr/pat/program/algo02.htm (2 of 4) [21-11-2001 17:41:05]

Page 31: algo

scanf("%d %d",&x,&n); result=x; for(i=1;i<n;i++)result*=x; printf("résultat : %d\n",result); }

La fonction puissance est souvent disponible dans les langages (pow en C), mais correspond à un calculassez long et souvent moins précis (xn=exp(n*ln(x)) qui donne toujours un résultat avec une erreur deprécision même si x est entier). La méthode ci-dessus sera plus rapide soit pour n petit (quelquesmultiplications d'entiers sont plus rapides qu'une exponentielle de logarithme), soit quand toutes lespuissances intermédiaires doivent être connues.

Exercice (boucle) : faire le programme calculant 2x4-3x3+x2-5x+2 pour x réel.

exemple (boucle_B) : calcul de moyenne :

#include <stdio.h>void main(void) { int n=0; float note,moy=0; do { printf("entrez la note (négative pour terminer) : "); scanf("%f",&note); if(note>=0) { moy+=note; n++; } } while(note>=0); moy/=n; printf("moyenne : %f\n",moy); }

Les valeurs des notes ayant servi au calcul ne sont pas mémorisées, car toutes stockées successivementdans la même mémoire.

récursivitéOn appelle fonction récursive une fonction qui s'appelle elle-même. La récursivité n'est possible que dansun langage acceptant des variables locales. En effet, l'emploi de la récursivité n'est réellement utile quelorsqu'une fonction doit retrouver, après un appel récursif, toutes ses variables locales dans leur étatinitial. Dans le cas contraire, une méthode itérative (boucle) sera en général plus efficace (il est inutile demémoriser les variables locales et les restaurer pour ne plus les réutiliser), comme par exemple pour lecalcul d'une factorielle (voir mon document sur le C, paragraphes 4.6 et 4.7, pour l'explication de la

Données et Algorithmique - LES VARIABLES SCALAIRES

http://www-ipst.u-strasbg.fr/pat/program/algo02.htm (3 of 4) [21-11-2001 17:41:05]

Page 32: algo

récursivité, l'empilement des variables locales et l'exemple de la factorielle).

Néanmoins dans un certain nombre de cas, l'emploi de la récursivité facilite la programmation. Si letemps de calcul ou la mémoire utilisée sont prohibitifs pour de grands nombres de données, il esttoujours possible de traduire un algorithme récursif en itératif, et souvent de manière plus efficace que lecompilateur, qui est obligé de le faire (le langage machine n'est pas récursif) sans connaître aussi bienque vous les conditions d'utilisation de l'algorithme.

Données et Algorithmique - LES VARIABLES SCALAIRES

http://www-ipst.u-strasbg.fr/pat/program/algo02.htm (4 of 4) [21-11-2001 17:41:05]

Page 33: algo

LES TABLEAUX STATIQUEStableaux unidimensionnels

généralités❍

fonctions de base (fichier inclus base_tus)❍

manipulations dans les tableaux (mani_tus)❍

tris

généralités (valables également pour d'autres types de données)■

le tri bulle■

le tri par insertion■

le tri par sélection■

le tri shell■

le tri rapide (Quick Sort)■

le tri par création■

d'autres tris■

recherches

la recherche séquentielle■

la dichotomie■

calculs mathématiques

calcul vectoriel■

polynômes■

tableaux multidimensionnels●

conclusions●

tableaux unidimensionnels

généralités

Un tableau permet de regrouper dans une structure plusieurs valeurs scalaires de même type. Pour permettre unemaintenance aisée du programme, la dimension doit être définie par une constante. C'est cette dernière qui serautilisée pour les tests de dépassement (peu de compilateurs le font automatiquement, ils le feraient par exemple àl'intérieur d'une boucle alors que le test sur la valeur finale serait suffisant). La taille réellement utilisée peut êtreinférieure ou égale à la dimension du tableau, les composantes au delà de la taille utilisée peuvent être mises à 0mais cela n'a aucun intérêt, sauf si on interdit le 0 dans le tableau (cas des caractères, en C).

Données et Algorithmique - LES TABLEAUX STATIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo03.htm (1 of 15) [21-11-2001 17:41:35]

Page 34: algo

Nous allons travailler dans un premier temps sur des tableaux de flottants. Nous utiliserons des tableaux dont lepremier indice est 0 puisque c'est la seule possibilité en C, et la solution optimale dans les autres langagespuisque nécessitant moins de calculs dans le code compilé. Si tous les tableaux utilisés ont la même dimension,on peut définir de manière globale :

#define composante float#define dim_tus 100typedef composante type_tus[dim_tus];

Ces déclarations sont nécessaires dans les langages effectuant un contrôle très strict des types de données(comme le Pascal) et refusant de combiner des tableaux de tailles différentes. En C, nous pouvons préparer desfonctions sur tous tableaux de réels, quelle que soit leur dimension :

#define composante floattypedef composante type_tus[]; /* ou typedef composante *type_tus */

C'est cette seconde déclaration que nous utiliserons dans les exemples suivants.

Remarque : dans notre cas il peut être intéressant de définir un tableau comme une structure regroupant letableau, sa dimension et sa taille effective.

fonctions de base (fichier inclus base_tus)

Les fonctions de base sur les tableaux unidimensionnels sont l'initialisation du tableau, l'ajout d'une valeur en findu tableau, et l'affichage de tout le tableau :

void init_tus(type_tus tab,int *taille,int dim) { int i; for(i=0;i<dim;i++) tab[i]=0; *taille=0; }

L'initialisation à 0 n'est pas nécessaire dans la plupart des cas. La taille est passée par adresse puisque modifiéepar la fonction init_tus.

int ajoute_val_tus(type_tus tab,int *taille,int dim,composante val)/* retourne 0 si tout s'est bien passé, 1 si erreur */ { if (*taille>=dim) { puts("dépassement de capacité du tableau"); return(1); } /* le else n'est pas nécessaire du fait du return précédent */ tab[(*taille)++]=val; return(0); }

void affiche_tus(type_tus tab,int taille) {

Données et Algorithmique - LES TABLEAUX STATIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo03.htm (2 of 15) [21-11-2001 17:41:35]

Page 35: algo

int i; for(i=0;i<taille;i++) printf("%dième valeur :%f\n",i+1,tab[i]); }

Les déclarations globales et fonctions ci-dessus étant recopiées dans le fichier "base_tus", nous pouvons écrire leprogramme suivant (ex_tus) :

#include <stdio.h>#include "base_tus.inc"#define dim 100void main(void) { int nb; composante v,t[dim]; init_tus(t,&nb,dim); do { printf("entrez la %dième note (fin si <0 ou >20) :",nb+1); scanf("%f",&v); if(v<0||v>20) break; /* on aurait pu le mettre dans la condition du while */ } while (!ajoute_val_tus(t,&nb,dim,v)); affiche_tus(t,nb); }

Exercice (tusexo_a) : modifier ce programme pour qu'il calcule la moyenne et affiche, pour chaque note, l'écartavec la moyenne (ce qui nécessite l'utilisation d'un tableau car il faut d'abord calculer la moyenne puis utiliser lesnotes mémorisées auparavant).

manipulations dans les tableaux (mani_tus)

L'insertion et la suppression de composantes d'un tableau nécessitent des décalages des autres composantes dutableau:

void suppr_tus(type_tus tab,int *taille,int position) { int i; if(position>=*taille||position<0)return; (*taille)--; for(i=position;i<*taille;i++)tab[i]=tab[i+1]; }

On peut remarquer que la suppression de la dernière composante n'entraîne aucun décalage.

int insert_tus(type_tus tab,int *taille,int dim,int position,composante val)/* retourne 0 si pas d'erreur */ { int i; if(position<0)return(1);

Données et Algorithmique - LES TABLEAUX STATIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo03.htm (3 of 15) [21-11-2001 17:41:35]

Page 36: algo

if(position>*taille)position=*taille; if (*taille>=dim) { puts("dépassement de capacité du tableau"); return(2); } for(i=*taille;i>position;i--)tab[i]=tab[i-1]; tab[position]=val; (*taille)++; return(0); }

Le décalage doit se faire par indice décroissant (par indice croissant, on recopierait progressivement lacomposante à l'indice position dans tout le reste du tableau).

Les rotations sont également des manipulations fréquentes sur les tableaux :

void rot_gauche_tus(type_tus tab,int taille) { composante tampon; int i; tampon=tab[0]; for(i=1;i<taille;i++)tab[i-1]=tab[i]; tab[taille-1]=tampon; }void rot_droite_tus(type_tus tab,int taille) { composante tampon; int i; tampon=tab[taille-1]; for(i=taille-1;i>0;i--)tab[i]=tab[i-1]; tab[0]=tampon; }

Exercice (tusexo_b) : faire un programme permettant de tester ces fonctions, à l'aide d'un menu permettantd'essayer dans n'importe quel ordre ces fonctions.

tris

généralités (valables également pour d'autres types de données)

Les exemples qui suivent traitent des tableaux de flottants, les méthodes étant identiques pour tout type decomposante à condition d'y définir une relation d'ordre (par exemple, pour des chaînes de caractères on utiliserastrcmp au lieu de <, > et =). Mais il ne faut pas oublier que l'efficacité de l'algorithme dépend également destypes de données traitées : une comparaison de chaînes de caractères étant relativement longue, les algorithmeseffectuant beaucoup de tests seront moins efficaces qu'avec des flottants. De même, les tableaux trop gros pourentrer en mémoire devront être traités sur support externe, rendant l'accès aux données (plusieurs millisecondes)bien plus lent que les tests ou calculs (micro voire nanosecondes). Dans les cas plus complexes, comme parexemple les tableaux de structures, on appelle clef le champ servant pour le tri (par exemple le nom pour untableau contenant nom, prénom, adresse,...). Dans ce cas, les calculs sur les clefs seront souvent plus rapides queles déplacements des structures entières. Les méthodes de tris présentées ici sont souvent utilisables également

Données et Algorithmique - LES TABLEAUX STATIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo03.htm (4 of 15) [21-11-2001 17:41:35]

Page 37: algo

avec les autres types de données, mais les conclusions sur leur efficacité varieront. On qualifiera de stable un trilaissant dans le l'ordre initial les éléments de clef identique (par exemple, un stock saisi au fur et à mesure desarrivées de matériel, le classement par ordre alphabétique gardant les matériels de même nom dans leur ordred'arrivée sera stable). Tous les algorithmes décrits ici sont stables, à condition d'y prendre garde (scruter letableau du début vers la fin et non l'inverse par exemple). Dans ce chapitre, nous noterons N le nombre decomposantes du tableau (appelé taille auparavant).

le tri bulle

Cet algorithme est relativement connu, bien qu'il soit rarement efficace (en termes de temps de calcul, le tri estnéanmoins correct, bien évidement). Il consiste à balayer tout le tableau, en comparant les éléments adjacents etles échangeant s'ils ne sont pas dans le bon ordre. Un seul passage ne déplacera un élément donné que d'uneposition, mais en répétant le processus jusqu'à ce plus aucun échange ne soit nécessaire, le tableau sera trié.(bull_tus)

void tri_bulle_tus(type_tus tab, int N) { int ok,i; composante tampon; do { ok=1; /* vrai */ for(i=1;i<N;i++) if(tab[i-1]>tab[i]) { ok=0; tampon=tab[i-1]; tab[i-1]=tab[i]; tab[i]=tampon; } } while(!ok); }

Ce tri va nécessiter un grand nombre de déplacements d'éléments, il est donc inutilisable dans les cas où cesdéplacements sont coûteux en temps. Il va nécessiter N-1 boucles principales dans le cas où le dernier élémentdoit être placé en premier. Le nombre de boucles internes maximal est donc de l'ordre de (N-1)2. Il peut parcontre être intéressant quand le tableau initial est déjà pré-trié, les éléments n'étant pas disposés trop loin de leurposition finale (par exemple classement alphabétique où les éléments sont déjà triés par leur première lettre).

Plutôt que de déplacer un élément dans une position meilleure que la précédente mais néanmoins mauvaise, lesdeux algorithmes qui suivent tentent de déplacer les éléments directement en bonne position.

le tri par insertion

Plutôt que de déplacer les éléments d'une position, on peut prendre un élément après l'autre dans l'ordre initial, etle placer correctement dans les éléments précédents déjà triés, comme on le fait lorsque l'on classe ses cartes àjouer après la donne (inse_tus) :

void tri_insertion_tus(type_tus tab, int N) {

Données et Algorithmique - LES TABLEAUX STATIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo03.htm (5 of 15) [21-11-2001 17:41:35]

Page 38: algo

int pt,ppg; /* position testée, premier plus grand */ composante tampon; for(pt=1;pt<N;pt++) { ppg=0; while(tab[ppg]<=tab[pt]&&ppg<pt)ppg++; if(ppg<pt) { tampon=tab[pt]; suppr_tus(tab,&N,pt); insert_tus(tab,&N,32767,ppg,tampon); /* je suis sur de ne pas dépasser la dimension puisque je viens de supprimer un élément */ } } }

Le nombre maximal de boucles internes est descendu à N(N-1)/2, on a au maximum N-1 couples desuppression/insertion mais qui eux effectuent en moyenne environ N/2 échanges d'éléments, ce qui amène unmaximum d'échanges de l'ordre de N2, ce qui n'est pas satisfaisant. On peut néanmoins améliorer l'implantationde cet algorithme en optimisant la recherche de la position d'un élément dans la partie déjà triée, par dichotomiepar exemple (voir chapitre sur les recherches), ainsi qu'en améliorant le couple suppression/insertion (ne décalerque les éléments entre la position finale et la position initiale, par une rotation à droite). On remplace la boucleprincipale par :

for(pt=1;pt<N;pt++) { dpg=pt-1; tampon=tab[pt]; while(tab[dpg]>tampon&&dpg>=0) {tab[dpg+1]=tab[dpg];dpg--;} tab[dpg+1]=tampon; }

Le tri par insertion peut être intéressant pour des tableaux ayant déjà été triés, mais où l'on a rajouté quelquesnouveaux éléments en fin de tableau (dans ce cas il faut améliorer l'implantation pour découvrir rapidement lepremier élément mal placé, puis utiliser l'algorithme complet pour les éléments restants). Dans les autres cas, ilsera plutôt réservé aux types de données permettant une insertion rapide (listes chaînées par exemple).

le tri par sélection

Le but est désormais de déplacer chaque élément à sa position définitive. On recherche l'élément le plus petit. Ilfaut donc le placer en premier. Or cette position est déjà occupée, on se propose donc d'échanger les deuxéléments. Il ne reste plus qu'à répéter l'opération N fois (sele_tus):

void tri_selection_tus(type_tus tab, int N) { int pd,pp,i; /* place définitive, plus petit */ composante tampon; for(pd=0;pd<N-1;pd++)

Données et Algorithmique - LES TABLEAUX STATIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo03.htm (6 of 15) [21-11-2001 17:41:35]

Page 39: algo

{ pp=pd; for(i=pp+1;i<N;i++) if(tab[i]<tab[pp])pp=i; tampon=tab[pp]; tab[pp]=tab[pd]; tab[pd]=tampon; } }

Chaque échange met un élément en position définitive, l'autre par contre est mal placé. Mais aucun échange n'estinutile. Un élément qui a été bien placé ne sera plus testé par la suite. Le nombre de boucles internes est environN(N-1)/2, ce qui est meilleur que le tri bulle, mais toujours de l'ordre de N2. Par contre le nombre dedéplacements d'éléments est au maximum de 2(N-1), la moitié étant des déplacements nécessaires, ce qui estfaible pour un fichier en désordre total, mais n'est pas optimal pour les fichiers dont la première partie est déjàclassée (et grande par rapport à la taille totale). Une amélioration possible serait d'essayer de placer le secondélément de l'échange dans une position pas trop mauvaise, à condition que cette recherche ne soit pas elle mêmeplus gourmande en temps.

le tri shell

C'est une amélioration du tri par insertion : au lieu d'effectuer une rotation de tous les éléments entre la positioninitiale et finale (ou du moins meilleure) d'un élément, on peut faire des rotations par pas de P, ce qui rendra lefichier presque trié (chaque élément sera à moins de P positions de sa position exacte). On répète ce tri pour Pdiminuant jusqu'à 1. Une suite possible pour P est de finir par 1, les pas précédents étant de 4, 13, 40, 121, 364,1093... (Pi=3*Pi-1 +1). D'autres suites sont évidement possibles, à condition de prendre des valeurs qui ne soientpas multiples entre elles (pour ne pas toujours traiter les mêmes éléments et laisser de côté les autres, par exempleles puissances successives de 2 ne traiteraient que les positions paires, sauf au dernier passage. Exempled'implantation (shel_tus) :

void tri_shell_tus(type_tus tab, int N) { int pt,dpg,P; /* position testée,dernier plus grand */ composante tampon; for(P=1;P<=N/9;P=3*P+1); /* calcul de P initial (<=N/9) */ for(;P>0;P/=3) /* inutile de soustraire 1 car division entière */ { for(pt=P;pt<N;pt++) { dpg=pt-P; tampon=tab[pt]; while(tab[dpg]>tampon&&dpg>=P-1) {tab[dpg+P]=tab[dpg];dpg-=P;} tab[dpg+P]=tampon; } } }

L'intérêt de ce tri, bien qu'il ait une boucle autour du tri par insertion, est qu'il crée rapidement un fichier presquetrié, le dernier tri par insertion sera donc beaucoup plus rapide. Il est en général plus rapide que le tri par insertionpour les fichiers complètement mélangés, mais pour certains tableaux et pour certaines suites de P, il peut être

Données et Algorithmique - LES TABLEAUX STATIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo03.htm (7 of 15) [21-11-2001 17:41:35]

Page 40: algo

bien plus mauvais que les autres tris.

le tri rapide (Quick Sort)

Ce tri est récursif. On cherche à trier une partie du tableau, délimitée par les indices gauche et droite. On choisitune valeur de ce sous-tableau (une valeur médiane serait idéale, mais sa recherche ralentit plus le tri que deprendre aléatoirement une valeur, par exemple la dernière), que l'on appelle pivot. Puis on cherche la positiondéfinitive de ce pivot, c'est à dire qu'on effectue des déplacements de valeurs de telle sorte que tous les élémentsavant le pivot soient plus petits que lui, et que toutes celles après lui soient supérieures, mais sans chercher à lesclasser pour accélérer le processus. Puis on rappelle récursivement le tri de la partie avant le pivot, et de celleaprès le pivot. On arrête la récursivité sur les parties à un seul élément, qui est donc nécessairement triée.(Quick_tus)

void tri_rapide_tus(type_tus tab,int gauche,int droite) { int g,d; composante tampon,val; if(droite<=gauche)return; /* fin de récursivité si tableau d'une seule case à trier */ /* choix du pivot : on prend par exemple la valeur de droite */ val=tab[droite]; g=gauche-1; d=droite; do { while(tab[++g]<val); /* g pointe le premier élément (à gauche) plus grand (ou égal) que le pivot */ while(tab[--d]>val); /* d pointe le premier élément (par la droite) plus petit (ou égal) que le pivot */ if(g<d) /* si g et d ne se sont pas rencontrés, on échange les contenus de g et d et on recommence */ {tampon=tab[g];tab[g]=tab[d];tab[d]=tampon;} } while(g<d); /* on sort quand g a rencontré d, alors tous les éléments à gauche de g sont <= au pivot, tous ceux à droite de d sont >= *//* on place le pivot en position g (d serait aussi possible), donc dans sa bonne position (tous ceux à gauche sont <=, à droite sont >=) */ tampon=tab[g];tab[g]=tab[droite];tab[droite]=tampon; /* il ne reste plus qu'à trier les deux parties, à droite et à gauche du pivot */ tri_rapide_tus(tab,gauche,g-1); tri_rapide_tus(tab,g+1,droite); }

On appelle le tri d'un tableau complet par : tri_rapide_tus(tableau, 0, N-1). On peut remarquerque cette implantation du tri n'est pas stable, mais peut l'être en gérant les égalités avec le pivot, mais enralentissant le tri. On effectue dans la boucle deux tests (g<d), on peut supprimer le second par une boucle infinieet un break dans le if. Ce tri fait en moyenne 2Nlog(N) boucles, sur des fichiers bien mélangés, mais N2 sur unfichier déjà trié (et dans ce cas la profondeur de récursivité est N, ce qui est prohibitif). Mais ces boucles sont

Données et Algorithmique - LES TABLEAUX STATIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo03.htm (8 of 15) [21-11-2001 17:41:35]

Page 41: algo

longues et gourmandes en mémoire du fait de la récursivité: chaque appel de fonction est assez long, il fautmémoriser l'état actuel. On peut optimiser le tri en remplaçant la récursivité par des boucles (obligatoire si lelangage utilisé n'est pas récursif), ce qui évite d'empiler des adresses, mais la gestion des variables locales doitêtre remplacée par gestion par pile (voir plus loin) pour mémoriser les sous-tris en attente, ce qui permettrad'accélérer le tri mais nécessite une programmation complexe (rappel : la récursivité sera automatiquementsupprimée par le compilateur, cette transformation par le programmateur peut être plus efficace).

Plutôt que d'arrêter la récursivité sur des sous-tableaux de taille 1, on peut s'arrêter avant (entre 5 et 25 engénéral) pour éviter une profondeur de récursivité trop importante. Le fichier est alors presque trié, on peut alorseffectuer un tri par insertion qui dans ce cas sera très rapide. Une autre amélioration possible est de mieux choisirle pivot. la solution idéale est de trouver à chaque fois la valeur médiane du sous-tableau à trier, mais sarecherche précise rend le tri plus lent que sans elle. Une solution quelquefois utilisée est de prendre par exempletrois valeurs, pour en prendre la valeur médiane, par exemple tab[droite], tab[gauche] et tab[(droite+gauche)/2](dans le cas d'un fichier parfaitement mélangé, le choix de trois positions n'a pas d'importance, mais dans desfichiers presque triés le choix ci-dessus est plus judicieux). La totalité de ces améliorations peut apporter un gainde l'ordre de 20% par rapport à la version de base.

le tri par création

Lorsqu'il est nécessaire de disposer simultanément du tableau initial et du tableau trié, on peut recopier le tableauinitial puis effectuer un tri sur la copie, ou adapter un des algorithmes précédents. Par exemple, à partir du tri parsélection, l'algorithme consiste à rechercher l'élément le plus petit, le copier en première position du tableau final,rechercher le suivant, le placer en seconde position, etc... En cas d'éléments identiques, il y a lieu de marquer leséléments déjà choisis, par exemple à l'aide d'un troisième tableau d'indicateurs (le tri est alors stable), ou suivantl'exemple (crea_tus) ci-dessous (ceci n'est qu'un exemple, d'autres possibilités existent) :

int le_suivant(type_tus ti, int taille, int precedent) { int pos,i;/* 1) recherche du premier égal au précédent */ pos=precedent+1; while(pos<taille&&ti[pos]!=ti[precedent])pos++; if(pos<taille)return(pos);/* 2) sinon, recherche du suivant mais différent dans tout le tableau */ pos=0; while(ti[pos]<=ti[precedent])pos++; /* le 1er > precedent */ for(i=pos+1;i<taille;i++) /*le plus petit dans la suite */ if(ti[i]>ti[precedent]&&ti[i]<ti[pos])pos=i; return(pos); }

void tri_creation_tus(type_tus ti, type_tus tf, int taille)/* ti tableau initial, tf tableau final (trié) */ { int i,imin=0; for(i=1;i<taille;i++)if(ti[i]<ti[imin])imin=i; tf[0]=ti[imin]; for(i=1;i<taille;i++) {

Données et Algorithmique - LES TABLEAUX STATIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo03.htm (9 of 15) [21-11-2001 17:41:35]

Page 42: algo

imin=le_suivant(ti,taille,imin); tf[i]=ti[imin]; } }

On peut remarquer que ce tri minimise le nombre de copies des éléments, mais nécessite beaucoup decomparaisons de clefs (en particulier un élément déjà sélectionné sera encore comparé par la suite). Ceci peut êtreacceptable pour un fichier séquentiel à grands champs, sur bande par exemple, mais dont les clefs peuvent êtrestockées complètement en mémoire. On verra d'autres propositions dans le cas des fichiers.

d'autres tris

Suivant les données à trier, il peut être plus efficace de construire un algorithme de tri spécifique. Par exemple, sile tableau contient un grand nombre de valeurs similaires (exemple : gestion annuelle d'un stock où la plupart desarticles entrent et sortent plusieurs fois par jour), on peut utiliser l'algorithme simple (par création) consistant àrechercher l'élément le plus petit, compter le nombre de ces éléments, les mettre dans le tableau destination, etrépéter l'opération jusqu'à la fin du fichier destination. C'est le tri par comptage. Dans le cas où le nombre de clefsdifférentes est suffisamment faible, on peut utiliser un tableau de compteurs, ce qui permet d'effectuer lecomptage en un seul balayage du fichier.

Dans la cas où les clefs sont bornées (c'est à dire comprises entre un minimum et un maximum connus à l'avance)et en nombre fini, on peut utiliser le tri basique : par exemple si toutes les clefs sont des entiers entre 000 et 999,on peut séparer le tableau en 10 parties en fonction des centaines, puis récursivement traiter les dizaines puis lesunités (tri en base 10). Evidement, un tri en base 2 sera plus efficace sur ordinateur : on part à gauche ,on avancejusqu'à trouver un nombre commençant par 1, puis par la droite jusqu'à trouver un nombre commençant par 0, leséchanger et continuer jusqu'à croisement des deux côtés. Puis on recommence (récursivement par exemple) sur lebit suivant, jusqu'à tri complet. Pour trier des clefs alphabétiques, on peut effectuer un tri en base 26, sur les Npremiers caractères (N pouvant valoir 2 ou 3 par exemple), le fichier est alors presque trié. Il est alors plusefficace d'effectuer un tri par insertion (passe de finition) plutôt que de répéter le tri basique jusqu'à tri complet.

Le tri par fusion utilise un algorithme de fusion de deux tableaux triés en un seul plus grand, appelérécursivement sur les deux moitiés du tableau, jusqu'à une taille de tableau de 1 (ou plus, avec un tri spécifiquepour petits tableaux, par exemple par échange sur des sous-tableaux de 3 éléments)

recherches

On a souvent besoin de rechercher, dans un grand tableau, la position d'un élément donné. Un point particulier àne pas oublier pour tous les algorithmes est le traitement du cas où l'élément cherché n'est pas dans le tableau.Une autre caractéristique importante d'un algorithme de recherche est son comportement désiré en cas d'élémentsidentiques (doit-il donner le premier, le dernier, tous ?).

la recherche séquentielle

Il suffit de lire le tableau progressivement du début vers la fin. Si le tableau n'est pas trié, arriver en fin du tableausignifie que l'élément n'existe pas, dans un tableau trié le premier élément trouvé supérieur à l'élément recherchépermet d'arrêter la recherche, de plus cette position correspond à celle où il faudrait insérer l'élément cherchépour garder un tableau trié. Une recherche sur un tableau trié nécessitera en moyenne N/2 lectures, mais on serapprochera de N pour un fichier non trié avec beaucoup de recherches d'éléments inexistants.

int rech_sequentielle_tus(type_tus tab, int N, composante val)/* rend -1 si val non trouvée, première occurence trouvée sinon */

Données et Algorithmique - LES TABLEAUX STATIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo03.htm (10 of 15) [21-11-2001 17:41:35]

Page 43: algo

{ int i; for(i=0;i<N;i++)if(tab[i]==val)return(i); return(-1); }

la dichotomie

Dans le cas d'un tableau trié, on peut limiter le nombre de lectures à log(N)+1, en cherchant à limiter l'espace derecherche. On compare la valeur cherchée à l'élément central du tableau, si ce n'est pas la bonne, un test permetde trouver dans quelle moitié du tableau on trouvera la valeur. On continue récursivement jusqu'à un sous-tableaude taille 1. Il vaut bien mieux implanter cet algorithme de manière itérative, car la fonction se rappelle jusqu'àtrouver la position désirée, puis seulement on effectue les dépilages, alors que l'on n'a plus besoin des étatsintermédiaires qui ont été mémorisés par la récursivité puisque le problème est résolu.

int rech_dichotomie_tus(type-tus tab, int N, composante val) { int g,m,d; /* gauche, milieu, droite */ g=0;d=N; while (g<=d) { m=(g+d)/2; /* division entière */ if(val<tab[m])d=m-1; else if(val>tab[m])g=m+1; else return(m) } return(-1); }

L'utilisation de la variable m permet d'éviter plusieurs calculs de (g+d)/2. Dans certains cas il peut être intéressantde prévoir également une mémorisation de tab[m], mais pas pour les tableaux puisqu'ils permettent d'accès direct.L'ordre des tests est important, l'égalité ayant statistiquement moins de chances, elle doit être traitée en dernier(donc faire le maximum de tests dans le cas le moins probable). Si on avait traité l'égalité en premier, tous lesautres cas auraient nécessité deux tests, l'égalité puis la sélection de la partie droite ou gauche. En cas demultiples éléments correspondants à la valeur cherchée, on retourne la position de l'un d'eux, mais pasnécessairement le premier ou le dernier. Pour retourner le premier par exemple, il suffit de rajouter une boucletestant l'égalité vers la gauche, à n'effectuer qu'une seule fois bien évidement, lorsque une valeur adéquate a étélocalisée. On peut améliorer l'algorithme en comparant val à tab[g] et tab[d], pour estimer la position recherchéeplutôt que de la supposer au milieu, comme on effectue une recherche dans un dictionnaire :m=g+(int)((val-tab[g])*(d-g)/(tab[d]-tab[g])). Attention, ce calcul se fait sur descomposantes (par exemple des flottants), ce qui est toujours plus long que de simples calculs sur des entiers.

calculs mathématiques

Les tableaux unidimensionnels permettent de résoudre simplement divers problèmes mathématiques. Nous allonsen traiter certains.

calcul vectoriel

L'utilisation des tableaux statiques est bien indiquée pour le calcul vectoriel. En effet, toutes les variables seront

Données et Algorithmique - LES TABLEAUX STATIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo03.htm (11 of 15) [21-11-2001 17:41:35]

Page 44: algo

de même dimension. Il est aisé de prévoir une bibliothèque de fonctions vectorielles comportant toutes lesopérations de base (multiplication par un réel, produit scalaire, produit vectoriel, produit mixte, norme...). Ungrand nombre de problèmes géométriques se résoudront bien plus facilement par calcul vectoriel que de manièreparamétrique.

polynômes

Une manière (mais il y en a d'autres) de représenter un polynôme est le tableau de ses coefficients. Par exemplef(x)=4x3+x+2 sera représenté par le tableau 2,1,0,4 (en mettant le coefficient de xi en position i). L'évaluationd'un polynôme (c'est à dire le calcul de sa valeur pour un x donné) ne doit pas utiliser de fonction puissances maisuniquement des multiplications successives, puisque toutes les puissances intermédiaires sont nécessaires. Lasomme de polynômes est triviale (somme des coefficients), le produit à peine plus compliqué (à moins que l'onait besoin d'une optimisation poussée, dans ce cas on peut réduire d'1/4 le nombre de multiplications mais avecune complexité accrue). La résolution de l'équation f(x)=0 (recherche de racines) peut se faire par dichotomie parexemple (il faut alors donner le premier intervalle de recherche), en cas de racines multiples on en trouve une auhasard. Une recherche de racines plus efficace nécessite des algorithmes complexes, rarement universels (c'est àdire que dans certains cas ils ont un résultat déplorable, voire faux ou plantage de l'ordinateur en cas dedivergence) qui ne seront pas traités ici, mais une littérature abondante existe sur ce sujet.

L'interpolation polynomiale correspond elle à la recherche d'une courbe polynomiale passant par N+1 pointsdonnés : P(xi)=yi pour i entre 0 et N. La solution la plus simple consiste à choisir le polynôme de Lagrange(d'ordre N):

N N

P(x)= ( yj (x-xi)/(xj-xi) )

j=0i=0

i!=j

qui est le plus rapide à déterminer mais donne des résultats décevants pour N assez grand (100 par exemple),puisque les seules conditions imposées sont des points de passage, on obtient (souvent près des points extrêmes)une courbe assez "folklorique" entre certains points. Une méthode souvent plus satisfaisante est l'utilisation des"splines", qui cherche parmi les multiples polynômes d'ordre N passant par N+1 points celui qui minimise unequadratique (en fait, correspond à la minimisation de l'énergie de déformation d'une poutre passant par ces points,d'où le nom de spline, "latte" en anglais) (voir mon support de cours sur l'infographie). Ou alors on peut utiliserune approximation (polynôme d'ordre M<N) passant au voisinage des points (par exemple moindres carrés).

tableaux multidimensionnelsUn tableau à N dimensions est en fait un tableau unidimensionnel de tableaux de N-1 dimensions. Tout ce qui aété présenté auparavant reste donc valable. La décision d'utiliser des tableaux multidimensionnels doit être bienréfléchie : ces tableaux nécessitant beaucoup de mémoire, il faut évaluer le ratio de composantes utiles parrapport aux places mémoire utilisées. Par exemple un tableau 10x10x10 utilisant dans chacune des 3 directionsune seule fois les 10 mémoires prévues, les autres fois on s'arrête en moyenne à 7 (si ce n'est pas moins), réserve1000 mémoires, dont seulement 352 utiles (7x7x7+3+3+3).

Outre les tableaux de chaînes de caractères, les tableaux multidimensionnels les plus utilisés sont les matrices Lesalgorithmes de base du calcul matriciel (base_mat) sont la mise à 0, la recopie, l'addition et le produit dematrices, qui sont simples à mettre en place (le produit entraîne néanmoins N3 multiplications, des algorithmesplus performants existent mais ne commencent à être rentables que pour N très grand, entre 10000 et un million

Données et Algorithmique - LES TABLEAUX STATIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo03.htm (12 of 15) [21-11-2001 17:41:35]

Page 45: algo

!).

Par contre, le problème de l'inversion d'une matrice est plus complexe. Elle est utilisée principalement pour larésolution de N équations à N inconnues, représentées par une matrice NxN. La méthode de Gauss estcertainement la plus simple à mettre en oeuvre, bien que pouvant poser problème dans certains cas particuliers.On utilise en fait la méthode de résolution d'un système d'équations A.X=B par substitution. Nous allons lepréciser sur un exemple :

1 1 -2 x1 2

1 3 -4 * x2 = 6

-1 -2 6 x3 -1

A X B

On utilise le fait que de remplacer une ligne du système d'équations par une combinaison linéaire entre elle etd'autres lignes ne modifie pas le résultat, pour éliminer le premier élément de la seconde ligne. En soustrayant lapremière ligne à la seconde on obtient :

1 1 -2 x1 2

0 2 -2 * x2 = 4

-1 -2 6 x3 -1

Puis on élimine les deux premiers éléments de la troisième ligne (on ajoute la première puis on ajoute 1/2 fois laseconde) :

1 1 -2 x1 2

0 2 -2 * x2 = 4

0 0 1 x3 1

On peut désormais résoudre le système (en commençant par le bas) : x3=1, donc (seconde ligne) 2x2-2.1=4, doncx2=3, donc (première ligne) x1+3-2.1=2 donc x1=1.

void gauss_triangulation_simpliste(type_mat A,type_mat B, int N)/* A de taille (N,N), B (N,1). On aurait pu gagner de la place en prenant B tableau unidimensionnel, ou même le rajouter en colonne N de A */ { int ce,l,c; composante coef; for(ce=0;ce<N-1;ce++) /* ce=col à effacer (dans les lignes SUIVANTES) */ for(l=ce+1;l<N;l++) /* pour chaque ligne au dessous */ { coef=A[l][ce]/A[ce][ce]; A[l][ce]=0; /* normalement pas besoin de le calculer */ for(c=ce+1;c<N;c++) A[l][c]-=coef*A[ce][c]; B[l][0]-=coef*B[ce][0]; } }

Si ces substitutions font apparaître une ligne de 0, soit le système admet une infinité de solutions (0=0, une ligne

Données et Algorithmique - LES TABLEAUX STATIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo03.htm (13 of 15) [21-11-2001 17:41:36]

Page 46: algo

est une combinaison linéaire des autres), soit aucune (0=N). Mais cette méthode n'est pas directement applicablepour des coefficients réels (ou du moins flottants). En effet, si les substitutions précédentes ont amené uncoefficient nul, on obtient une division par zéro. S'il est proche de 0, l'utilisation de ce coefficient pour en annulerd'autres nécessitera un multiplicateur très grand, ce qui entraînera une multiplication importante de l'erreurinhérente à l'utilisation de réels et donc un résultat faux (en fait on se trouvera en présence de coefficients d'ordrede grandeur très différent, et donc les petits deviendront négligeables devant l'erreur sur les très grands). Lasolution est de ne pas traiter les lignes dans l'ordre mais pour une colonne donnée, choisir pour celle qui aura sonpremier terme non nul celle dont ce terme est le plus grand (on l'appelle le pivot). Il suffit alors d'échanger laligne que l'on veut traiter avec la ligne contenant le pivot (échanger des lignes d'un système d'équations nemodifie pas la solution) (gauss):

void gauss_triangulation(type_mat A,type_mat B, int N) { int ce,l,c,lpivot; composante coef; for(ce=0;ce<N-1;ce++) /* ce=colonne à effacer */ {/*Recherche du pivot le + grand possible (dans les lignes qui restent)*/ lpivot=ce; for(l=ce+1;l<N;l++)if(fabs(A[l][ce])>fabs(A[lpivot][ce]))lpivot=l;/*Echange de la ligne du pivot et de la ligne ce (ne pas oublier B)*/ for(c=ce;c<N;c++) /*tous les termes devant ce sont nuls*/ {coef=A[ce][c];A[ce][c]=A[lpivot][c];A[lpivot][c]=coef;} coef=B[ce][0];B[ce][0]=B[lpivot][0];B[lpivot][0]=coef;/*Suite de l'algorithme, comme le cas simpliste */ for(l=ce+1;l<N;l++) /* pour chaque ligne au dessous */ { coef=A[l][ce]/A[ce][ce]; A[l][ce]=0; for(c=ce+1;c<N;c++) A[l][c]-=coef*A[ce][c]; B[l][0]-=coef*B[ce][0]; } } }

Une fois la matrice A triangulée, il ne reste plus qu'à déterminer la matrice colonne solution X:

void gauss_resolution(type_mat A,type_mat B,type_mat X,int N) { int l,c; composante tampon; for(l=N-1;l>=0;l--) { tampon=B[l][0]; for(c=l+1;c<N;c++)tampon-=A[l][c]*X[c][0]; X[l][0]=tampon/A[l][l]; } }

Données et Algorithmique - LES TABLEAUX STATIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo03.htm (14 of 15) [21-11-2001 17:41:36]

Page 47: algo

Remarque : on pourrait retourner le résultat dans B (si l'utilisateur désire le garder, il lui suffirait de le copieravant). Ceci économise le tableau X et le tampon.

D'autres algorithmes existent, mais ils ne sont plus efficaces que Gauss que pour de très grosses matrices. Maissouvent les grosses matrices possèdent des propriétés particulières nécessitant d'utiliser d'autres structures dedonnées que les tableaux à 2 dimensions (en cas de matrices triangulaires, symétriques, bandes, en "ligne deciel", creuses..., voir paragraphe 11.3.2), pour lesquelles Gauss n'est pas la meilleure solution, car la triangulationsupprime ces propriétés.

conclusionsLes tableaux unidimensionnels statiques sont d'une utilisation simple. Ils permettent un accès direct (donc quasiimmédiat) à une donnée dont on connaît la position. Les seules manipulations de base rapides sont l'insertion et lasuppression en fin du tableau. La dimension du tableau doit être connue (ou du moins maximisée) dès la phased'écriture du programme, ces tableaux sont donc intéressants dans le cas de dimensions petites ou presqueconstantes.

Données et Algorithmique - LES TABLEAUX STATIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo03.htm (15 of 15) [21-11-2001 17:41:36]

Page 48: algo

LES TABLEAUX DYNAMIQUEStableaux unidimensionnels en C●

la méthode du super-tableau●

les tableaux multidimensionnels

matrices pleines (matrices rectangulaires dynamiques : mrd)❍

tableaux de tableaux dynamiques❍

conclusions●

tableaux unidimensionnels en CLes tableaux statiques nécessitent de maximiser lors de l'écriture du programme la dimension destableaux. En cas de tableaux nombreux, il serait plus utile de ne réserver, pour chaque exécution, que lataille nécessaire à l'application en cours. En C, cette transformation est triviale grâce à la fonction mallocet à l'équivalence d'écriture entre les tableaux unidimensionnel et les pointeurs. Il suffira donc, pourutiliser les fonctions décrites pour les tableaux unidimensionnels statiques, de ne remplacer que ladéclaration des tableaux :

#define composante floattypedef composante *type_tus; /* ou typedef composante type_tus[] */

reste identique, mais la déclaration composante tab[dim] sera remplacée par :

tab=(type_tus)malloc(taille*sizeof(composante));

à partir du moment où l'on a besoin du tableau, puis free(tab); quand il redevient inutile. Leproblème des tableaux dynamiques en C est que l'on doit connaître la dimension d'un tableau avant sapremière utilisation, ce qui empêchera par exemple une introduction de données du type "entrez vosdonnées, tapez FIN pour terminer" mais nécessitera de demander en premier le nombre de données.L'autre problème provient du fait de la gestion de la mémoire inaccessible au programmeur : descréations et suppressions successives de tableaux vont créer une mémoire morcelée, et doncl'impossibilité de réserver un gros tableau, alors que la mémoire était disponible mais non continue. Onest alors obligé de passer par la méthode du super-tableau pour pouvoir effectuer des retassages demémoire.

Données et Algorithmique - LES TABLEAUX DYNAMIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo04.htm (1 of 4) [21-11-2001 17:41:45]

Page 49: algo

la méthode du super-tableauDans les langages ne disposant pas de fonctions spécifiques à l'allocation dynamique de mémoire, oncrée un grand tableau, appelé super-tableau, dimensionné au maximum de mémoire disponible. On créeensuite les fonctions utilitaires nécessaires : réservation de mémoire (bloc) d'une taille donnée enargument (la fonction rend l'indice dans le super-tableau du début du sous-tableau alloué), libération d'unbloc préalablement alloué,... L'utilisation d'un bloc alloué est alors très simple : on remplace l'écriturebloc[i] par super_tableau[indice_debut_bloc+i]. Les parties du super-tableau utiliséesn'ont pas absolument besoin d'une gestion poussée, mais on préfère en général prévoir un tableau annexecontenant les adresses et tailles des blocs actuellement réservés. Par contre il faut gérer les parties libres.Une solution est d'utiliser une pile (voir plus loin), mais la libération d'un bloc autre que le dernier soitnécessite un décalage des blocs suivants (attention, les indices de début de blocs sont modifiés), soit unmarquage spécifique de cette zone (la place ne sera effectivement libérée que lorsque tous les blocssuivants seront libérés). Cette méthode est utilisable dans beaucoup de cas, il suffit de réserver enpremier les blocs qui seront utilisés tout au long du programme, les blocs à durée de vie plus faible par lasuite. L'autre solution consiste à gérer les blocs libres sous forme d'une liste chaînée (voir plus loin),chaque bloc libéré contenant l'indication de sa taille et l'adresse du bloc libre suivant (la place utilisée parces informations est "masquée" puisque n'utilisant que des zones libres). L'allocation d'un bloc consistealors en la recherche du premier bloc libre de taille suffisante. Un retassage (et donc modification desindices de débuts de blocs) n'est nécessaire qu'en cas de mémoire trop morcelée.

Cette méthode du super-tableau permet de manière très simple d'accéder à toutes les possibilités despointeurs, dans tout langage. C'est la raison pour laquelle des programmes très efficaces continuent à êtredéveloppés dans ces langages (pratiquement tous les gros programmes scientifiques (C.A.O., élémentsfinis,...) de plusieurs centaines de milliers de lignes sont écrits en FORTRAN, et utilisent cette méthode).De plus la gestion par le programmeur de l'allocation de mémoire peut permettre d'être plus efficace quela gestion par le compilateur, puisque pouvant être spécifique au problème traité.

les tableaux multidimensionnelsIl n'y a pas en C d'équivalence d'écriture permettant une utilisation directe de l'allocation dynamique pourles tableaux multidimensionnels. On utilise donc la même méthode pour l'allocation dynamique en C (lamémoire est en fait un tableau unidimensionnel d'octets) qu'avec un super-tableau. Nous n'allons traiterque les tableaux à deux dimensions, l'extension à N dimensions ne posant aucun problème.

matrices pleines (matrices rectangulaires dynamiques : mrd)

Pour allouer dynamiquement une matrice de taille (nbl,nbc), on réserve un tableau unidimensionnel detaille nbl*nbc :

typedef composante * mat_dyn;mat_dyn alloc_mrd(int nbl;int nbc) {return((mat_dyn)malloc(nbl*nbc*sizeof(composante)));}

On accède à l'élément en ligne l et colonne c par m[l*nbc+c] (pour l et c commençant à 0, comme en C).

Données et Algorithmique - LES TABLEAUX DYNAMIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo04.htm (2 of 4) [21-11-2001 17:41:45]

Page 50: algo

On peut prévoir une fonction (ou même une macro, plus rapide) pour effectuer ce calcul :

#define adr_mrd(l,c,nbc) ((l)*(nbc)+(c))

Les algorithmes pour les matrices statiques doivent être réécrits, en remplaçant chaque mat[l][c] parmat[adr_mrd(l,c,nbc)]. Souvent, on choisira un nom plus court pour adr_mrd. Dans les cas simplesuniquement, on peut choisir nbc comme variable globale pour éviter sa transmission en argument (parexemple si l'on utilise des matrices carrées toutes de même taille), mais ce n'est pas conseillé (dans le casd'une macro, ce ne sont pas de vrais passages d'arguments et donc ne prend pas de tempssupplémentaire).

Exercice (gauss_mrd) : écrire une version de la méthode de Gauss pour des matrices dynamiques. Lasolution donnée en annexe 2 (du document papier) est un exemple de matrices dynamiques.

tableaux de tableaux dynamiques

Dans le cas de matrices non pleines, la gestion sera plus complexe mais le résultat très efficace. On gèreen fait un ensemble de lignes de longueur différente (donc des tableaux dynamiques). Dans quelques cas,la longueur et la position de chaque ligne se trouve par calcul : matrices triangulées, matrices bandes(réorganisées pour que tous les éléments non nuls soient au maximum à la distance B (largeur de bande)de la diagonale),... Un utilise alors la même méthode que pour les matrices pleines, en changeantsimplement le calcul pour accéder à une composante (adr_mrd). Dans tous les autres cas, chaque ligneest allouée dynamiquement, l'adresse et la longueur de chaque ligne étant stockée dans un tableaustatique ou dynamique, voire liste chaînée... La longueur peut être omise si la ligne est terminée par unsigne particulier (chaînes de caractères en particulier). Les manipulations deviennent alors plus efficaces: les manipulations de composantes (dans les lignes) restent des manipulations de type tableaux, doncefficaces tant que les lignes ne sont pas de taille exagérée, alors que les manipulations de lignes (plusvolumineuses) se font par manipulation d'adresses (par exemple pour échanger deux lignes, il suffitd'échanger les deux adresses de lignes, les lignes elles-mêmes n'étant physiquement pas déplacées). Cetype de données est certainement le plus efficace pour du traitement de textes. Mais il permet aussi detraiter les matrices en "ligne de ciel:" dans le cas (fréquent en mécanique) de matrices symétriquescontenant beaucoup de 0, on peut avoir du mal à réorganiser la matrice efficacement pour qu'elle soitsous forme de bande, par contre il est plus facile de la réorganiser pour qu'un maximum de lignes soientregroupées près de la diagonale, quelques lignes restant à grande largeur. On stocke alors uniquement,pour chaque ligne, les éléments de la diagonale au dernier non nul. Ce type de stockage est égalementappelé quelquefois "à largeur de bande variable".

Ces tableaux de tableaux dynamiques permettent toujours un accès presque direct à un élément l,c :tab[adresse_ligne[l]][c]. Mais ils gardent les problèmes des tableaux dynamiques, en particulier de ne pasêtre totalement dynamiques puisqu'une fois une ligne créée, on ne peut pas directement l'agrandir (en faitil suffit de réserver une nouvelle ligne plus grande, y recopier la précédente, changer l'adresse de la lignedans le tableau d'adresses de lignes puis supprimer l'ancienne ligne). Souvent dans ce cas on préfèredirectement créer un ligne un peu plus longue que nécessaire, pour ne pas répéter l'opération tropsouvent.

Exercice (inse_ttd) : écrire un programme pour trier des lignes de texte, utilisant les tableaux detableaux dynamiques. On choisira un tri par insertion, puisque les échanges de lignes ne sont que des

Données et Algorithmique - LES TABLEAUX DYNAMIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo04.htm (3 of 4) [21-11-2001 17:41:45]

Page 51: algo

échanges d'adresses, le texte en lui-même ne sera jamais déplacé.

conclusionsLes tableaux dynamiques ne sont pas totalement dynamiques, c'est à dire que leur taille, bien que définieen cours d'exécution du programme, ne peut pas facilement être modifiée (c'est néanmoins presquetoujours possible mais relativement coûteux en temps et mémoire). Mais ils gardent la principale qualitédes tableaux statiques : l'accès immédiat à une composante dont on connaît la position. Ils en gardentégalement la faible efficacité en cas d'insertions et suppressions. Les tableaux dynamiques sontnéanmoins la solution minimisant la place occupée en mémoire pour de gros ensembles de données :Seule la place nécessaire est réservée (excepté une mémoire pour l'adresse du début du tableau), aucunemémoire n'est utilisée pour indiquer où se trouve la composante suivante, puisqu'elle est placéedirectement après la précédente (contrairement aux listes par exemple).

Données et Algorithmique - LES TABLEAUX DYNAMIQUES

http://www-ipst.u-strasbg.fr/pat/program/algo04.htm (4 of 4) [21-11-2001 17:41:45]

Page 52: algo

LES LISTESfonctions de base et manipulations (base_lst)●

les tris

le tri bulle❍

le tri par insertion❍

le tri par sélection❍

le tri par création❍

les autres tris❍

problèmes mathématiques●

conclusions●

fonctions de base et manipulations (base_lst)Les listes sont un regroupement ordonné de données effectué de manière à ce que chaque composante sache où setrouve la suivante. En C, une composante sera une structure contenant la valeur mémorisée, mais également unpointeur sur la composante suivante. Sur fichier ou dans les langages ne possédant pas de pointeurs, on utiliserala méthode du super-tableau, le pointeur étant remplacé par l'indice, dans le super-tableau, de la composantesuivante. Une liste est accessible par l'adresse de sa première composante. On supposera dans la suite que lesvaleurs à mémoriser sont de type flottant, mais évidement tout autre type de données est possible (mêmetableaux, structures, listes...). La déclaration en C sera donc :

typedef float type_val;typedef struct scomp {type_val val; struct scomp *suiv;} type_comp;typedef type_comp *adr_comp;

Nous représenterons les composantes des listes (de type type_comp) ainsi :

Supposons disposer de la liste ci-dessous en mémoire (nous verrons plus loin comment la créer en mémoire). Lavariable prem, de type adr_comp (donc pointeur sur une composante) contient l'adresse de la premièrecomposante. Le champ suiv de la dernière composante contient la valeur NULL, donc ne pointe sur rien.

Données et Algorithmique - LES LISTES

http://www-ipst.u-strasbg.fr/pat/program/algo05.htm (1 of 10) [21-11-2001 17:42:10]

Page 53: algo

Pour simplifier les algorithmes, on peut mettre d'office une composante particulière en début et fin de liste(appelée sentinelle). Ceci évite de devoir traiter de manière particulière le premier et dernier élément de la liste,puisque chaque composante utile possède toujours un précédent et un suivant. Cette méthode prend un peu plusde mémoire (négligeable en % pour de longues listes) et évite des tests systématiques dans le boucles, alors qu'ilsne servent que pour les extrémités (d'où gain de temps appréciable, toujours en cas de longues listes). Une autreméthode pour repérer le dernier élément est de le faire pointer sur lui-même. Nous utiliserons dans la suite deslistes sans sentinelle, le dernier élément pointant sur NULL.

L'appel de : affiche_lst(prem) affichera à l'écran le contenu de la liste :

void affiche_lst(adr_comp l) { while(l!=NULL) { printf("%6.1f ",l->val); l=l->suiv; } printf("\n"); }

l pointe sur la première composante. On affiche la valeur pointée par l puis on fait pointer l sur son suivant. Onrépète le processus jusqu'en fin de liste (lorsque l'on pointe sur NULL). La variable l doit être locale (donc passéepar valeur) pour ne pas modifier le contenu de prem, et donc perdre l'adresse du début de la liste, ce quiempêcherait tout accès ultérieur à la liste.

Comme pour les chaînes de caractères, plutôt que de gérer un variable entière indiquant toujours la longueuractuelle de la liste, c'est la spécificité du dernier élément (ici, le champ suiv contient NULL) qui permet depréciser que l'on est en fin de liste. Pour connaître la longueur d'une liste, on utilisera :

int longueur_lst(adr_comp l) { int n=0; while(l!=NULL) { l=l->suiv; n++; } return(n); }

Les listes ont l'avantage d'être réellement dynamiques, c'est à dire que l'on peut à loisir les rallonger ou lesraccourcir, avec pour seule limite la mémoire disponible (ou la taille du super-tableau). Par exemple pour insérerune nouvelle composante en début de liste, on utilisera :

Données et Algorithmique - LES LISTES

http://www-ipst.u-strasbg.fr/pat/program/algo05.htm (2 of 10) [21-11-2001 17:42:10]

Page 54: algo

void insert_premier(adr_comp *prem,type_val val) { adr_comp nouv; nouv=(adr_comp)malloc(sizeof(type_comp)); nouv->val=val; nouv->suiv=*prem; *prem=nouv; }

En insérant la valeur 5 à notre exemple précédent, on obtient la liste :

La variable prem a dû être passée par adresse, pour que l'on récupère bien l'adresse de la nouvelle premièrecomposante (appel : insert_premier(&prem,5)). En fait le schéma ci-dessus n'est qu'une représentationabstraite de la liste (chaque composante pointe sur la suivante), alors que les composantes sont physiquementplacées différemment en mémoire. Dans le meilleur des cas, la nouvelle composante créée a été placée justederrière celles déjà existantes (premier emplacement libre). Un schéma plus proche de la réalité serait donc :

Ces deux schémas sont équivalents (les liens partent des mêmes cases, et pointent sur les mêmes cases), seule ladisposition des cases diffère. En fait ceci nous montre bien que la disposition réelle en mémoire ne nous intéressepas (jamais la valeur effective de l'adresse contenue dans un pointeur ne nous intéressera). Dans nos schémas,nous choisirons donc une disposition des composantes correspondant plus au problème traité qu'à la dispositionréelle en mémoire (par exemple dans le schéma suivant, on utilise une représentation bidimensionnelle, alors quela mémoire n'est qu'unidimensionnelle).

Le second avantage des listes est que l'insertion d'une composante au milieu d'une liste ne nécessite que lamodification des liens avec l'élément précédent et le suivant, le temps nécessaire sera donc indépendant de lalongueur de la liste. Supposons disposer d'une variable X de type adr_comp, pointant sur la composante devaleur 10. L'appel de insert_après(X,15) donnera le résultat suivant :

Données et Algorithmique - LES LISTES

http://www-ipst.u-strasbg.fr/pat/program/algo05.htm (3 of 10) [21-11-2001 17:42:10]

Page 55: algo

void insert_après(adr_comp prec,type_val val) { adr_comp nouv; nouv=(adr_comp)malloc(sizeof(type_comp)); nouv->val=val; nouv->suiv=prec->suiv; prec->suiv=nouv; }

Cette fonction permet l'insertion en tout endroit de la liste, sauf en première position (qui n'a pas de précédentdans notre cas puisque sans sentinelle), il faut traiter spécifiquement le premier de la liste (voir plus haut).L'insertion nécessite la connaissance de l'adresse du précédent et du suivant. Les composantes ne comportant quedes liens vers l'élément suivant, il faut nécessairement donner à la fonction insert_après l'adresse du précédent,alors que d'habitude on préfère donner l'élément devant lequel on veut faire l'insertion (tableaux par exemple).Ceci nous montre le principal problème des listes : l'accès est séquentiel. On devra, pour chercher la composanteprécédente, parcourir toute la liste depuis son début (on donne l'adresse du début de la liste et de l'élément donton cherche le précédent):

adr_comp rech_prec(adr_comp prem, adr_comp suiv)/* rend l'adresse, NULL si non trouvé */ { while(prem->suiv!=suiv && prem!=NULL) prem=prem->suiv; return(prem); }

Une autre solution, si l'on a fréquemment besoin de parcourir la liste vers l'avant et vers l'arrière, est de stockerdans chaque composante l'adresse du suivant et celle du précédent. Ceci nécessite plus de place en mémoire etralentit un peu les manipulations de base (il y a plus de liens à mettre à jour). Mais même dans ce cas, l'accèsreste séquentiel. Ceci empêche d'utiliser un certain nombre d'algorithmes utilisant l'accès direct (la dichotomiepar exemple). Pour trouver l'adresse du Nième élément d'une liste il faudra utiliser (on suppose numéroter 0 lepremier) :

adr_comp rech_ind(adr_comp l, int i)/* rend l'adresse du (i+1)ième, NULL si liste trop courte */ { int j; for(j=0;j<i && l!=NULL;j++) l=l->suiv; return(l); }

La recherche d'un élément, même si la liste est triée, se fera donc toujours séquentiellement :

adr_comp rech_val(adr_comp l, type_val v)/* rend l'adresse, NULL si non trouvé */ { while(l!=NULL && l->val!=v) l=l->suiv; return(l); }

Pour créer une liste, la solution la plus simple consiste à boucler sur un appel de la fonction insert_premier,

Données et Algorithmique - LES LISTES

http://www-ipst.u-strasbg.fr/pat/program/algo05.htm (4 of 10) [21-11-2001 17:42:10]

Page 56: algo

mais les éléments seront stockés dans l'ordre inverse de leur introduction (le dernier saisi sera placé en premier).Pour une création de liste dans l'ordre, on fera :

adr_comp saisie_lst(void) { adr_comp prem=NULL,prec,actu; /* premier, précédent, actuel*/ type_val v; int err; do { printf("entrez votre prochaine valeur, un caractère pour finir :"); err=scanf("%f",&v); if(err<=0)break; /*scanf rend le nombre de variables lues sans erreur*/ actu=(adr_comp)malloc(sizeof(type_comp)); actu->val=v; if(prem==NULL)prem=actu; else prec->suiv=actu; prec=actu; } while(1); actu->suiv=NULL; return(prem); }

Cette fonction crée la liste en mémoire, effectue la saisie et retourne l'adresse du début de la liste.

Il nous reste à traiter les suppressions dans une liste. Il faut ici encore préciser l'élément précédent celui àsupprimer, et traiter de manière particulière le début de la liste :

void suppr_suivant(adr_comp prec) { adr_comp a_virer; if(prec==NULL || prec->suiv==NULL) {puts("rien à supprimer");return;} a_virer=prec->suiv; prec->suiv=a_virer->suiv; free(a_virer); }

void suppr_premier(adr_comp *prem) { adr_comp a_virer; if(*prem==NULL) {puts("rien à supprimer");return;} a_virer=*prem; *prem=(*prem)->suiv; free(a_virer); }

La suppression complète d'une liste permet de récupérer la place en mémoire. Cette opération n'est pas nécessaireen fin de programme, le fait de quitter un programme remet la mémoire dans son état initial et libère doncautomatiquement toutes les mémoires allouées dynamiquement :

Données et Algorithmique - LES LISTES

http://www-ipst.u-strasbg.fr/pat/program/algo05.htm (5 of 10) [21-11-2001 17:42:10]

Page 57: algo

void suppr_tout(adr_comp prem)/* attention : ne met pas NULL dans prem qui pointe donc toujours sur laliste, qui n'est plus allouée mais dont le contenu n'a peut-être pas changé*/

{ adr_comp deuxieme; while(prem!=NULL) { deuxieme=prem->suiv; free(prem); prem=deuxieme; } }

Il n'était à priori pas obligatoire d'utiliser la variable deuxième car la libération par free n'efface pas lesmémoires, le suivant est donc encore disponible après free et avant tout nouveau malloc. Néanmoins cetteécriture est plus sure, ne gérant pas la mémoire nous même (sauf si méthode du super-tableau), en particulier encas de multitâche, d'interruption matérielle...

On trouvera un exemple utilisant ces fonctions dans test_lst.c (disquette d'accompagnement)

les trisSeuls les tris n'utilisant pas l'accès direct pourront être efficaces pour les listes. Au lieu de déplacer les valeursdans la liste, on changera uniquement les liens. Dans la plupart des configurations, le tri par insertion sera le plusefficace.

le tri bulle

Le tri bulle est donc assez efficace (n'ayant pas de lien sur la composante précédente, on mémorisera toujoursl'adresse du précédent dans une variable auxiliaire). Mais il reste peu efficace lorsque des éléments sont loin deleur position finale, puisque chaque passage ne peut déplacer un élément que d'une position (de l'ordre de N2/2échanges, autant de boucles internes), on le réservera donc aux listes presque triées. Les autres tris, comme le tripar insertion déplaceront chaque élément directement en bonne position, mais le temps nécessaire à la recherchepeut être assez long, alors qu'ici la position destination est directement connue (mais pas nécessairement juste)(bull_lst) :

void tri_bulle_lst(adr_comp *prem)/* le premier ne sera peut-être plus le même donc passage par adresse */ { int ok; adr_comp prec,actu,suiv; do { ok=1; /* vrai */ prec=NULL; actu=*prem; suiv=actu->suiv;

Données et Algorithmique - LES LISTES

http://www-ipst.u-strasbg.fr/pat/program/algo05.htm (6 of 10) [21-11-2001 17:42:10]

Page 58: algo

while(suiv!=NULL) { if(actu->val > suiv->val) { ok=0; if(prec!=NULL) prec->suiv=suiv; else *prem=suiv; actu->suiv=suiv->suiv; suiv->suiv=actu; } prec=actu; actu=suiv; suiv=actu->suiv; } } while(!ok); }

En utilisant prec->suiv et prec->suiv->suiv, on pouvait éviter d'utiliser les variables actu et suiv.Le temps d'accès aux variables aurait été un peu plus long mais on supprimait deux des trois affectations situéesen fin de boucle.

le tri par insertion

Le tri par insertion sera bien plus intéressant, dans la majorité des cas : il nécessite une boucle principale(séquentielle), dans laquelle on appelle une seule recherche pour placer l'élément, les déplacements se faisant trèsrapidement et sans s'occuper du reste de la liste (inse_lst) :

void tri_insertion_lst(adr_comp *prem) { /*position testée, précédent,dernier plus petit*/ adr_comp pt,prec,dpp;

for(prec=*prem,pt=(*prem)->suiv;pt!=NULL;prec=pt,pt=pt->suiv) if(prec->val>pt->val) /*inutile de chercher si en bonneposition */ { prec->suiv=pt->suiv; if((*prem)->val > pt->val) /*cas particulier du premier*/ { pt->suiv=*prem; *prem=pt; } else { dpp=*prem; while(dpp->suiv->val <= pt->val)dpp=dpp->suiv; /* on est sur d'en trouver un, vu les tests effectués plus haut */ pt->suiv=dpp->suiv; dpp->suiv=pt; }

Données et Algorithmique - LES LISTES

http://www-ipst.u-strasbg.fr/pat/program/algo05.htm (7 of 10) [21-11-2001 17:42:10]

Page 59: algo

} }

Ici également, on aurait pu tenter d'éviter l'utilisation des deux variables prec et pt puisque pt est le suivant deprec, mais les échanges auraient alors nécessité une variable tampon. Cette version du tri est stable (le nouveauest inséré derrière les valeurs égales), mais ceci ralentit un peu la recherche de la position définitive d'une valeuren cas de nombreuses valeurs égales (si la stabilité n'est pas nécessaire, il suffit d'arrêter la recherche au premierélément supérieur ou égal). Dans tous les cas, on fera au maximum N échanges (aucun en bonne position), enmoyenne N/2 pour les fichiers mélangés. Dans la cas d'un fichier mélangé, le nombre de boucles internes est deN(N-1)/2 en moyenne. Dans le cas d'un fichier presque trié, dans le cas de quelques éléments (en nombre P) pasdu tout à leur place, ce tri est très efficace : P échanges, (P+2)*N/2 boucles internes, donc on devient linéaire enN. Par contre dans le cas de nombreux éléments pas tout à fait à leur place (à la distance D), il l'est moins que letri bulle, la recherche de la position exacte se faisant à partir du début de la liste (proche de N2 : (N-D)(N-1)boucles internes). Dans ce cas, si l'on peut également disposer d'un chaînage arrière, on fera la recherche à partirde la position actuelle, ce qui rendra le tri très efficace également dans ce cas : D(N-1) boucles internes donclinéaire en N. Sinon, on peut mémoriser la position du Dième précédent, le comparer à la valeur à insérer et doncdans la majorité des cas (si D bien choisi) rechercher derrière lui, dans les quelques cas où il faut l'insérer devantlui, on effectue une recherche depuis le début.

le tri par sélection

Le tri par sélection prendra environ N2/2 boucles internes, et ceci quel que soit l'ordre initial du fichier. Lenombre maximal d'échanges sera de N, N/2 en moyenne pour un fichier mélangé, P pour uniquement P élémentsmal placés (sele_lst) :

void tri_selection_lst(adr_comp *prem) { type_comp faux_debut; adr_comp pdpd,pdpp,i; faux_debut.suiv=*prem; for(pdpd=&faux_debut;pdpd->suiv!=NULL;pdpd=pdpd->suiv) { /*recherche du plus petit (du moins son précédent)*/ pdpp=pdpd; /*le plus petit est pour l'instant l'actuel, on va tester lessuivants*/ for(i=pdpd->suiv;i->suiv!=NULL;i=i->suiv) if(i->suiv->val < pdpp->suiv->val)pdpp=i; /* échange (si beaucoup d'élémentsdéjà en place, rajouter un test pour ne pas échangerinutilement) */ i=pdpp->suiv; pdpp->suiv=i->suiv; i->suiv=pdpd->suiv; pdpd->suiv=i; } *prem=faux_debut.suiv; /* retourner le bon premier */ }

pdpd représente le Précédent De la Place Définitive (boucle principale : de place définitive valant *prem jusqu'àfin de la liste), pdpp représente le Précédent Du Plus Petit (de la suite de la liste, pas encore traitée). On a dans

Données et Algorithmique - LES LISTES

http://www-ipst.u-strasbg.fr/pat/program/algo05.htm (8 of 10) [21-11-2001 17:42:10]

Page 60: algo

cette implantation évité les variables pour la place définitive et le plus petit, ceux-ci étant les suivants desvariables précisées ci-dessus. Ceci nuit à la clarté mais améliore l'efficacité. On pouvait améliorer la clarté(définir les "variables" pd et pp) sans nuire à l'efficacité (ne pas devoir les remplacer par leur suivant en fin deboucle) par des #define :

#define pd pdpd->suiv#define pp pdpp->suiv

Pour limiter la portée de ces substitutions à cette fonction, il suffit de déclarer juste derrière la fin de la fonction :

#undef pd#undef pp

De plus, afin d'éviter de tester partout le cas particulier du premier de la liste, on a choisi d'ajouter un élément endébut de liste (faux_début), pointant sur le premier de la liste. Dans ce cas, tous les éléments y compris le premieront un précédent. Le gain est donc appréciable (en temps car moins de tests et en taille du code source), pour uncoût limité à une variable locale supplémentaire.

le tri par création

Ce tri nécessite de recréer tous les liens. En fait on utilisera un algorithme par insertion (ou par sélection) un peumodifié, puisque ces deux tris créent progressivement la liste triée. en cas de valeurs de grande taille, on préférerane créer qu'une nouvelle liste de liens, pour éviter de doubler la place mémoire utilisée par les valeurs (lacomposante de base contiendra donc deux pointeurs : l'adresse de la valeur et l'adresse de la composantesuivante).

les autres tris

Le tri shell, quand à lui, n'améliore pas le tri par sélection puisqu'il traite les composantes séparées d'une distanceP.

Pour le tri rapide, le nombre de boucles internes est de l'ordre de Nlog(N) (N sur toute la liste, puis deux fois N/2sur les deux moitiés.... donc N*P, P étant la profondeur de récursivité, qui est de log(N)). Par contre les échangessont plus nombreux que les autres tris (en moyenne une boucle interne sur deux pour un fichier mélangé). Pourtransposer l'implantation détaillée pour les tableaux, il faut disposer d'une liste à chaînage avant et arrière, mais ilest facile de n'utiliser que le chaînage avant : l'algorithme devient donc :

choix d'un pivot (le premier par exemple, puisqu'on y accède directement),●

scruter la liste pour créer deux sous-listes (celle des valeurs plus petites et celle des plus grandes),●

appel récursif sur les deux sous-listes.●

mise à jour des liens (fin de la première liste, pivot, début de la deuxième)●

Cette gestion des liens ralentit beaucoup l'algorithme, son implantation doit donc être soigneusement optimiséepour espérer un gain, du moins pour les très longues listes.

problèmes mathématiquesOn utilisera les listes pour les cas nécessitant de nombreuses manipulations (en particulier dans les problèmesgraphiques). On les utilise également pour les polynômes ou matrices creuses (c'est à dire avec de nombreuxcoefficients nuls, on ne stocke que les coefficients non nuls (ainsi que leur indice ou le nombre de 0 qui lesséparent du suivant). Les algorithmes restent similaires à ceux s'appliquant aux tableaux, mais sont souvent moins

Données et Algorithmique - LES LISTES

http://www-ipst.u-strasbg.fr/pat/program/algo05.htm (9 of 10) [21-11-2001 17:42:10]

Page 61: algo

efficaces (une triangulation de Gauss rend non nuls une grande partie des coefficients nuls, nécessitant denombreuses insertions de nouveaux éléments).

conclusionsLes listes sont parfaitement dynamiques. Toutes les modifications peuvent se faire en cours d'utilisation. Parcontre l'accès est séquentiel, ce qui peut être très pénalisant dans certains cas. Il est néanmoins possible d'utiliserun double chaînage avant et arrière, mais au détriment de la place mémoire. L'encombrement des listes enmémoire est important : chaque élément doit contenir l'adresse du suivant (alors que pour les tableaux elle étaitfacile à calculer donc non stockée). Pour de très grandes listes, on peut remédier à ce problème en utilisant deslistes de tableaux, mais l'utilisation devient complexe. Un autre avantage des listes est que l'on utilise toujours unadressage indirect, et donc que les manipulations dans les listes ne font que des modifications du chaînage, sansréellement déplacer les valeurs stockées, ce qui est capital en cas de champs de grande taille.

Données et Algorithmique - LES LISTES

http://www-ipst.u-strasbg.fr/pat/program/algo05.htm (10 of 10) [21-11-2001 17:42:10]

Page 62: algo

LES PILES ET FILESdéfinition●

fonctions de base●

utilisations●

définitionCe sont des structures de données ordonnées, mais qui ne permettent l'accès qu'à une seule donnée. On utilisesouvent le nom générique de pile pour les piles et les files, un seul nom existant en anglais (stack). Les piles(stack LIFO : Last In First Out) correspondent à une pile d'assiettes : on prend toujours l'élément supérieur, ledernier empilé. Les files (on dit aussi queues) (stack FIFO: First In First Out) correspondent aux files d'attente :on prend toujours le premier élément, donc le plus ancien (on ne tolère pas ici les resquilleurs). Les piles et filessont très souvent utiles : elles servent à mémoriser des choses en attente de traitement. Elles permettront uneclarification des algorithmes quand effectivement on n'a pas besoin d'accéder directement à tous les éléments.Elles sont souvent associées à des algorithmes récursifs. Il n'y a pas de structures spécifiques prévues dans leslangages (sauf FORTH), il faut donc les créer de toutes pièces. Pour les piles, on utilisera un tableauunidimensionnel (statique ou dynamique) en cas de piles de hauteur maximale prévisible (la hauteur de la pileest mémorisée par une variable entière), ou une liste en cas de longueur très variable (ne pas oublier que dans cecas on a un surcoût en mémoire d'autant de liens (pointeurs) que d'éléments empilés). Pour les files, l'utilisationd'un tableau nécessite deux variables : la position du premier et celle du dernier. La suppression du premierélément ne se fait pas par décalage des suivants mais en incrémentant la variable indiquant le premier. Lagestion est alors un peu plus complexe que pour les piles, puisque le suivant de la fin du tableau est le début dutableau (en fait, l'indice du suivant est l'indice plus 1, modulo la taille du tableau. La fonction modulo est en faittrès rapide pour les nombres correspondants à une puissance de 2, à condition de l'implanter à l'aide d'unmasquage. L'utilisation d'une liste pour une file par contre est aussi simple que pour une pile.

fonctions de baseLes fonctions de base pour les piles sont l'empilage et le dépilage, pour les files l'enfilage et le défilage. Dansles deux cas on prévoira également un fonction d'initialisation, et une fonction indiquant si la pile est vide.Seules ces fonctions de base dépendent de la méthode réelle de mise en oeuvre (tableau, liste,...). Tous lesalgorithmes n'utiliseront que ces fonctions. C'est le grand avantage des piles et files, puisque l'on va pouvoirmodifier facilement le type d'implantation en mémoire sans réécrire les programme. Ceci permet de testerd'abord la faisabilité du programme sur des petites quantités de données puis seulement on l'optimise pourl'utilisation réelle. Pour une implantation par tableaux, on écrira par exemple, pour une pile de flottants(base_p_t) :

#define dim_pile 100#define composante float

Données et Algorithmique - LES PILES ET FILES

http://www-ipst.u-strasbg.fr/pat/program/algo06.htm (1 of 6) [21-11-2001 17:42:18]

Page 63: algo

/* static pour empêcher l'accès direct extérieur*/static composante pile[dim_pile]; static int sommet;

void init_pile(void){sommet=0;}

int pile_vide(void){return(sommet=0);}

int empiler(composante x)/* retourne 0 si pas d'erreur (donc il restait de la place dans la pile) */{ if(sommet<dim_pile) {pile[sommet++]=x;return(0);} else {puts("pile saturée");return(1);}}

composante depiler(void){ if (sommet>0) return(pile[--sommet]); else puts("pile vide");return(0);}

Si l'on désire un dimensionnement totalement dynamique de la pile, on utilisera une liste (base_p_l) :

#include <alloc.h>#include <stdio.h>#define composante floattypedef struct s_comp {composante val;struct s_comp *prec;}type_comp;

static type_comp *sommet=NULL;

int empiler(composante x)/* retourne 0 si pas d'erreur (donc il restait de la place dans la pile)*/{ type_comp *nouv; if((nouv=(type_comp*)malloc(sizeof(type_comp)))!=NULL) { nouv->val=x; nouv->prec=sommet; sommet=nouv; return(0);} else {puts("pile saturée");return(1);}}

Données et Algorithmique - LES PILES ET FILES

http://www-ipst.u-strasbg.fr/pat/program/algo06.htm (2 of 6) [21-11-2001 17:42:18]

Page 64: algo

composante depiler(void){ composante x; if (sommet!=NULL) { x=sommet->val; free(sommet); /*pour plus de sûreté, on peut passer par une variable*/ sommet=sommet->prec; return(x); } else puts("pile vide");return(0);}

void init_pile(void){while(sommet!=NULL)depiler();}

int pile_vide(void){return(sommet==NULL);}

Pour certaines applications, on pourra préférer ne pas libérer la mémoire au dépilage pour gagner du temps : audépilage, mais aussi à l'empilage, on ne prend du temps que s'il faut agrandir la pile. On peut également utiliserune pile de tableaux dynamiques, ce qui permet d'économiser de la place mémoire, sans être limité en taille.

Pour les files, l'implantation des fonctions de base est similaire, par exemple par tableaux (base_f_t) :

#define dim_file 100#define composante floatstatic composante file[dim_file]; static int bas,sommet,taille;#define suiv(i) ((i)<dim_file-1 ? ((i)+1) : 0)

void init_file(void){bas=sommet=taille=0;}

int file_vide(void){return(taille=0);}

int enfiler(composante x)/* retourne 0 si pas d'erreur (donc il restait de la place dans la pile)*/{ if(taille<dim_file) {file[sommet]=x;sommet=suiv(sommet);taille++;return(0);} else {puts("file saturée");return(1);}}

composante depiler(void)

Données et Algorithmique - LES PILES ET FILES

http://www-ipst.u-strasbg.fr/pat/program/algo06.htm (3 of 6) [21-11-2001 17:42:18]

Page 65: algo

{ composante x; if (taille>0) {x=file[bas];bas=suiv(bas);taille--;return(x);} else {puts("file vide");return(0);}}

Il faut prévoir un indice pour chaque extrémité de la file. Il en serait de même pour une implantation par listechaînée (un pointeur pour chaque extrémité).

utilisationsLes piles sont souvent nécessaires pour rendre itératif un algorithme récursif. Une application courante des pilesest pour les calculs arithmétiques: l'ordre dans la pile permet d'éviter l'usage des parenthèses. Il existe troispossibilités pour représenter une équation (du moins de manière unidimensionnelle, les arbres en sont unegénéralisation bidimensionnelle), suivant la position relative des opérateurs et de leurs opérandes. Il faut avanttout définir l'arité d'une opération : une opération unaire nécessite un opérateur (- unaire, cosinus, log,factorielle...), une opération deuxaire (dénomination P. Trau, pour différencier d'une opération binaire qui pourmoi traite des nombres en base 2) nécessite deux arguments (+, -, *, /, produit vectoriel,...), une opérationternaire nécessite trois opérandes (produit mixte,...). La notation préfixée (dite polonaise) consiste à placerl'opérateur, suivi de ses arguments. La notation postfixée (polonaise inverse) consiste à placer les opérandesdevant l'opérateur. La notation infixée (parenthèsée) consiste à entourer les opérateurs deuxaires par leursopérandes, pour les autres arités on place l'opérateur en premier, suivi de ses opérandes (entre parenthèses,séparés par des virgules pour les opérateurs ternaires). Les parenthèses sont nécessaires uniquement en notationinfixée, certaines règles permettent d'en réduire le nombre (priorité de la multiplication par rapport à l'addition,en cas d'opérations unaires représentées par un caractère spécial (-, !,...). Les notations préfixée et postfixée sontd'un emploi plus facile puisqu'on sait immédiatement combien d'opérandes il faut rechercher. Détaillons ici lasaisie et l'évaluation d'une expression postfixée (polonais) : on modifie le type de composantes de la pile (etdonc les fonctions de base) :

#define operande 1#define operateur 0

typedef struct {int type; union {float op_r;char op_c;}val; }composante;void saisie(void)/* marche pour toute notation puisque ne vérifie rien */ { composante x; char txt[100],*deb; char rep; init_pile(); printf("entrez opérandes (nombres) et opérateurs (+,-,*,/,C (cos),S)\n"); printf("séparés par des blancs ou virgules\n"); fflush(stdin); gets(txt); /* on lit un texte qui sera traité par après */ deb=txt; /* deb pointe le début du texte non encore traité */

Données et Algorithmique - LES PILES ET FILES

http://www-ipst.u-strasbg.fr/pat/program/algo06.htm (4 of 6) [21-11-2001 17:42:18]

Page 66: algo

do { while(*deb==' '||*deb==',') deb++; if(*deb==0)break; if(isdigit(*deb)||*deb=='.'||(*deb=='-'&&isdigit(*(deb+1)))) { x.type=operande; sscanf(deb,"%f",&(x.val.op_r)); empiler(&x); while(isdigit(*deb)||*deb=='.') deb++; /*pointer la suite*/ } else /*cas d'un opérateur */ { x.val.op_c=toupper(*(deb++)); x.type=operateur; empiler(&x); } } while(1); }

float eval_post(void) { float r1,r2; composante x; if(depiler(&x)!=0) {puts("expression non postfixée");return(0);} if(x.type==operande) return(x.val.op_r); /* else inutile car les autres cas se finissent par return */ /* on traite d'abord les opérateurs unaires */ if (x.val.op_c=='C') return(cos(eval_post())); if (x.val.op_c=='S') return(sin(eval_post())); /* les deuxaires maintenant */ r2=eval_post(); r1=eval_post(); switch (x.val.op_c) { case '+':return(r1+r2); case '-':return(r1-r2); case '*':return(r1*r2); case '/':return(r1/r2); } puts("erreur (code opératoire inconnu par exemple)"); return(0); }

void main(void) { saisie();

Données et Algorithmique - LES PILES ET FILES

http://www-ipst.u-strasbg.fr/pat/program/algo06.htm (5 of 6) [21-11-2001 17:42:18]

Page 67: algo

printf("l'expression postfixée vaut %6.1f\n",eval_post()); }

Les piles permettent très souvent de clarifier l'implantation d'un algorithme, bien qu'évidemment on puisseutiliser le principe tout en n'utilisant que des tableaux ou listes.

Données et Algorithmique - LES PILES ET FILES

http://www-ipst.u-strasbg.fr/pat/program/algo06.htm (6 of 6) [21-11-2001 17:42:18]

Page 68: algo

LES ARBRESintroduction●

expressions arithmétiques (arb_expr)●

listes triées●

les arbres généraux●

introductionLes listes et piles sont des structures dynamiques unidimensionnelles. Les arbres sont leur généralisationmultidimensionnelle (une liste est un arbre dont chaque élément a un et un seul fils). On utilise unvocabulaire inspiré des arbres généalogiques (sexiste il est vrai, bien qu'on utilise quelquefois les termesfille et mère). Chaque composante d'un arbre contient une valeur, et des liens vers ses fils. On peutdistinguer un noeud, qui est une composante ayant des fils, et une feuille, qui n'en possède pas (mais estfils d'un noeud) mais souvent on préfère utiliser un type noeud y compris pour les feuilles (tous les filssont mis à NULL), surtout si l'arbre est évolutif (une feuille peut devenir un noeud, et inversement). Unebranche rassemble un lien vers un fils mais aussi ce fils et toute sa descendance. Le noeud racine est leseul qui n'est le fils d'aucun noeud (tous les autres noeuds sont donc sa descendance). Comme pour lepremier d'une liste, l'adresse de la racine est nécessaire et suffisante pour accéder à l'intégralité d'unarbre. Un arbre N-aire ne contient que des noeuds à N fils (et des feuilles). Une liste est donc un arbreunaire. De nombreux algorithmes ont été développés pour les arbres binaires (nous verrons que tout arbrepeut être représenté par un arbre binaire). Comme les listes, les arbres sont complètement dynamiques,mais les liens sont également gourmands en mémoire. L'accès aux données est encore séquentiel, mais onverra qu'il reste néanmoins rapide.

expressions arithmétiques (arb_expr)Nous allons détailler les fonctionnalités de base des arbres à l'aide d'un exemple : la représentation etl'évaluation d'expressions arithmétiques. Nous supposerons (voir chapitre sur les piles) utiliseruniquement des opérandes flottants, les opérateurs deuxaires +,-,*,/ et les opérateurs unaires C (pourcosinus) et S (sinus). L'expression 2*5 + 2*{cos[(5*3.14)/180]} se représentera :

Données et Algorithmique - LES ARBRES

http://www-ipst.u-strasbg.fr/pat/program/algo07.htm (1 of 9) [21-11-2001 17:42:39]

Page 69: algo

Les composantes de l'arbre seront donc soit des opérateurs (noeuds), soit des opérandes (feuilles). Nousallons choisir les déclarations suivantes :

typedef float type_feuille;typedef struct s_noeud_2 {char op_c; struct s_comp*fils1; struct s_comp*fils2; }type_noeud_2;typedef struct s_noeud_1 {char op_c; struct s_comp*fils; }type_noeud_1;typedef struct s_comp {int arite; union {type_noeud_2 n2; type_noeud_1 n1; type_feuille f; }val; }composante;typedef composante *lien;

Nous prévoyons donc deux types de noeuds : à arité 1 (avec un fils) ou à arité 2 (deux fils). On aurait puutiliser un seul type (à arité 2) en mettant NULL dans le second fils en cas d'arité 1. Une feuille parcontre ne contient aucun lien. Une composante de l'arbre contiendra donc un indicateur de son type (icil'arité) et, suivant ce type, soit une feuille, soit un noeud (d'arité 1 ou 2). Nous allons écrire une fonctioncréant un tel arbre (à partir d'une chaîne de caractères préalablement saisie, contenant l'expression ennotation polonaise préfixée par exemple) :lien saisie_prefixe(char **deb)

Données et Algorithmique - LES ARBRES

http://www-ipst.u-strasbg.fr/pat/program/algo07.htm (2 of 9) [21-11-2001 17:42:39]

Page 70: algo

/* on donne une chaîne de char contenant l'expression en notation préfixée. les opérateurs possibles sont+,-,*,/(deuxaires), C,S(cos,sin,unaires). Les nombres sont séparés par des blancs (optionnels pour lesopérateurs) Les nombres commencent par un chiffre (exemple 0.5 au lieu de .5).*//* deb pointe sur le début de chaîne, il pointera ensuite sur le reste de la chaîne (pas encore traitée) doncpassage par adresse d'un pointeur */

{ lien x; char c; while(**deb==' '||**deb==',') (*deb)++; if(**deb==0) /* on est arrivé en fin de chaîne */ {puts("erreur : il doit manquer des opérandes"); return(NULL);} x=(composante*)malloc(sizeof(composante)); if(isdigit(**deb)) { x->arite=0; sscanf(*deb,"%f",&(x->val.f)); while(isdigit(**deb)||**deb=='.') (*deb)++; } else { c=toupper(*((*deb)++)); if(c=='*'||c=='/'||c=='+'||c=='-') { x->arite=2; x->val.n2.op_c=c; x->val.n2.fils1=saisie_prefixe(deb); x->val.n2.fils2=saisie_prefixe(deb); } else if(c=='C'||c=='S') { x->arite=1; x->val.n1.op_c=c; x->val.n1.fils=saisie_prefixe(deb); } else printf("erreur, '%c'n'est pas un opérateur prévu\n",c); } return(x); }

On peut remarquer que cette fonction est récursive. La création de l'arbre à partir d'une expressionpostfixée est similaire (scruter la chaîne dans l'autre sens par exemple), à partir d'une expression infixéec'est un peu plus dur, surtout si l'on ne veut pas imposer d'entrer toutes les parenthèses, par exemple1+2+3 au lieu de (1+(2+3)).

Données et Algorithmique - LES ARBRES

http://www-ipst.u-strasbg.fr/pat/program/algo07.htm (3 of 9) [21-11-2001 17:42:39]

Page 71: algo

L'utilisation d'un tel arbre devient maintenant très simple. On utilisera la récursivité. Pour évaluerl'expression, si c'est une feuille unique la valeur est celle de la feuille, si c'est un noeud, la valeur estobtenue en effectuant l'opération correspondante, après évaluation (récurrente, donc soit directement lavaleur si feuille soit nouveau calcul) de ses fils :

float eval(lien x) { float r1,r2; if(x->arite==0) return(x->val.f); else if (x->arite==1) { if (x->val.n1.op_c=='C') return(cos(eval(x->val.n1.fils))); else if (x->val.n1.op_c=='S') return(sin(eval(x->val.n1.fils))); } else { r1=eval(x->val.n2.fils1); r2=eval(x->val.n2.fils2); switch (x->val.n2.op_c) { case '+':return(r1+r2); case '-':return(r1-r2); case '*':return(r1*r2); case '/':return(r1/r2); } } /* si aucun return n'a été effectué jusqu'ici*/ puts("erreur (code opératoire inconnu par exemple)"); return(0); }

Le parcours des arbres (c'est à dire le passage par tous les noeuds et feuilles) se fait d'habitude de manièrerécursive. On doit évidement parcourir l'arbre pour afficher son contenu. On peut utiliser dans le cas desarbres binaires trois possibilités de parcours : afficher la valeur du noeud puis récursivement de ses deuxfils, afficher le premier fils, la valeur du noeud, puis le second fils, ou afficher les deux fils avant lavaleur du noeud. On obtient dans notre cas directement les notations préfixé, infixée et postfixée (avec unpetit travail supplémentaire pour la gestion des parenthèses en notation infixée, qu'on aurait pu simplifiersi l'on avait accepté des parenthèses surabondantes) :

void affiche_prefixe(lien x) { switch(x->arite) { case 0:printf("%6.1f ",x->val.f);break;

Données et Algorithmique - LES ARBRES

http://www-ipst.u-strasbg.fr/pat/program/algo07.htm (4 of 9) [21-11-2001 17:42:39]

Page 72: algo

case 1:printf(" %C ",x->val.n1.op_c); affiche_prefixe(x->val.n1.fils); break; case 2:printf(" %c ",x->val.n2.op_c); affiche_prefixe(x->val.n2.fils1); affiche_prefixe(x->val.n2.fils2); } }

void affiche_postfixe(lien x) { switch(x->arite) { case 0:printf("%6.1f ",x->val.f);break; case 1:affiche_postfixe(x->val.n1.fils); printf(" %C ",x->val.n1.op_c); break; case 2:affiche_postfixe(x->val.n2.fils1); affiche_postfixe(x->val.n2.fils2); printf(" %c ",x->val.n2.op_c); } }

void affiche_infixe(lien x) { switch(x->arite) { case 0:printf("%6.1f ",x->val.f);break; case 1:printf(" %C( ",x->val.n1.op_c); affiche_infixe(x->val.n1.fils); putch(')'); break; case 2:if(x->val.n2.fils1->arite!=0)putch('('); affiche_infixe(x->val.n2.fils1); if(x->val.n2.fils1->arite!=0)putch(')'); printf(" %c ",x->val.n2.op_c); if(x->val.n2.fils2->arite!=0)putch('('); affiche_infixe(x->val.n2.fils2); if(x->val.n2.fils2->arite!=0)putch(')'); } }

Notre exemple est un peu plus complexe que dans véritable arbre binaire, puisque nous acceptionségalement des noeuds à un seul fils.

Données et Algorithmique - LES ARBRES

http://www-ipst.u-strasbg.fr/pat/program/algo07.htm (5 of 9) [21-11-2001 17:42:39]

Page 73: algo

listes triéesIl est possible de mémoriser une liste ordonnée à l'aide d'un arbre binaire. Chaque noeud de l'arbrecontient une valeur et deux liens : l'un vers un sous-arbre ne contenant que des valeurs inférieures, l'autrevers des valeurs supérieures. Nous allons traiter cette fois des chaînes de caractères plutôt que des réels.Nous définirons donc les types suivants :

typedef struct s_noeud *lien;typedef struct s_noeud {char *nom; lien fils1; lien fils2; }type_noeud;

Il vaut mieux ne pas prévoir de type spécifique pour les feuilles, l'arbre étant géré de manière évolutive(une feuille sera donc un noeud avec ses deux fils valant le pointeur NULL). Le nom contenu danschaque noeud aurait pu être un tableau statique de caractères, mais pour optimiser le coût mémoire, nousutiliserons un tableau dynamique. Donc, pour allouer la mémoire d'un nouveau noeud, deux mallocseront nécessaires : un pour le noeud lui-même, et un pour le nom qui lui est associé. Ecrivons unefonction de création d'un noeud (on lui transmet le nom associé, elle retourne l'adresse allouée):

lien cree_feuille(char *nouv_nom) { lien x; int taille; x=(lien)malloc(sizeof(type_noeud)); taille=strlen(nouv_nom)+1; /* compter le \0 */ x->nom=(char*)malloc(taille); strcpy(x->nom,nouv_nom); x->fils1=NULL; x->fils2=NULL; return(x); }

Supposons entrer dans l'ordre : Jean, Bernard, Lucie, Anne, Jacques, Laurent, Maud, Luc, Julie, Elsa. Sivous créez progressivement l'arbre, vous pourrez voir que toute nouvelle valeur trouve toujours sa place,les feuilles se transformant petit à petit en noeuds, au fur et à mesure de l'augmentation de la taille del'arbre.

Données et Algorithmique - LES ARBRES

http://www-ipst.u-strasbg.fr/pat/program/algo07.htm (6 of 9) [21-11-2001 17:42:39]

Page 74: algo

La fonction effectuant la saisie et la création de cet arbre devra donc, après la saisie du nouveau nom àinsérer, rechercher sa position définitive. Cette recherche sera récursive: sur un noeud donné, si lenouveau nom est plus petit, rechercher dans la descendance du fils1, sinon rechercher dans ladescendance du fils2. La recherche s'arrête quand on arrive à un pointeur NULL (qui sera remplacé parl'adresse du nouveau noeud). En cas d'égalité, si l'on désire une création stable, un nouveau nom seraplacé derrière ceux déjà existants. :

void insert_feuille(lien racine, lien x) { while(racine!=NULL) /* ou boucle infinie */ { if(strcmp(x->nom,racine->nom)<0) if(racine->fils1==NULL){racine->fils1=x;return;} else racine=racine->fils1; else if(racine->fils2==NULL){racine->fils2=x;return;} else racine=racine->fils2; } }

lien saisie(void) { lien racine=NULL; char txt[100]; do { printf("entrez un nouveau nom, @@@ pour finir : "); gets(txt); if(strcmp(txt,"@@@")) if(racine==NULL)racine=cree_feuille(txt); else insert_feuille(racine,cree_feuille(txt)); } while(strcmp(txt,"@@@")); return(racine); }

Données et Algorithmique - LES ARBRES

http://www-ipst.u-strasbg.fr/pat/program/algo07.htm (7 of 9) [21-11-2001 17:42:39]

Page 75: algo

On remarque l'efficacité de cette méthode : aucun déplacement d'élément, le tri se fait par insertion, maisavec recherche optimisée (du type dichotomie : l'espace de recherche est réduit à chaque test). Pour Ninsertions, on fait donc N recherches donc N*P lectures de composantes (P profondeur de l'arbre).

Une fois l'arbre créé, on peut afficher la liste triée par ordre alphabétique par un simple parcours infixé(arbr_nom):

void affiche(lien x) { if(x!=NULL) { affiche(x->fils1); printf("%s, ",x->nom); affiche(x->fils2); } }

L'utilisation d'un arbre binaire pour une liste triée permet donc une programmation relativement aisée,des algorithmes rapides, mais moyennant un peu de place mémoire supplémentaire. L'arbre va possédersimultanément tous les avantages des autres structures de données:

totalement dynamique: l'insertion d'un élément se fait sans aucun déplacement d'élément (ni mêmed'échange de liens comme c'était le cas pour les listes)

rapide : la recherche d'un élément se fait en P tests maximum, P étant la profondeur de l'arbre (cequi donne la même efficacité qu'une recherche dichotomique dans un tableau, dans le cas d'unarbre équilibré).

parcours facile des données sans coût trop important en mémoire (avec deux liens on obtient unestructure bidimensionnelle, alors qu'avec une liste à chaînage avant et arrière on garde unestructure unidimensionnelle, bien que bidirectionnelle).

Par contre l'arbre binaire nécessite d'être équilibré pour profiter pleinement de ces avantages. Un arbreéquilibré est un arbre organisé de telle manière à ce que sa profondeur soit minimale. A l'extrême, en casd'introduction d'une liste de noms déjà triée, tous les fils1 pointeront sur NULL alors que les fils2pointeront sur le suivant, on se retrouve dans le cas d'une liste chaînée simple. Différents algorithmesd'équilibrage d'arbres binaires existent, mais en général un algorithme simple permet un résultatsatisfaisant (sauf en cas d'un très grand nombre de données), l'équilibre parfait n'étant pas nécessaire.

les arbres générauxQuand le nombre de fils de chaque élément est variable, on peut soit prévoir un tableau statique desadresses des fils, soit prévoir un tableau dynamique, ce qui optimise l'occupation mémoire maiscomplique l'ajout de fils supplémentaires. Pour avoir une gestion parfaitement dynamique, on peut créerune liste des adresses des fils :

Données et Algorithmique - LES ARBRES

http://www-ipst.u-strasbg.fr/pat/program/algo07.htm (8 of 9) [21-11-2001 17:42:39]

Page 76: algo

En fait, plutôt que de créer cette liste hors des noeuds, le plus simple (et qui utilise autant de mémoire)est d'associer à chaque noeud l'adresse de son fils aîné, et de son frère cadet. Accéder à tous les filsrevient donc à accéder au fils aîné puis à tous ses frères:

On peut remarquer qu'un tel arbre est un arbre binaire: chaque noeud possède deux liens. On peut donctraiter tout arbre sous forme d'un arbre binaire.

Une autre amélioration possible d'un arbre est de permettre un accès toujours séquentiel maisbidirectionnel : pour un arbre binaire, chaque noeud possède en plus l'adresse de son père, pour un arbregénéralisé ceci revient à ce que chaque frère connaît son aîné, l'aîné connaissant leur père commun. Cetaccès bidirectionnel est coûteux en mémoire, mais complique également les modifications (plus de liensà gérer), pour par contre accélérer les parcours dans l'arbre. On ne prévoira cette amélioration que lorsquel'on utilise de fréquentes remontées (l'utilisation d'algorithmes récursifs ne nécessite en général pas cesliens, le fait de quitter une fonction appelée pour gérer un fils fait automatiquement retrouver le père).

Données et Algorithmique - LES ARBRES

http://www-ipst.u-strasbg.fr/pat/program/algo07.htm (9 of 9) [21-11-2001 17:42:39]

Page 77: algo

LES GRAPHESUn graphe est en ensemble de noeuds reliés par des liens. Ce n'est plus un arbre dès qu'il existe deuxparcours différents pour aller d'au moins un noeud à un autre. Un graphe est connexe lorsqu'il estpossible de trouver au moins un parcours permettant de relier les noeuds deux à deux (un arbre est ungraphe connexe, deux arbres forment un graphe non connexe). Un graphe est dit pondéré lorsqu'à chaquelien est associée une valeur (appelée poids). On utilisera un graphe pondéré par exemple pour gérer desitinéraires routiers (quelle est la route la plus courte pour aller d'un noeud à un autre), pour gérer desfluides (noeud reliés par des tuyauteries de diamètre différent) ou pour des simulations de trafic routier,pour simuler un circuit électrique, pour prévoir un ordonnancement dans le temps de tâches... Un grapheest dit orienté lorsque les liens sont unidirectionnels. Nous ne traiterons pas ici en détail les algorithmesassociés aux graphes, mais nous aborderons quelques problèmes rencontrés.

On peut représenter un graphe de manière dynamique, comme les arbres (le nombre de liens par noeudest souvent variable). Une autre solution est de numéroter les N sommets, et d'utiliser une matrice carréeNxN, avec en ligne i et colonne j un 0 si les noeuds i et j ne sont pas reliés, ou le poids de la liaison sinon(1 pour les graphes non pondérés). Pour des graphes non orientés, la matrice est symétrique (par rapportà la diagonale), ce qui permet d'économiser de la mémoire mais peut compliquer les programmes (c'est latechnique employée pour les éléments finis). Une représentation par matrice est surtout intéressantelorsqu'il y a beaucoup de liens (graphe presque complet), la représentation à l'aide de pointeurs étantmoins gourmande en mémoire pour les graphes comportant peu de liens par noeud.

Un problème important est le parcours d'un graphe : il faut éviter les boucles infinies, c'est à direretourner sur un noeud déjà visité et repartir dans la même direction. On utilise par exemple desindicateurs de passage (booléens), ou une méthode à jetons (on place des "jetons" dans différents noeudsbien choisis et on les fait suivre les liens). Une méthode souvent utilisée est de rechercher avant tout (etune seule fois) l'arbre recouvrant : c'est un arbre permettant de visiter tous les noeuds, n'utilisant que desliens existants dans le graphe (mais pas tous). Cet arbre recouvrant n'est évidement pas unique. En cas degraphe non connexe, il faut rechercher plusieurs arbres recouvrants.

On peut remarquer qu'un arbre recouvrant d'un graphe connexe à N sommets aura nécessairement N-1liens. Pour les graphes pondérés, on peut rechercher l'arbre recouvrant de poids minimum (somme despoids des liens minimale). Différents algorithmes existent pour traiter ce problème.

Données et Algorithmique - LES GRAPHES

http://www-ipst.u-strasbg.fr/pat/program/algo08.htm [21-11-2001 17:42:43]

Page 78: algo

LES FICHIERSles fichiers séquentiels●

les fichiers à accès direct●

l'indexation●

Les fichiers ont pour avantage d'être dynamiques (la taille peut varier ou du moins augmenter au cours del'utilisation, du moins tant qu'il reste de la place sur le support), et de ne pas être volatiles comme l'est lamémoire (c'est à dire que les informations restent présentes en l'absence d'alimentation électrique). Leurprincipal inconvénient est le temps d'accès à une donnée (de l'ordre de 106 fois plus lent que la mémoire,en général plus de 10 ms pour un disque dur, mais jusqu'à plusieurs secondes pour une bandemagnétique). L'insertion et la suppression d'éléments autre part qu'en fin d'un fichier est quasimentimpossible, en général on devra passer par la création d'un nouveau fichier, y recopier le début du fichierinitial jusqu'à la modification prévue, puis écrire les données modifiées puis recopier le reste du fichier.Les fichiers peuvent être séquentiels ou à accès direct.

les fichiers séquentielsUn fichier séquentiel permet uniquement d'accéder aux données dans l'ordre de leur écriture. L'exemplele plus courant est la bande magnétique (ou streamer ou DAT). On n'utilise plus que rarement les fichiersstockés sur bande directement dans les programmes : du fait des possibilités des disques durs (jusqu'àplusieurs Giga-octets), on préfère utiliser des fichiers à accès direct, et les sauvegarder sur bande(séquentiellement) une fois le traitement terminé. Certaines grosses applications nécessitent néanmoinsdes traitements directement sur bandes magnétiques, il faut alors choisir les algorithmes en conséquence(en général dans ces cas on utilisera au moins deux lecteurs de bandes, un pour le fichier initial, un pourle fichier traité), en choisissant plus particulièrement des algorithmes divisant le fichier en sous-fichiersqui eux tiendront en mémoire centrale et pourront être traités plus rapidement (par exemple pour les tris,on utilisera par exemple un tri par fusion, surtout si l'on dispose de trois lecteurs : deux pour les sousfichiers à fusionner, le troisième pour le fichier final). Le grand avantage du fichier séquentiel est qu'ilpeut contenir des données de tout type, de taille différente (c'est désormais la seule raison de sonutilisation). Pour stocker un graphique, on pourra enregistrer le nombre de segments, puis lescaractéristiques de chacun des segments, puis le nombre d'arcs de cercles, puis leurs caractéristiques,...

On classe souvent sous la dénomination de fichiers séquentiels les fichiers de texte : se sont en faitsouvent des fichiers à accès direct aux caractères (on peut accéder directement au Nième caractère), maisen fait l'accès est séquentiel au niveau des lignes : pour accéder à la Nième ligne, il faut lire le fichierdepuis le début, jusqu'à compter N-1 signes de fin de ligne. Les fichiers de texte peuvent également êtreutilisés pour stocker des valeurs numériques : les nombres sont alors formatés pour être écrits en décimalà l'aide de caractères ASCII, et peuvent donc directement être imprimés ou réutilisés par un autre

Données et Algorithmique - LES FICHIERS

http://www-ipst.u-strasbg.fr/pat/program/algo09.htm (1 of 3) [21-11-2001 17:42:54]

Page 79: algo

programme ou sur une autre machine, alors que la sauvegarde directe d'une valeur numérique est faite enbinaire (recopie des 0 et 1 en mémoire), ce qui prend moins de place mais n'est plus lisible que par unprogramme qui utilise le même format.

Les fichiers séquentiels ne peuvent en général pas être modifiés, la seule possibilité étant l'ajout derrièreles données déjà stockées (pour un fichier texte, sur disque, on peut remplacer des caractères mais pas enajouter ni en supprimer sauf en fin de fichier).

les fichiers à accès directUn fichier à accès direct correspond à un tableau en mémoire : toutes ses composantes ont la même taille,on peut donc accéder directement à la Nième. Comme pour un tableau, les insertions et suppressionsnécessitent des décalages des composantes suivantes, ce qui est en général trop long pour êtreenvisageable. Ceci exclut donc l'utilisation de tout algorithme utilisant l'insertion (le tri par insertion parexemple), mais aussi ceux qui déplacent des éléments sans les positionner à leur place définitive (le tribulle par exemple). Une méthode de tri sera par exemple un tri par sélection et création d'un nouveaufichier. L'accès au données devra être optimisé : on préférera bien évidement la dichotomie à la rechercheséquentielle, et même on préférera une dichotomie pondérée (avec estimation par calcul de la positionprobable), puisque tout calcul sera beaucoup plus rapide qu'une lecture dans le fichier.

Un fichier à accès direct peut également être utilisé pour stocker et traiter des listes, arbres ou graphes :on utilise la méthode du super-tableau : chaque élément est numéroté, en fonction de sa position dans lefichier, les liens étant ces numéros. Il faut bien garder à l'esprit qu'il ne faut jamais stocker sur fichier unpointeur : l'adresse où a été mise la valeur pointée a peu de chances d'être la même à la prochaineutilisation du programme. Ils est alors toujours nécessaire de numéroter les composantes et remplacer lespointeurs par le numéro de la valeur pointée avant de faire une sauvegarde sur fichier.

l'indexationLa méthode souvent la plus efficace pour l'utilisation de fichiers séquentiels est l'indexation (elle estégalement utilisable pour les autres types de données, stockées en mémoire). Les composantes sontstockées dans le fichier dans l'ordre de leur création. On utilise alors un tableau d'index, donnant enpremière position le numéro de la première composante, puis de la seconde,... L'avantage de cetteméthode est que l'ajout de composantes est optimal : on rajoute la valeur en fin de fichier, on met à jourle tableau d'index. Tout déplacement d'une composante sera donc remplacé par une modification dutableau d'index, sans déplacement réel de la valeur dans le fichier. En général, ce tableau peut tenir enmémoire, ce qui permet une modification rapide, en général on préfère le sauver également sur supportmagnétique avant de quitter le programme, ce qui évitera de le recréer (par exemple refaire un tri) à laprochaine utilisation. On peut également utiliser une liste d'index si les déplacements sont fréquents(mais alors l'accès devient séquentiel). Le second avantage de cette méthode est que l'on peut utilisersimultanément plusieurs index : par exemple pour une liste de personnes, on peut créer un index pour leclassement alphabétique des noms, un autre sur les villes, on accédera donc plus rapidement à tous leschamps indexés, alors que les champs non indexés devront se satisfaire d'une recherche séquentielle, etce sans modification dans le fichier (un tri par nom puis par ville auraient été nécessaires sansindexation). Par contre toute modification nécessitera la mise à jour de tous les tableaux d'index.

Données et Algorithmique - LES FICHIERS

http://www-ipst.u-strasbg.fr/pat/program/algo09.htm (2 of 3) [21-11-2001 17:42:54]

Page 80: algo

Exemple:

La suppression, par contre, pose problème. En général, toujours pour éviter les décalages dans lesfichiers, on préfère marquer d'un signe distinctif les champs supprimés (par exemple un nom nonalphabétique ou vide), puis remettre à jour les index qui ne pointeront plus sur ce champ. Le retassage,assez long, n'est effectuée que sur ordre de l'utilisateur ou lorsqu'il quitte le programme. On peut aussi(comme dans la méthode du super-tableau) créer une liste des champs vides, ce qui permettra d'yaccéder, plus rapidement que par une recherche séquentielle, lors de la prochaine insertion.

Sur un fichier indexé, on peut à nouveau se permettre des algorithmes utilisant l'insertion, puisquecelle-ci n'affecte que l'index (à accès rapide). Pour un tri par exemple, on pourra utiliser le tri parinsertion, à condition d'optimiser la recherche de la position d'insertion (par dichotomie pondérée parexemple), puisque celle-ci nécessite des lectures de champs dans le fichier alors que l'insertion n'entraîneque des décalages dans un tableau, d'une durée généralement négligeable devant le temps pris par larecherche. On peut également utiliser une liste d'index plutôt qu'un tableau si nécessaire.

Données et Algorithmique - LES FICHIERS

http://www-ipst.u-strasbg.fr/pat/program/algo09.htm (3 of 3) [21-11-2001 17:42:54]

Page 81: algo

CORRECTION DES EXERCICESBOUCLE●

TUSEXO_A●

TUSEXO_B●

GAUSS_MRD●

INSE_TTD●

BOUCLE#include <stdio.h>;void main(void) { float puiss,x,result; printf("entrez x "); scanf("%f",&x); result=2 -5*x +(puiss=x*x) -3*(puiss*=x) +2*puiss*x; printf("résultat : %f\n",result); }

TUSEXO_A

#include <stdio.h>#include "base_tus.inc"#define dim 10void main(void) { int i,nb; composante v,t[dim],moy=0; init_tus(t,&nb,dim); do { printf("entrez la %dième note (fin si <0 ou >20) :",nb+1); scanf("%f",&v); if(v<0||v>20) break; /* on aurait pu le mettre dans la condition du while */ moy+=v; } while (!ajoute_val_tus(t,&nb,dim,v)); if(nb) moy/=nb; printf("moyenne des %d notes : %5.2f\n",nb,moy); for(i=0;i<nb;i++) printf("%2dième valeur : %5.2f (écart/moyenne%+5.2f)\n",i+1,t[i],t[i]-moy); }

Données et Algorithmique - CORRECTION DES EXERCICES

http://www-ipst.u-strasbg.fr/pat/program/algo10.htm (1 of 6) [21-11-2001 17:43:01]

Page 82: algo

TUSEXO_B#include <stdio.h>#include <conio.h>#include "base_tus.inc"#include "mani_tus.inc"#define dim 10void lecture(type_tus t,int *nb) { composante v; do { printf("entrez la %dième note (fin si <0 ou >20) :",(*nb)+1); scanf("%f",&v); if(v<0||v>20) break; /* on aurait pu le mettre dans la condition du while */ } while (!ajoute_val_tus(t,nb,dim,v)); }

void main(void) { int nb; composante t[dim]; char rep; init_tus(t,&nb,dim); lecture(t,&nb); do { printf("0 fin, 1 affiche, 2 rot gauche, 3 rot droite, 4 suppr, 5 ins :"); rep=getche()-'0'; printf("\n"); switch (rep) { case 0:puts("au revoir");break; case 1:affiche_tus(t,nb);break; case 2:rot_gauche_tus(t,nb);break; case 3:rot_droite_tus(t,nb);break; case 4:{int pos; printf("position de l'élément à supprimer ? "); scanf("%d",&pos); suppr_tus(t,&nb,pos); break;} case 5:{int pos;composante v; printf("position de l'élément à insérer ? "); scanf("%d",&pos); printf("valeur à insérer ? "); scanf("%f",&v); insert_tus(t,&nb,dim,pos,v); break;} default:puts("code erroné !"); } } while (rep); }

Données et Algorithmique - CORRECTION DES EXERCICES

http://www-ipst.u-strasbg.fr/pat/program/algo10.htm (2 of 6) [21-11-2001 17:43:01]

Page 83: algo

GAUSS_MRD#include <stdio.h>#include <alloc.h>#include <math.h> /* pour fabs */

#define composante floattypedef composante *mat_dyn;

#define adr_mrd(l,c,nbc) ((l)*(nbc)+(c))

mat_dyn alloc_mrd(int nbl,int nbc) {return((mat_dyn)malloc(nbl*nbc*sizeof(composante)));}

void affiche_mrd(mat_dyn tab,int nblig, int nbcol) { int l,c; printf("\n"); for(l=0;l<nblig;l++) { printf("|"); for(c=0;c<nbcol;c++)printf("%5.1f ",tab[adr_mrd(l,c,nbcol)]); printf(" |\n"); } }

void autom_3_3(mat_dyn *t,int*nblig, int *nbcol) { composante ex[][3]={{1,1,-2},{1,3,-4},{-1,-2,6}}; int l,c; *nblig=*nbcol=3; *t=alloc_mrd(*nblig,*nbcol); for(l=0;l<*nblig;l++) for(c=0;c<*nbcol;c++) (*t)[adr_mrd(l,c,*nbcol)]=ex[l][c]; }void autom_3_1(mat_dyn *t,int*nblig, int *nbcol) { composante ex[]={2,6,-1}; int l,c; *nblig=3;*nbcol=1; *t=alloc_mrd(*nblig,*nbcol); for(l=0;l<*nblig;l++) for(c=0;c<*nbcol;c++) (*t)[adr_mrd(l,c,*nbcol)]=ex[l]; }

void gauss_triangulation(mat_dyn A,mat_dyn B, int N) { int ce,l,c,lpivot; composante coef; for(ce=0;ce<N-1;ce++) /* ce=colonne à effacer */ {/* recherche du pivot le plus grand possible (dans les lignes qui restent)*/

Données et Algorithmique - CORRECTION DES EXERCICES

http://www-ipst.u-strasbg.fr/pat/program/algo10.htm (3 of 6) [21-11-2001 17:43:01]

Page 84: algo

lpivot=ce; for(l=ce+1;l<N;l++) if(fabs(A[adr_mrd(l,ce,N)])>fabs(A[adr_mrd(lpivot,ce,N)])) lpivot=l;/* echange de la ligne du pivot et de la ligne ce (ne pas oublier B)*/ for(c=ce;c<N;c++) /* tous les termes devant ce sont nuls */ { coef=A[adr_mrd(ce,c,N)]; A[adr_mrd(ce,c,N)]=A[adr_mrd(lpivot,c,N)]; A[adr_mrd(lpivot,c,N)]=coef; } coef=B[ce];B[ce]=B[lpivot];B[lpivot]=coef; for(l=ce+1;l<N;l++) /* pour chaque ligne au dessous */ { coef=A[adr_mrd(l,ce,N)]/A[adr_mrd(ce,ce,N)]; A[adr_mrd(l,ce,N)]=0; /* normalement pas besoin de le calculer*/ for(c=ce+1;c<N;c++) A[adr_mrd(l,c,N)]-=coef*A[adr_mrd(ce,c,N)]; B[l]-=coef*B[ce]; } } }

void gauss_resolution(mat_dyn A,mat_dyn B,mat_dyn X,int N)/* on pourait rendre le résultat dans B (si l'utilisateurdésirait le garder, il lui suffit de le copier avant). Ceciéconomise le tableau X et le tampon */ { int l,c; composante tampon; for(l=N-1;l>=0;l--) { tampon=B[l]; for(c=l+1;c<N;c++) tampon-=A[adr_mrd(l,c,N)]*X[c]; X[l]=tampon/A[adr_mrd(l,l,N)]; } }

void main(void) { int nblA,nblB,nbcA,nbcB; mat_dyn A,B,X; autom_3_3(&A,&nblA,&nbcA); affiche_mrd(A,nblA,nbcA); autom_3_1(&B,&nblB,&nbcB); affiche_mrd(B,nblB,nbcB);

if(nblA!=nbcA){puts("erreur fatale : matrice A non carrée");return;} if(nblB!=nblB){puts("erreur fatale : nb lignes du second membre incompatibles");return;} if(nbcB!=1){puts("erreur fatale : le second membre doit avoir une seule colonne");return;}

gauss_triangulation(A,B,nblA); /*nblA=nbcA=nblB*/ puts("résultat après triangulation : ");

Données et Algorithmique - CORRECTION DES EXERCICES

http://www-ipst.u-strasbg.fr/pat/program/algo10.htm (4 of 6) [21-11-2001 17:43:01]

Page 85: algo

affiche_mrd(A,nblA,nbcA); affiche_mrd(B,nblB,nbcB);

X=alloc_mrd(nblB,nbcB); gauss_resolution(A,B,X,nblA); puts("solution :"); affiche_mrd(X,nblB,1); }

INSE_TTD#include <stdio.h>#include <alloc.h>#include <string.h>typedef char composante; typedef composante *ligne;/* ou composante ligne []*/typedef ligne *mat_ttd;/* ou ligne mat_ttd[] */

void affiche(mat_ttd tab,int nblig) { int l; for(l=0;l<nblig;l++)printf("%s\n",tab[l]); }

void lecture(mat_ttd *tdl,int *nblig) { /* on se limite à 100 lignes de 1000 caractères, mais unefois sorti de la fonction, seule la place nécessaire estréservée (variables locales). On supprime ces limites parutilisation (toujours temporaire) de listes chaînées */ composante txt[1000]; ligne tab_de_lignes[100]; int longueur; *nblig=0; printf("entrez vos lignes (fin du texte par '@@@' en déb de ligne):\n"); do { gets(txt); longueur=strlen(txt); /* \0 non compris */ if(!strcmp(txt,"@@@"))break; tab_de_lignes[*nblig]=(ligne)malloc(longueur+1); strcpy(tab_de_lignes[*nblig],txt); (*nblig)++; } while (1); *tdl=(mat_ttd)malloc((*nblig)*sizeof(ligne)); memcpy(*tdl,tab_de_lignes,(*nblig)*sizeof(ligne)); }

void tri_insertion(mat_ttd tab, int N) { int pt,dpg; /* position testée,dernier plus grand */

Données et Algorithmique - CORRECTION DES EXERCICES

http://www-ipst.u-strasbg.fr/pat/program/algo10.htm (5 of 6) [21-11-2001 17:43:01]

Page 86: algo

ligne tampon; for(pt=1;pt<N;pt++) { dpg=pt-1; tampon=tab[pt]; while(strcmp(tab[dpg],tampon)>0 && dpg>=0) {tab[dpg+1]=tab[dpg];dpg--;} tab[dpg+1]=tampon; } }

void main(void) { int nbl; mat_ttd txt; lecture(&txt,&nbl); puts("avant tri :"); affiche(txt,nbl); tri_insertion(txt,nbl); puts("après tri :"); affiche(txt,nbl); }

Données et Algorithmique - CORRECTION DES EXERCICES

http://www-ipst.u-strasbg.fr/pat/program/algo10.htm (6 of 6) [21-11-2001 17:43:01]

Page 87: algo

Données et Algorithmique - Index

A , B , C , D , E , F , G , I , L , M , N , O , P , Q , R , S ,T , U , V , W

Aaccès●

direct [1]

[2]

séquentiel [1] [2]❍

allocation dynamique [1]●

arbre [1]●

binaire [1]

[2]

argument [1]●

Bbande [1] [2]●

binaire [1]●

bit [1]●

boucles [1]●

Cindex du langage C●

chiffres significatifs [1]●

clef [1] [2]●

Données et Algorithmique - Index

http://www-ipst.u-strasbg.fr/pat/program/algofi.htm (1 of 6) [21-11-2001 17:43:08]

Page 88: algo

Ddébogage [1]●

décalage [1]●

décalages [1]●

défiler [1]●

dépiler [1]●

define [1]●

deuxaire [1]●

dichotomie [1] [2]

[3]

dimension [1] [2]●

do-while [1]●

dynamique [1] [2]

[3] [4]

Eeffet de bord [1]●

empiler [1]●

encombrement [1]●

enfiler [1]●

Ffeuille [1]●

fichier [1]●

FIFO [1]●

file [1]●

fils [1]●

float [1]●

for [1]●

free [1]●

Données et Algorithmique - Index

http://www-ipst.u-strasbg.fr/pat/program/algofi.htm (2 of 6) [21-11-2001 17:43:08]

Page 89: algo

GGauss [1] [2]●

graphe [1]●

Iindex [1]●

indexation [1]●

infixé [1] [2]●

insertion [1] [2]

[3] [4] [5]

interpolation [1]●

LLagrange [1]●

largeur de bande [1]●

LIFO [1]●

ligne de ciel [1] [2]●

liste [1] [2]

[3]

Mmalloc [1]●

mathématiques [1] [2]

[3] [4]

matrice [1] [2]

[3]

triangulée [1]❍

modèle [1]●

Données et Algorithmique - Index

http://www-ipst.u-strasbg.fr/pat/program/algofi.htm (3 of 6) [21-11-2001 17:43:08]

Page 90: algo

Nnoeud [1]●

notation polonaise [1]●

NULL [1] [2]

[3]

Oobjets [1]●

optimisation [1]●

Pparcours [1] [2]

[3]

pile [1] [2]

[3]

pivot [1]●

de Gauss [1]●

pointeur [1] [2]

[3]

polynôme [1] [2]●

postfixé [1] [2]●

préfixé [1] [2]●

Qqueue [1]●

Quick Sort [1]●

Rrécursif [1]●

récursivité [1] [2]●

Données et Algorithmique - Index

http://www-ipst.u-strasbg.fr/pat/program/algofi.htm (4 of 6) [21-11-2001 17:43:08]

Page 91: algo

[3]

racine [1]●

recherche [1] [2]●

retassage [1]●

Sséquentiel [1] [2]●

sentinelle [1]●

spline [1]●

stable [1]●

(tri) [1]●

stack [1]●

strcmp [1]●

structuré [1]●

suites [1]●

super-tableau [1] [2]●

suppression [1] [2]

[3]

Ttableau [1] [2]

[3] [4] [5] [6] [7]

dynamique [1]❍

multidimensionnel [1]❍

statique [1]❍

ternaire [1]●

tri [1]

bulle [1] [2]❍

tri par●

arbre [1]

comptage [1]❍

création [1] [2] [3]❍

Données et Algorithmique - Index

http://www-ipst.u-strasbg.fr/pat/program/algofi.htm (5 of 6) [21-11-2001 17:43:08]

Page 92: algo

fusion [1] [2]❍

insertion [1] [2] [3]❍

sélection [1] [2]❍

rapide [1] [2]●

shell [1] [2]●

triangulation [1] [2]●

typedef [1]●

Uunaire [1]●

Vvecteur [1]●

virgule flottante [1]●

Wwhile [1]●

Données et Algorithmique - Index

http://www-ipst.u-strasbg.fr/pat/program/algofi.htm (6 of 6) [21-11-2001 17:43:08]

Page 93: algo

Données et Algorithmique - SommaireINTRODUCTION●

LES VARIABLES SCALAIRES

codage binaire❍

boucles❍

récursivité❍

LES TABLEAUX STATIQUES

tableaux unidimensionnels

généralités■

fonctions de base (fichier inclus base_tus)■

manipulations dans les tableaux (mani_tus)■

tris

généralités (valables également pour d'autres types de données)■

le tri bulle■

le tri par insertion■

le tri par sélection■

le tri shell■

le tri rapide (Quick Sort)■

le tri par création■

d'autres tris■

recherches

la recherche séquentielle■

la dichotomie■

calculs mathématiques

calcul vectoriel■

polynômes■

tableaux multidimensionnels❍

conclusions❍

LES TABLEAUX DYNAMIQUES●

Données et Algorithmique - Sommaire

http://www-ipst.u-strasbg.fr/pat/program/algofc.htm (1 of 3) [21-11-2001 17:43:13]

Page 94: algo

tableaux unidimensionnels en C❍

la méthode du super-tableau❍

les tableaux multidimensionnels

matrices pleines (matrices rectangulaires dynamiques : mrd)■

tableaux de tableaux dynamiques■

conclusions❍

LES LISTES

fonctions de base et manipulations (base_lst)❍

les tris

le tri bulle■

le tri par insertion■

le tri par sélection■

le tri par création■

les autres tris■

problèmes mathématiques❍

conclusions❍

LES PILES ET FILES

définition❍

fonctions de base❍

utilisations❍

LES ARBRES

introduction❍

expressions arithmétiques (arb_expr)❍

listes triées❍

les arbres généraux❍

LES GRAPHES●

LES FICHIERS

les fichiers séquentiels❍

les fichiers à accès direct❍

l'indexation❍

CORRECTION DES EXERCICES

BOUCLE❍

TUSEXO_A❍

Données et Algorithmique - Sommaire

http://www-ipst.u-strasbg.fr/pat/program/algofc.htm (2 of 3) [21-11-2001 17:43:13]

Page 95: algo

TUSEXO_B❍

GAUSS_MRD❍

INSE_TTD❍

recherche dans l'index de mon document sur le langage C●

Données et Algorithmique - Sommaire

http://www-ipst.u-strasbg.fr/pat/program/algofc.htm (3 of 3) [21-11-2001 17:43:13]

Page 96: algo

Langage C - SommaireIntroduction (première partie)

Organisation de l'ordinateur❍

Langages de programmation❍

Connaissances de base●

Fonctions d'entrées/sorties les plus utilisées●

La syntaxe du C

Second exemple, définitions❍

Variables / identificateurs / adresse / pointeurs❍

Expressions / opérateurs

Arithmétiques

unaires■

deuxaires■

Relationnels

comparaisons■

logique booléenne■

binaires■

Affectation

affectation simple =■

incrémentation / décrémentation■

affectation élargie■

Opérateurs d'adresses■

Autres

conditionnel ? :■

séquentiel ,■

Ordre de priorité et associativité■

Instructions❍

Structures de contrôle

Boucles■

Langage C - Sommaire

http://www-ipst.u-strasbg.fr/pat/program/tpcfc.htm (1 of 3) [21-11-2001 17:43:18]

Page 97: algo

While (tant que)■

Do While (faire tant que)■

For (pour)■

Branchements conditionnels

If - Else (Si - Sinon)■

Switch - Case (brancher - dans le cas)■

Branchements inconditionnels

Break (interrompre)■

Continue (continuer)■

Goto (aller à)■

Return (retourner)■

Exit (sortir)■

Déclaration et stockage des variables

Déclarations locales■

Déclarations globales■

Déclaration de type■

Fonctions

Définitions générales■

Récursivité, gestion de la pile■

Arguments passés par adresse■

La fonction main■

Fonction retournant un pointeur et pointeur de fonction■

Les types de données du C

Variables scalaires

char : caractère (8 bits)■

int : entier■

float : réel■

Tailles et plages■

Conversions de type / cast■

Enumérations■

Tableaux

Tableaux unidimensionnels■

Tableaux et pointeurs / arithmétique des pointeurs■

Langage C - Sommaire

http://www-ipst.u-strasbg.fr/pat/program/tpcfc.htm (2 of 3) [21-11-2001 17:43:18]

Page 98: algo

Chaînes de caractères■

Bibliothèques de fonctions pour tableaux et chaînes■

Allocation dynamique de mémoire■

Tableaux multidimensionnels■

Structures et unions

Déclaration■

Utilisation■

Champs de bits■

Unions■

Structures chaînées■

Les fichiers de données

Fichiers bruts❍

Fichiers bufférisés❍

Directives du pré-compilateur●

Utiliser Turbo C (3.5 par exemple)●

Correction des exercices●

Autres sites sur le C●

Langage C - Sommaire

http://www-ipst.u-strasbg.fr/pat/program/tpcfc.htm (3 of 3) [21-11-2001 17:43:18]

Page 99: algo

Langage C -Sommaire

Introduction (première partie)

Organisation de l'ordinateur❍

Langages deprogrammation

Connaissances de base●

Fonctions d'entrées/sorties les plusutilisées

La syntaxe du C

Second exemple,définitions

Variables / identificateurs /adresse / pointeurs

Expressions / opérateurs

Arithmétiques

unaires■

deuxaires■

Relationnels

comparaisons■

logiquebooléenne

binaires■

Affectation

affectationsimple =

incrémentation/décrémentation

affectation■

Langage CLe Langage C

Aujourd'hui, l'informatique est présente dans tous lesdomaines de la vie courante, mais à des degrés différents. Ily a pour cela trois grandes raisons :

- les gains (en temps, argent, qualité) que l'informatique peutapporter,

- le prix abordable des matériels,

- la disponibilité de logiciels dans tous les domaines.

Deux domaines sont pleinement exploités :

- les logiciels généraux, vendus en grande série, et doncrelativement bon marché,

- les logiciels spécifiques, d'un coût total important et donclimités à des sujets très pointus, pour de très grossesindustries.

Le domaine intermédiaire, qui peut encore se développer,concerne les programmes spécifiques, pour des applicationsde moindre importance. Pour cela, il est nécessaire dedisposer de langages de programmation. Les tableurs etbases de données par exemple disposent désormais devéritables langages de programmation (souvent orientésobjets) qui vont plus loin que les précédents langages demacro-commandes. Pour les autres cas, le C est souvent lemeilleur choix. En effet, c'est un langage structuré, avectoutes les possibilités des autres langages structurés. Mais ilpermet également (avec son extension C++) de gérer desobjets. A l'inverse, il permet également une programmationproche du langage machine, ce qui est nécessaire pouraccéder aux interfaces entre l'ordinateur et son extérieur.Mais son principal avantage est que ces trois types deprogrammation peuvent être combinés dans un mêmeprogramme, tout en restant portable sur tous les ordinateursexistants. Le langage C a néanmoins deux inconvénientsmajeurs, c'est d'être un peu plus complexe d'utilisation (maisuniquement du fait de ses nombreuses possibilités), et d'être

Langage C

http://www-ipst.u-strasbg.fr/pat/program/tpc.htm (1 of 4) [21-11-2001 17:43:29]

Page 100: algo

élargie

Opérateurs d'adresses■

Autres

conditionnel ?:

séquentiel ,■

Ordre de priorité etassociativité

Instructions❍

Structures de contrôle

Boucles

While (tantque)

Do While(faire tant que)

For (pour)■

Branchementsconditionnels

If - Else (Si -Sinon)

Switch - Case(brancher -dans le cas)

Branchementsinconditionnels

Break(interrompre)

Continue(continuer)

Goto (aller à)■

Return(retourner)

Exit (sortir)■

Déclaration et stockage desvariables

Déclarations locales■

séquentiel, ce qui ne lui permettra pas d'être le langageoptimal pour les machines massivement parallèles (maisaujourd'hui il n'existe pas encore de langage universel pource type de machines qui puisse combiner efficacement descalculs procéduraux et du déclaratif).

Ceci est la première partie du livre "Programmation en C,langage et algorithmes", qui est composé de trois parties.

* La première définit le langage C, avec de nombreuxexemples directement dans le texte, et certainssupplémentaires en annexe.

* La seconde partie traite des structures de données et desalgorithmes. Elle n'est pas spécifique, seuls les exemplessont en C, le texte et les algorithmes restent utilisables danstout langage séquentiel. Les fonctionnalités du C nondisponibles dans d'autres langages sont analysées, leméthodes utilisées pour parvenir au même résultat sontprécisées (par exemple, gestion d'un liste dynamique à l'aided'un tableau).

* La troisième partie quand à elle traite des algorithmesd'infographie. Elle est importante du fait de la nécessité dugraphisme dans les programmes. Mais elle détailleégalement, pour ces cas pratiques, les méthodes et moyensutilisés pour optimiser des algorithmes. Une bibliothèquegraphique est fournie en annexe.

* Les parties que j'ai prévues, mais pas encore rédigées :utilisation des objets C++, programmation graphiqueévennementielle (Microsoft Windows, X-Windows)

Introduction (première partie)●

Connaissances de base●

Fonctions d'entrées/sorties les plus utilisées●

La syntaxe du C●

Les fichiers de données●

Directives du pré-compilateur●

Utiliser Turbo C (3.5 par exemple)●

Correction des exercices●

Autres sites sur le C●

Sommaire●

Langage C

http://www-ipst.u-strasbg.fr/pat/program/tpc.htm (2 of 4) [21-11-2001 17:43:29]

Page 101: algo

Déclarations globales■

Déclaration de type■

Fonctions

Définitions générales■

Récursivité, gestionde la pile

Arguments passéspar adresse

La fonction main■

Fonction retournantun pointeur etpointeur de fonction

Les types de données du C

Variables scalaires

char : caractère(8 bits)

int : entier■

float : réel■

Tailles etplages

Conversionsde type / cast

Enumérations■

Tableaux

Tableauxunidimensionnels

Tableaux et pointeurs/ arithmétique despointeurs

Chaînes de caractères■

Bibliothèques defonctions pourtableaux et chaînes

Allocationdynamique demémoire

Langage C

http://www-ipst.u-strasbg.fr/pat/program/tpc.htm (3 of 4) [21-11-2001 17:43:29]

Page 102: algo

Tableauxmultidimensionnels

Structures et unions

Déclaration■

Utilisation■

Champs de bits■

Unions■

Structures chaînées■

Les fichiers de données

Fichiers bruts❍

Fichiers bufférisés❍

Directives du pré-compilateur●

Utiliser Turbo C (3.5 parexemple)

Correction des exercices●

Autres sites sur le C●

Langage C

http://www-ipst.u-strasbg.fr/pat/program/tpc.htm (4 of 4) [21-11-2001 17:43:29]

Page 103: algo

SommaireInfographie

JUSTIFICATION●

BIBLIOTHEQUEGRAPHIQUE DE BASE

tracés simples

matériel existant■

fonctionsélémentaires

représentation d'une droite(en mode point ou surtable traçante)

autres courbes

par tâtonnements■

approximation parla tangente

formulationparamétrique

remplissages / hachurages

remplissage d'unefrontière déjà tracée

frontière totalementdéfinie

les échelles

fenêtre objet etfenêtre papier

clipping■

intersections

droite - droite■

droite - cercle /cercle - cercle

contraintes❍

Conclusion❍

Infographie

JUSTIFICATION●

BIBLIOTHEQUE GRAPHIQUE DE BASE●

TRANSFORMATIONS MATRICIELLES●

PROJECTIONS 3D●

ELIMINATION LIGNES / SURFACES CACHEES●

COURBES ET SURFACES●

ANNEXE : DOCUMENTATION DE LA BIBLIOTHEQUEGRAPHIQUE

télécharger la disquette d'accompagnement●

Sommaire détaillé●

Vous trouverez ici un cours sur l'infographie (c'est à dire, ici, lesalgorithmes pour faire du graphique). On débute par les tracés lesplus simples (le pixel, la ligne) pour les matériels de base, on passeaux cas plus complesxes, progressivement pour aborder le 3D, lessurfaces complexes... Les algorithmes sont expliqués en clair, lesexemples pratiques sont en C. Une bibliothèque graphique (en C) estaccessible en téléchargement (gratuit).

Autres liens : Paul Bourke (en anglais)

Infographie

http://www-ipst.u-strasbg.fr/pat/program/infogr.htm (1 of 5) [21-11-2001 17:43:40]

Page 104: algo

TRANSFORMATIONSMATRICIELLES

représentation defonctions planes parmatrices 2x2

matrices 3x3(coordonnées homogènes2D)

transformations 3D❍

PROJECTIONS 3D

parallèle❍

perspective

méthodes

méthodevectorielle :

méthodematricielle :

clipping■

points particuliers■

ELIMINATION LIGNES /SURFACES CACHEES

lignes cachées❍

faces cachées

surfaces orientées■

algorithme dupeintre

calculs de facettes■

élimination desarrêtes cachées

tubes de projection■

plans de balayage■

rayons deprojection

éclairage desurfaces

problème des surfacesgauches

COURBES ET SURFACES●

Infographie

http://www-ipst.u-strasbg.fr/pat/program/infogr.htm (2 of 5) [21-11-2001 17:43:40]

Page 105: algo

introduction❍

courbes

représentation despoints

polynômes deLagrange

splines■

courbes de Bezier

conditions■

déterminationdespolynômesde Bezier

formepolynomiale

intérêt■

exemples■

surfaces

Coons■

surfaces de Bezier■

ANNEXE :DOCUMENTATION DE LABIBLIOTHEQUEGRAPHIQUE

G2D Librairie graphiquede base en C

Préliminaire■

Passage en modegraphique

Les fenêtres■

Les échelles■

Attributs de tracé■

Tracés de base■

Table traçante■

Autresbibliothèques

Exemple :■

bibliothèque GECR❍

Infographie

http://www-ipst.u-strasbg.fr/pat/program/infogr.htm (3 of 5) [21-11-2001 17:43:40]

Page 106: algo

remplissage - hachuragede polygones (GPOLY)

remplissage suivantl'écran (GREMPL)

bibliothèque GPLUS❍

bibliothèquetridimensionnelle

G3D■

précisions sur lemode G34VUES

G3ECR■

G3POLY■

Vecteurs■

OBJets à lier àvotre EXEcutable

EXEMPLE G3D■

SOURIS : utilisation de lasouris sous G2D

types utilisés■

fonctions d'usagecourant

forme du curseur■

fonctions de basniveau

exemple■

Bibliothèque MENUG

Descriptif général■

Descriptiondétaillée

Détailspratiques

Menus■

lectures(clavier ousouris)

référence

Constanteprédéfinie

Infographie

http://www-ipst.u-strasbg.fr/pat/program/infogr.htm (4 of 5) [21-11-2001 17:43:40]

Page 107: algo

Variableglobaleprédéfinie

Typesprédéfinis

Gestion dumode MENU

Fonctionsprincipales

Ecrituresdans lafenêtre menu

Lectures(clavier ousouris)

Ecrire dans lafenetre degauche (58caractères, 25lignes)

Exemple complet■

télécharger ladisquetted'accompagement

Infographie

http://www-ipst.u-strasbg.fr/pat/program/infogr.htm (5 of 5) [21-11-2001 17:43:40]

Page 108: algo

télécharger la Disquetted'accompagnement - P. TRAU

CONTENU DE LA DISQUETTE D'ACCOMPAGNEMENT

correction des exercices de la première partie❍

exemples pour la première partie❍

correction des exercices de la seconde partie❍

exemples pour la seconde partie❍

exemples pour la troisième partie❍

Bibliothèque graphique❍

TELECHARGER CES DOCUMENTS●

sommaire documents programmation

CONTENU DE LA DISQUETTED'ACCOMPAGNEMENTCedocument contient la liste des fichiers disponibles sur la disquette d'accompagnement.

Ils sont regroupés par répertoires

correction des exercices de la première partienoms des fichiers (répertoire exercices.c). Le listing complet est donné en annexe 1.

1 while_puiss WH_PUISS.C2 while_err WH_ERR.C3 do_while DO_WHILE.C4 for FOR.C5 jeu JEU.C6 calcul CALCUL.C7 moyenne MOYENNE.C8 rotation ROTATION.C9 classer CLASSER.C

Disquette d'accompagnement - P. TRAU

http://www-ipst.u-strasbg.fr/pat/program/disk-acc.htm (1 of 6) [21-11-2001 17:43:49]

Page 109: algo

10 chaîne CHAINES.C11 matrices MATRICES.C12 determinant DETERMIN.C13 tel TEL.C14 liste & insertion LISTE_CH.C15 agenda AGENDA.C

exemples pour la première partieL'intérêt de ces fichiers est qu'il contiennent la fonction décrite en exemple mais aussi une fonction mainqui l'utilise, ainsi que quelques exemples supplémentaires. (répertoire exemples.c)

PREM_EX.C premier petit programme du chapitre 2SECONDEX.C programme du chapitre 4.1WHILE.C exemple de boucle whileWH_ERR.C source du programme "while_err" dont on doit expliquer la fonctionFACTORIE.C calcul de factorielle par boucle for et par récursivitéFONCT_PT.C exemple de fonction retournant un pointeurENUM.C utilisation des énumérationsTABLO_PT équivalence d'écriture entre tableau et pointeur

MULTIDIM.Cquatre méthodes différentes pour stocker un tableau multidimensionnel en mémoire(matrice statique, tableau unidimensionnel, tableau de lignes, pointeurs de pointeurs)

ARG_MAIN.Carguments de la fonction main (un programme à mettre dans AUTOEXEC.BAT pourinitialiser les couleurs de l'écran)

FIC_BRUT.C utilisation de fichiers bruts (accès par blocs de taille constante)

correction des exercices de la seconde partieLe listing est donné en annexe 2 (répertoire exercices.a)

BOUCLE.C exercice du paragraphe 9.2TUSEXO_A.C exercice du paragraphe 10.1.2TUSEXO_B.C exercice du paragraphe 10.1.3

GAUS_MRD.Cexercice du paragraphe 11.3.1. Il montre une application des matrices rectangulairesdynamiques.

INSE_TTD.Cexercice du paragraphe 11.3.2. C'est également un exemple d'utilisation d'un stockagedynamique pour une grande matrice.

Disquette d'accompagnement - P. TRAU

http://www-ipst.u-strasbg.fr/pat/program/disk-acc.htm (2 of 6) [21-11-2001 17:43:49]

Page 110: algo

exemples pour la seconde partieexemples donnés dans le document. En particulier les fichiers inclus contenant les manipulations de basesur les types de données sont regroupés (.INC). Les différentes fonctions données dans le document (trispar exemple) sont accompagnés d'une fonction main permettant de les utiliser directement. Certainsexemples supplémentaires présents sur la disquette ne sont pas listés dans le document par manque deplace (répertoire exemples.a)

FLOTTANT.C exemple du paragraphe 9.1BOUCLE_A.C, BOUCLE_B.C exemples du paragraphe 9.2

BASE_TUS.INCfonctions de base pour les tableaux unidimensionnels statiques(paragraphe 10.1.2)

EX_TUS.C exemple du paragraphe 10.1.2

MANI_TUS.INCfonctions de manipulation des tableaux unidimensionnels statiques(paragraphe 10.1.3)

BULL_TUS.Cimplantation d'un tri bulle pour les tableaux unidimensionnels statiques(paragraphe 10.1.4.2)

INSE_TUS.Cimplantation d'un tri par insertion pour les tableaux unidimensionnelsstatiques (paragraphe 10.1.4.3). Les deux implantations (simple etoptimisée) sont prévues.

SELE_TUS.Cimplantation d'un tri par sélection pour les tableaux unidimensionnelsstatiques (paragraphe 10.1.4.4)

SHEL_TUS.Cimplantation d'un tri shell pour les tableaux unidimensionnels statiques(paragraphe 10.1.4.5)

QUIC_TUS.Cimplantation d'un tri rapide (Quick Sort) pour les tableauxunidimensionnels statiques (paragraphe 10.1.4.6)

CREA_TUS.Cimplantation d'un tri par création pour les tableaux unidimensionnelsstatiques (paragraphe 10.1.4.7)

BASE_MAT.INCfonctions de base pour la gestion des matrices statiques (paragraphe10.2)

GAUSS.Crésolution matricielle de AX=B avec triangulation simpliste ouaméliorée (paragraphe 10.2)

BASE_LST.INC fonctions de base sur les listes chaînées (paragraphe 12.1)TEST_LST.C test des fonctions de listes chaînées (paragraphe 12.1)BULL_LST.C implantation d'un tri bulle dans une liste chaînée (paragraphe 12.2.1)INSE_LST.C implantation d'un tri insertion dans une liste chaînée (paragraphe 12.2.2)

SELE_LST.Cimplantation d'un tri par sélection dans une liste chaînée (paragraphe12.2.3)

BASE_P_T.INCfonctions de base pour l'implantation de piles par tableaux statiques(paragraphe 13.2).

BASE_P_L.INCfonctions de base pour l'implantation de piles par listes chaînées(paragraphe 13.2).

Disquette d'accompagnement - P. TRAU

http://www-ipst.u-strasbg.fr/pat/program/disk-acc.htm (3 of 6) [21-11-2001 17:43:49]

Page 111: algo

BASE_F_T.INCfonctions de base pour l'implantation de files par tableaux statiques(paragraphe 13.2).

POLONAIS.Cexemple de mise en oeuvre d'une pile pour évaluer une expression ennotation polonaise (paragraphe 13.3)

ARB_EXPR.Creprésentation d'une expression mathématique sous forme d'un arbre(paragraphe 14.2)

ARB_NOMS.C gestion d'une liste de noms à l'aide d'un arbre binaire (paragraphe 14.3)

exemples pour la troisième partierépertoire exemples.g :

BIB_BASE.INC une bibliothèque de base sous TURBO C++ (initialisation, allumer un point)G_LIGNE.INC mise en oeuvre d'un tracé de droite quelconque en n'utilisant que BIB_BASE

CERCLES.Ctest du tracé d'arc de cercle par la méthode de la dérivée, comparaison avec la méthodeparamétrique (sinus, cosinus)

REMPLIR.Cremplissage d'une courbe fermée par un algorithme récursif. On voit (car c'est lent)l'ordre des appels récursifs par un remplissage qui semble désordonné

CRETE.Cexemple de tracé de surface avec élimination de lignes cachées par la méthode de laligne de crête (nécessite la bibliothèque graphique G2D)

PARALLEL.C projection parallèle : vue d'un cube dans toutes les positions

LAGRANGE.Cprogramme permettant de tester l'interpolation de Lagrange (nécessite G2D et unesouris compatible).

BEZIER.C programme de tracé de courbes de Bezier

Bibliothèque graphiquerépertoire bib_graph :

Fichiers inclus :

Vous devez inclure les fichiers dont vous avez besoin dans votre fichier source. Il est inutile d'inclure lesfichiers qui ne vous servent pas directement.

G2D.H Bibliothèque graphique de base

CHAR.HDéfinition du type CARACT qui définit un caractère. Ceci est nécessaire car en TURBOC les caractères sont définis autrement que par un char (unsigned char). Si vous utilisezun autre compilateur il suffit de modifier ce fichier.

CHAINES.H Fonctions de base traitement de caractèresVECTEURS.H onctions de base de traitement de vecteurs (produit scalaire, vectoriel...) utilisé par G3D.GECR.H Fonctions d'écritureGPOLY.H Tracé, remplissage et hachurage de polygones fermésGREMPL.H Remplissage d'une courbe déjà tracée à l'écran

Disquette d'accompagnement - P. TRAU

http://www-ipst.u-strasbg.fr/pat/program/disk-acc.htm (4 of 6) [21-11-2001 17:43:49]

Page 112: algo

GPLUS.H Quelques fonctions supplémentaires à G2DG3D.H Bibliothèque de base 3DG3ECR.H Ecritures (2D) mais débutant en un point défini en 3D

G3POLY.HTracé, remplissage et hachurage de polygones définis en 3D. Attention, le remplissagese fait sur la projection du polygone, donc peut poser des problèmes si la surface est"trop gauche".

SOURIS.H Utilisation d'une souris pour entrer des coordonnées 2D à votre échelle.MENUG.H Fonctions de menus

Fichiers sources à compiler et lier à vos programmes objets. Il faut lier les fichiers dont vous vous servezexplicitement mais également indirectement (par exemple si vous avez inclus dans votre programmeG3ECR.H, il faut lier votre programme à G3ECR.C mais aussi à GECR.C puisqu'il utilise ce dernier (parcontre il était inutile d'inclure GECR.H dans votre programme si vous ne vous en servez pasdirectement).

G2D.C Bibliothèque graphique de baseCHAINES.C Fonctions de base traitement de caractères

VECTEURS.CFonctions de base de traitement de vecteurs (produit scalaire, vectoriel...) utilisé parG3D.

GECR_STD.C

Fonctions d'écriture. Implantation standard : tous les graphismes des 255 caractères d'unPC y sont définis, un caractère sera donc dessiné à l'aide d'un ensemble de segments.Ceci prend pas mal de place en mémoire et est assez lent mais marchera partout (si lacouche 0 de G2D est bien définie).

GECR_ECR.C

Fonctions d'écriture. Implantation spécifique au TURBO C : On utilise les fonctionsexistantes sur le PC pour écrire. Ceci prend moins de place et va plus vite, mais on nepeut pas modifier la taille des caractères, ni leur inclinaison, ni faire d'écritures sur unetable traçante. Si vous avez inclus GECR.H dans votre programme, il faudra soit lui lierGECR_ECR.C, soit GECR_STD.C.

GPOLY.C Tracé, remplissage et hachurage de polygones fermésGREMPL.C Remplissage d'une courbe déjà tracée à l'écranGPLUS.C Quelques fonctions supplémentaires à G2DG3D.C Bibliothèque de base 3D

G3ECR.CEcritures (2D) mais débutant en un point défini en 3D. Utilise les écritures en 2D, doncGECR_ECR ou GECR_STD.

G3POLY.CTracé, remplissage et hachurage de polygones définis en 3D. Attention, le remplissage sefait sur la projection du polygone, donc peut poser des problèmes si la surface est "tropgauche".

SOURIS.C Utilisation d'une souris pour entrer des coordonnées 2D à votre échelle.

MENUG.CFonctions de menus. Ceci est donné en exemple, cette bibliothèque mérite d'êtrecomplètement modifiée (en particulier en utilisation Windows)

Exemples de programmes utilisant les différentes bibliothèques :

TST2D.C test de pratiquement toutes les fonctions de G2D

Disquette d'accompagnement - P. TRAU

http://www-ipst.u-strasbg.fr/pat/program/disk-acc.htm (5 of 6) [21-11-2001 17:43:49]

Page 113: algo

TSTECR.CDémonstration des possibilités d'écriture. On pourra comparer les résultats obtenus enliant GECR_STD (plus de possibilités mais lent) ou GECR_ECR (rapide mais limité)

TSTPOLY.C Démonstration de remplissage / hachurage de polygones convexes ou nonTSTREMPL.C Test des fonctions de remplissage (frontière tracée auparavant)TST3D.C Fonctions 3D : On peut regarder un cube sous toutes ses facesTST3POLY.C Démonstration de polygones 3DTSTSOURI.C Utilisation des fonctions de base utilisant la sourisTSTMENU.C Démonstration de quelques possibilités de la bibliothèque de menus

TELECHARGER CES DOCUMENTSc'est facile, il suffit de cliquer ici (transfert par FTP, le fichier est compressé en .ZIP).

Vous pouvez également télécherger de la même manière la bibliothèque graphique en PASCAL (sources,documentation et programmes d'exemples). Cette version est un peu plus ancienne que celle en C, maisreste presque similaire (mêmes noms de procédures et fonctions, mêmes arguments)

P. TRAU, ULP-IPST, 20/3/97

sommaire documents programmation

Disquette d'accompagnement - P. TRAU

http://www-ipst.u-strasbg.fr/pat/program/disk-acc.htm (6 of 6) [21-11-2001 17:43:49]

Page 114: algo

P. Trau ULP-IPST 24/2/97

Introduction au C++On trouvera un document complet sur www.mis.enac.fr/~dancel ou www.mygale.org/~dancel

Si la couleur de ce document ne vous plait pas, cliquez ici.

Table des matières  1) INTRODUCTION

a) qu'est-ce qu'un objet ?❍

b) pourquoi un L.O.O. ?❍

c) avantages - inconvénients ?❍

d) Pourquoi C++ ?❍

 2) PREMIÈRES SPÉCIFICITÉS C++

a) commentaires❍

b) entrées-sorties (flux)❍

c) mot clef const❍

d) passage d'arguments par adresse❍

e) arguments par défaut❍

f) résolution de portée❍

 3) VOCABULAIRE

a) la classe❍

b) l'instance❍

c) l'héritage❍

d) la surcharge❍

e) le constructeur❍

 4)APPLICATIONS

a)simple❍

b) accès aux membres d'une classe❍

c) héritage❍

d) new, delete❍

e) surcharge d'un opérateur❍

f) classes virtuelles❍

g) polymorphisme❍

 5) EXEMPLE COMPLET (COMMENTÉ)

Introduction C++ - P. Trau

http://www-ipst.u-strasbg.fr/pat/program/cpp.htm (1 of 11) [21-11-2001 17:44:08]

Page 115: algo

le C++

Introduction pour qui connaît le CCette page n'est pas destinée au débutant. Je suppose que le lecteur connait bien le C standard (ANSI). Sinon, vous pouvezd'abord voir mon cours C complet. Pour un problème précis, allez directement à son index.

1) INTRODUCTIONLe C++ est LA solution pour passer aux L.O.O. (langages orientés objet) sans trop de problèmes.

a) qu'est-ce qu'un objet ?une STRUCTure regroupant des données et les fonctions pour les manipuler.

b) pourquoi un L.O.O. ?Le passage de l'assembleur aux langages structurés a permis d'obtenir des programmes maintenables : on peut lescomprendre, les modifier, les améliorer : on a une structure de programme claire. Par contre si l'on décide de modifier lastructure des données importantes (par exemple remplacer le tableau des données par une liste chaînée), il fallait réécriretout le programme. Les objets structurent les données : en changeant la structure d'un objet, il suffit de modifier ses"méthodes" pour que la transformation s'applique à tout le programme. La programmation est plus simple, les méthodes(fonctions en C) sont classées par types de données plutôt que séquentiellement. De plus elles sont organiséeshiérarchiquement (arborescence=bidimensionnel plutôt que séquentiel=linéaire).

c) avantages - inconvénients ?Programmes plus faciles à écrire et à maintenir. Modification aisée, y compris des types de données. Modularitéaccrue (un objet bien défini reservira dans de nombreux programmes)

Programme résultant (exécutable) un peu moins efficace (plus gros et moins rapide, mais aujourd'hui le prix de lavitesse et de la mémoire est inférieur au coût d'une optimisation de programme, on n'écrit plus grand chose enassembleur).

d) Pourquoi C++ ?C++ est sûrement un mauvais L.O.O. (du point de vue de l'informaticien puriste), par contre il permet de garder tous lesavantages du C : portable, possibilité d'utiliser différents niveaux d'optimisation au sein d'un même programme (objets -langage structuré classique - assembleur). Il permet de passer en douceur aux objets, mais surtout de garder et réutilisertoutes les bibliothèques existantes. Bien que plus strict que C, il acceptera à peu près tout, donc sera avare en messagesd'erreur de compilation. C'est le programmeur qui doit se forcer à programmer "objets", s'il ne le fait pas le compilateur nele prévient même pas. Comme vous le verrez ici, le passage aux objets (si l'on connaît déjà C) est très simple.

Introduction C++ - P. Trau

http://www-ipst.u-strasbg.fr/pat/program/cpp.htm (2 of 11) [21-11-2001 17:44:08]

Page 116: algo

2) PREMIERES SPECIFICITES C++

a) commentairesLes commentaires /* ... */ restent possibles, on y a ajouté les commentaires commençant par // et se finissant à la fin de laligne.

b) entrées-sorties (flux)à condition d'inclure <iostream.h> (et donc pas <stdio.h>), on peut utiliser cout (pour afficher à l'écran) et cin (pour liresur le clavier). Exemple :

float P; int Nb;cout << "prix unitaire ? ";cin >> P;cout << "Nombre ? ";cin >> Nb;cout.precision(2); //manipulateur (fonction membre)de cout : tous les //flottants QUI SUIVENT seront affichés avec // 2 chiffres après la virgulecout << "prix total : " << P*Nb << "F \n";

L'avantage de ces fonctions est qu'elles peuvent être plus facilement surchargées que printf et scanf (par exemple étenduesaux tableaux). Les flux fstream possèdent les mêmes fonctionnalités pour les fichiers (je ne détaille pas).

c) mot clef const const type var=valeur;

contrairement au #define, permet une analyse syntaxique (on garde les define pour les "réécritures" et compilationsconditionnelles).

d) passage d'arguments par adresseil suffit d'ajouter le signe & dans l'entête de la fonction (qui doit être prototypée avant toute utilisation). Ceci évitel'écriture "pointeur" tant pour les arguments réels que formels :

void echange(int &a, int &b) {int z=a;a=b;b=z;}int X,Y;echange(X,Y);

e) arguments par défautOn peut déclarer des valeurs par défaut des arguments d'une fonction (uniquement dans le prototype, pas dans l'entête).Les arguments réels peuvent être omis en commençant par le dernier (impossible d'omettre les premiers si l'on veutpréciser un suivant).

f) résolution de portéeSi vous disposez de deux (ou plus) entités (donnée ou méthode) de même nom, en C standard seule la plus locale estaccessible. ou::nom permet en C++ de préciser de quel nom on parle (en général ou correspond à une classe, ::nom

Introduction C++ - P. Trau

http://www-ipst.u-strasbg.fr/pat/program/cpp.htm (3 of 11) [21-11-2001 17:44:08]

Page 117: algo

pour accéder à une variable globale).

3) VOCABULAIRE

a) la classeUne classe est un regroupement de données et de méthodes. C'est donc une extension des STRUCT du C :

class MaClasse {déclaration données et méthodes } MonInstance;

Ne pas oublier le ; final même quand on ne déclare pas d'instance ici (en général les classes sont globales, les variablesdevraient plutôt être locales). En fait les mots clef struct et union permettent également la déclaration de méthodes en plusde données, simplement elles sont par défaut publiques (public) (accessibles aux autres classes) alors que pour une classeelles sont par défaut privées (private).

b) l'instanceOn utilisera le terme "instanciation" à chaque création d'une instance (ce qu'on appelait avant une variable). L'adresse del'instance actuelle est appelée "this" (sans avoir à la déclarer).

c) l'héritageles classes sont structurées de manière arborescente. Si l'on crée une classe d'objets A (dite classe de base), on peut créerune classe B qui "dérive" de A : elle en hérite toutes les composantes (données et méthodes). On peut, à partir de C++version 2, utiliser l'héritage multiple (une classe hérite de plusieurs classes de base), alors que ce n'était pas possible avant.

d) la surchargeOn peut décrire plusieurs méthodes de même nom, à condition que chacune s'applique à des types de données différents.Par exemple on peut définir int puissance(int,int) et float puissance(float,float), les deuxfonctions ayant une implémentation différente suivant le type de données, c'est le compilateur qui choisira en fonction destypes des arguments. On peut même surcharger les opérateurs classiques du C (redéfinir + pour les vecteurs par exemple).On ne peut pas surcharger deux fonctions ayant exactement les mêmes types d'arguments mais retournant un type différent(produits scalaire et vectoriel par exemple)

e) le constructeurPour chaque classe, il existe une méthode nécessaire (mais non obligatoire, si on ne la définit pas le compilateur en créeune par défaut) : le constructeur. Son nom est toujours le même que celui de la classe. Il est appelé implicitement à chaquenouvelle création d'instance ou explicitement par la fonction new (correspond au malloc, mais c'est le compilateur quidétermine la taille nécessaire). Le constructeur est une fonction qui ne retourne rien (même pas void). Le destructeur estappelé implicitement à la destruction d'un objet ou explicitement par delete. Remarque : le constructeur peut affecter unevaleur à un membre constant (mais qui ne pourra pas changer jusqu'à sa destruction).

Introduction C++ - P. Trau

http://www-ipst.u-strasbg.fr/pat/program/cpp.htm (4 of 11) [21-11-2001 17:44:08]

Page 118: algo

4)APPLICATIONS

a)simpleclass Point { int X;intY; //les données int GetX(void) {return X;} // déclaration "interne" ou "inline" int GetY(void); // déclaration externe Point (int NewX=0, int NewY=0) {X=NewX;Y=NewY;} //déclaration //interne du constructeur, avec initialisation par défaut };int Point::GetY(void) {return Y;} //déclaration "externe", il faut préciser //à quelle classe elle se rapporte ici POINT. //dans la réalité j'aurai plutot utilisé une déclaration interne

si je déclare :

Point P(5,10); //appel automatique du constructeur à ladéclaration int coordX;

je peux par exemple appeler la fonction (attention, pas n'importe où, voir paragraphe suivant) :

coordX=P.GetX();

b) accès aux membres d'une classeles membres d'une classe peuvent être

privés (private), c'est à dire accessible uniquement aux autres membres de cette classe;●

protégés (protected), c'est à dire accessibles au membres de la classe et des classes dérivées;●

publics (public), c'est à dire accessibles "classiquement" : même portée qu'une déclaration classique C●

Exemple :

class Point { int X;intY; //privé par défaut public : // tout ce qui suit est public int GetX(void) {return X;} // ceci permet d'accéder aux //infos sans savoir comment elles ont été stockées int GetY(void) {return Y;} Point (int NewX, int NewY) {X=NewX;Y=NewY;} };

On peut utiliser les 3 accès, autant de fois que l'on veut et dans n'importe que ordre. L'accès qui s'applique est le dernierspécifié (ou celui par défaut, private pour class et public pour struct).

c) héritageclass Point { protected: //accessible uniquement par héritage

Introduction C++ - P. Trau

http://www-ipst.u-strasbg.fr/pat/program/cpp.htm (5 of 11) [21-11-2001 17:44:08]

Page 119: algo

int X;intY; public : // accessible partout int GetX(void) {return X;} int GetY(void) {return Y;} Point (int NewX=0, intNewY=0) {X=NewX;Y=NewY;} };class Pixel : public Point //dérive de point, { protected: int couleur; public : Pixel (int nx,int ny,int coul=0); void allume(void); void allume(int couleur); //surcharge : on peut allumer avec une autre couleur void eteind(void); };

Les accès dérivés sont le plus restrictif entre celui défini dans la classe de base et celui précisé lors de la dérivation (icidérivation publique, les accès restent inchangés sauf pour les privés qui sont inaccessibles).

Pixel::Pixel(int nx,int ny,int coul):Point(nx,ny) // je précise la //liste (séparée par des virgules) des constructeurs //(sinon val par défaut), je n'ai plus qu'à construire les //ajouts par rapport à la classe de base {couleur=coul;}void Pixel::allume(void) {g_pixel(X,Y,couleur);} //g_pixel : une fonction qui allume un pixel à l'écranvoid Pixel::allume(int coul) {g_pixel(X,Y,couleur=coul);}void Pixel::eteind(void) {allume(0);}

On pourrait maintenant définir une classe segment contenant un pixel et un point (la couleur n'a besoin d'être stockéequ'une fois). On redéfinirait des méthodes de même nom : Segment::allume...

d) new, delete Pixel *ptrPixel = new Pixel(100,100,1); // construction explicite ptrPixel->allume(); //utilisation delete ptrPixel; //destruction, le destructeur par défaut est souvent suffisant

Si l'on veut définir explicitement le destructeur d'une classe (pour fermer un fichier par exemple), on utilise le nom de laclasse précédé de ~ :

Point::~Point() {...}

e) surcharge d'un opérateurutilisons le signe + pour additionner deux Points (par adresse pour éviter de recopier en local):

Point operator+ (Point &P1, Point &P2) { Point res(P1.GetX()+P2.GetX(),P1.GetY()+P2.GetY(),P1); return res;}

On peut aussi surcharger << (pour cout) :

Introduction C++ - P. Trau

http://www-ipst.u-strasbg.fr/pat/program/cpp.htm (6 of 11) [21-11-2001 17:44:08]

Page 120: algo

ostream& operator << (ostream& flux, Point& P) { flux << "[" << P.GetX() << "," << P.GetY() << "]"; return flux; }

Ces deux surcharges sont globales. Mais on peut également les définir comme fonctions membres :

class Point { ..... Point operator + (Point &P); Point operator = (Point &P);};Point::Point::operator + (Point & P) {Point r;r.X=this->X+P.X;r.Y=this->Y+P.Y;return r;}void main(void) { Point A,B,C; A=B; //appelle A.operator=(B) B+C; //appelle A.operator+(B) A=B+C; //marchera aussi, mais A=B=C je n'en suis pas sur }

f) classes virtuellesSoient : une classe A, deux classes B et C dérivant de A, une classe D dérivant de B et C. Nous aurons dans D deuxinstances de A (qui peuvent être différentes). Mais si une seule instance de A suffisait, il suffit de les déclarer :

class A {...};class B : virtual public A {...};class C : virtual public A {...};class D : public C, public D {...};

Le constructeur de D appellera une seule fois celui de A

g) polymorphismeSi plusieurs classes (point, ligne, segment) possèdent des méthodes de même signature (écriture similaire du prototype),on peut éviter de réécrire des fonctions dont le contenu serait identique mais d'appliquant à des objets différents(déplacer=éteindre+ajouter+allumer pout tous mes objets). On peut pour cela utiliser les fonctions virtuelles (dynamiques :le choix de la fonction a utiliser est déterminée à l'exécution) ou les fonctions templates (statiques : le choix des fonctionsest fait à la compilation). Voyez l'exemple complet.

5) EXEMPLE COMPLET (commenté)#include <iostream.h>#include "graphiq0.cpp" // petite biblio graphique. contient g_init, // g_fin, g_pixel, g_ligne (voir plus loin)

class Point { protected: //accessible uniquement par héritage int X;int Y; public : // accessible partout int GetX(void) {return X;} //hors héritage on ne peut que lire,

Introduction C++ - P. Trau

http://www-ipst.u-strasbg.fr/pat/program/cpp.htm (7 of 11) [21-11-2001 17:44:08]

Page 121: algo

//pas écrire int GetY(void) {return Y;} Point (int NewX=0, int NewY=0) {X=NewX;Y=NewY;} };

//On peut surcharger << (pour cout) : marche pour le point et ses héritiers :ostream& operator << (ostream& flux, Point& P) { flux << "[" << P.GetX() << "," << P.GetY() << "]"; return flux; }

class Pixel : public Point //dérive de point { protected: int couleur; public : Pixel (int nx=0,int ny=0,int coul=0); virtual void allume(void); virtual void allume(int couleur); //surcharge : on peut allumer avec une autrecouleur void eteind(void); // héritable dynamiquement void ajoute(int plusx=1,int plusy=1); void deplace(int plusx=1,int plusy=1);// héritable dynamiquement int GetCouleur(void); };

Pixel::Pixel(int nx,int ny,int coul):Point(nx,ny) //je passe ainsi les // arguments au constructeur de Point (sinon il prend // celui par défaut, cad sans arguments {couleur=coul;}void Pixel::allume(void) {g_pixel(X,Y,couleur);}void Pixel::allume(int coul) {g_pixel(X,Y,couleur=coul);}void Pixel::eteind(void) {allume(0);} //allume est virtuelle, toute classe dérivée //possédant allume possèdera automatiquement éteintvoid Pixel::ajoute(int plusx,int plusy) {X+=plusx;Y+=plusy;}void Pixel::deplace(int plusx,int plusy) { int OldCol=couleur;eteind();couleur=OldCol; ajoute(plusx,plusy);allume();}int Pixel::GetCouleur(void) {return couleur;}

class Segment : public Pixel { protected : int LX;int LY; public : Segment (int x0=0,int y0=0,int lx=0,int ly=0,int coul=1); void allume(void); void allume(int couleur);

Introduction C++ - P. Trau

http://www-ipst.u-strasbg.fr/pat/program/cpp.htm (8 of 11) [21-11-2001 17:44:08]

Page 122: algo

//le reste est hérité };

Segment::Segment(int x0,int y0,int lx,int ly,int coul):Pixel(x0,y0,coul) {LX=lx;LY=ly;}void Segment::allume(void) {g_ligne(X,Y,X+LX,Y+LY,couleur);}void Segment::allume(int coul) {g_ligne(X,Y,X+LX,Y+LY,couleur=coul);}

class Rectangle : public Pixel { protected : int LX;int LY; public : Rectangle (int x0=0,int y0=0,int lx=0,int ly=0,int coul=1); void allume(void); void allume(int couleur); };

Rectangle::Rectangle(int x0,int y0,int lx,int ly,int coul):Pixel(x0,y0,coul) {LX=lx;LY=ly;}void Rectangle::allume(void) { g_ligne(X,Y,X+LX,Y,couleur); g_ligne(X+LX,Y,X+LX,Y+LY,couleur); g_ligne(X+LX,Y+LY,X,Y+LY,couleur); g_ligne(X,Y+LY,X,Y,couleur); }void Rectangle::allume(int coul) {couleur=coul;this->allume();}

//utilisons le signe + pour additionner deux objets quels qu'ils soient:template <class T> //T est un type de classe "variable"T operator+ (T &P1,Point &P2) {T res(P1.GetX()+P2.GetX(),P1.GetY()+P2.GetY(),P1);return res;}// ce qui ne marche pas pour les types autres que point : le constructeur// prend les autres arguments par défaut (longueur, couleur)

void main(void) { g_init(); Pixel *ptrPixel = new Pixel(100,100,1); ptrPixel->allume(); //utilisation cout << *ptrPixel << ':' << ptrPixel->GetCouleur()<< '\n'; delete ptrPixel; //destruction, le destructeur par défaut est souvent suffisant Segment s(50,50,100,0,10); s.allume(); Rectangle r(150,150,100,100,4); r.allume(); cin.get(); //équivalent du getch Point decal(-25,25); cout << (s+decal) << endl;

Introduction C++ - P. Trau

http://www-ipst.u-strasbg.fr/pat/program/cpp.htm (9 of 11) [21-11-2001 17:44:08]

Page 123: algo

(r+decal).allume(); s.deplace(0,100); r.deplace(0,100); cout << r << endl; //endl envoie un \n cin.get(); g_fin(); }

----------- La bibliothèque graphique pour Tubo C (DOS) - Graphiq0.cpp -----------

/* fichier inclus pour INTRO.CPP, version Turbo C 3.0 P.Trau 22/2/97 */

/* bibliothèque graphique minimale . Ce fichier contient les fonctions qu'il faudra réécrire si l'on change de compilateur. Il faut savoir : - passer en mode graphique : g_init (sauf si vous y êtes déjà) - quitter le mode graphique : g_fin - allumer un point : g_pixel - à la rigueur tracer une ligne : g_ligne (ou le laisser tel quel, il n'utilise que g_pixel)*/

#include <graphics.h>

#define abs(X) ((X>0)?(X):(-(X)))

void g_init(void) { int gdriver = DETECT, gmode, errorcode; initgraph(&gdriver, &gmode, ""); errorcode = graphresult(); if (errorcode != grOk)#ifdef __cplusplus cout << "g_erreur: " << grapherrormsg(errorcode) <<"\n";#else printf("g_erreur: %s\n", grapherrormsg(errorcode));#endif setcolor(getmaxcolor()); }

void g_fin(void) {closegraph();}

void g_pixel(int x,int y,int color) {putpixel(x,y,color);}

void g_ligne(int xd,int yd,int xf,int yf,int color) { int somme,pasx,pasy,deltax,deltay; deltax=abs(xf-xd);deltay=abs(yf-yd); pasx=(xd<xf)?1:-1; pasy=(yd<yf)?1:-1; g_pixel(xd,yd,color); if (deltax>deltay) /* ils sont déjà positifs */

Introduction C++ - P. Trau

http://www-ipst.u-strasbg.fr/pat/program/cpp.htm (10 of 11) [21-11-2001 17:44:08]

Page 124: algo

{ somme=deltax/2; while(xd!=xf) { xd+=pasx; somme+=deltay; if(somme>=deltax) {somme-=deltax;yd+=pasy;} g_pixel(xd,yd,color); } } else { somme=deltay/2; while(yd!=yf) { yd+=pasy; somme+=deltax; if(somme>=deltay) {somme-=deltay;xd+=pasx;} g_pixel(xd,yd,color); } } }

P. Trau ULP-IPST 24/2/97

sommaire documents programmation

Introduction C++ - P. Trau

http://www-ipst.u-strasbg.fr/pat/program/cpp.htm (11 of 11) [21-11-2001 17:44:08]

Page 125: algo

le LangagePASCAL -Sommaire

INTRODUCTION

LES LOGICIELS❍

ORGANISATION DEL'ORDINATEUR

LANGAGES DEPROGRAMMATION

UN PREMIER PETITPROGRAMME

CONSTANTES●

INSTRUCTIOND'AFFECTATION

LES TYPES DEVARIABLES STANDARDSIMPLES ET OPERATEURSASSOCIES

ENTIERS❍

REELS❍

BOOLEENS❍

CARACTERES❍

LES FONCTIONSSTANDARD

INSTRUCTION●

STRUCTURES DECONTROLE

BOUCLE WHILE - DO(tant que - faire)

BOUCLE REPEAT -UNTIL (répéter -jusqu'à ce que)

le Langage PASCALPatrick TRAU Janvier 92version HTML mars 97

Ce document présente (de manière claire je crois, d'après ce qu'enont dit certains) le langage PASCAL. Il a été publié dans APTEP -INFO il y a quelques années. Depuis, bien que je maîtrisais bien celangage et avais développé de nombreux programmes en Pascal, jesuis passé au C. Le C est d'après moi plus souple et plus efficace àcondition de bien en comprendre les mécanismes (il faut d'après moicomprendre à la fois l'assembleur et les objets pour bien programmeren C). De plus le C est plus utilisé dans mon environnementd'informaticiens. Néanmoins le Pascal reste bien meilleur pour ledébutant et le programmeur moyen : parfaitement structuré et clair,il conduit rapidement à un programme de bonne qualité et assezfacilement maintenable (ce qui l'est moins en C, qui possède tropsouvent trop de possibilités pour résoudre le même problème).

De plus, on trouve des compilateurs Pascal très conviviaux (TurboPascal sur PC, avec aide en ligne, déboguage,...).

Ce document reste donc d'actualité : le Pascal est d'après moi unetrès bonne manière d'aborder la programmation. C'est pourquoi j'aichoisi de mettre à disposition ce document sur Internet, qu'il serve àqui en a besoin ! Néanmoins, je n'ai pas passé trop de temps à samise en page, les graphiques restent en mode caractère, il n'y a pasde lien direct entre les sujets d'exercices et leur correction (que l'ontrouvera en fin du document).

Voici quelques adresses intéressantes :

ABC de la Programmation : Olivier Pecheux vous aide àdémarrer (y compris à installer le compilateur freewareDJGPP)

Pascalissime●

Point de rencontre des utilisateurs de Borland Pascal●

Site officiel de Borland France, et en particulier lescompilateurs gratuits (sous Dos-Windows évidement, sousUnix vous saviez déjà que les meilleurs compilateurs sontchez GNU).

le cours de Sylvain Bellefeuille (Université de Trois Rivières -●

le Langage PASCAL

http://www-ipst.u-strasbg.fr/pat/program/pascal.htm (1 of 3) [21-11-2001 17:44:19]

Page 126: algo

BOUCLE FOR - DO(pour - faire)

INSTRUCTION IF -THEN - ELSE (si -alors - sinon)

LA STRUCTURECASE - OF (cas -parmi)

TYPES ENUMERES NONSTANDARDS

LES TYPES INTERVALLES●

TABLEAUX

TABLEAUXUNIDIMENSIONNELS

LES CHAINES DECARACTERES

TABLEAUX DETABLEAUX

TABLEAUXCOMPACTES

ENREGISTREMENTS

DECLARATION❍

UTILISATION DESENREGISTREMENTS

LA STRUCTUREWITH - DO (avec -faire)

ENREGISTREMENTSAVEC VARIANTES

PROCEDURES ETFONCTIONS

GENERALITES❍

PORTEE DESDECLARATIONS

ARGUMENTS (OUPARAMETRES)

LES FONCTIONS❍

RECURSIVITE❍

Québec)

Copyright : utilisation de ce document libre pour tout usagepersonnel. Utilisation autorisée pour tout usage public noncommercial, à condition de citer son auteur (Patrick TRAU, IPST,Université Louis Pasteur Strasbourg) et de me signaler tout usageintensif. Utilisation commerciale interdite sans accord écrit de mapart.

INTRODUCTION●

UN PREMIER PETIT PROGRAMME●

CONSTANTES●

INSTRUCTION D'AFFECTATION●

LES TYPES DE VARIABLES STANDARD SIMPLES ETOPERATEURS ASSOCIES

LES FONCTIONS STANDARD●

INSTRUCTION●

STRUCTURES DE CONTROLE●

TYPES ENUMERES NON STANDARDS●

LES TYPES INTERVALLES●

TABLEAUX●

ENREGISTREMENTS●

PROCEDURES ET FONCTIONS●

LES ENTREES / SORTIES●

ENSEMBLES●

POINTEURS●

CORRECTION DES EXERCICES●

Sommaire détaillé●

le Langage PASCAL

http://www-ipst.u-strasbg.fr/pat/program/pascal.htm (2 of 3) [21-11-2001 17:44:19]

Page 127: algo

LES ENTREES / SORTIES

SUR LA CONSOLE❍

LES FICHIERS DETEXTE

EXTENSIONS NONSTANDARD

ACCES DIRECT■

IMPRIMANTE■

AUTRES■

ENSEMBLES●

POINTEURS

LES LISTESCHAINEES ETARBRES

LES POINTEURS ENPASCAL

CORRECTION DESEXERCICES

-- Ex ex_tva❍

-- Ex ex_puiss❍

-- Ex ex_jeu❍

-- Ex ex_moy❍

-- Ex ex_jeu_bis❍

-- Ex ex_calc❍

-- EX moy.a❍

-- Ex rot.b❍

-- Ex clas.c❍

-- Ex str❍

--Ex mat❍

-- Ex tel❍

-- Ex rec❍

-- Ex fichier❍

-- Ex pointeurs❍

le Langage PASCAL

http://www-ipst.u-strasbg.fr/pat/program/pascal.htm (3 of 3) [21-11-2001 17:44:19]

Page 128: algo

Correction des TP d'informatique IUP2Vous trouverez ici la correction des TP d'informatique en IUP 2, en 97/98. Depuis, si chaque année lesTP sont un peu différents, l'ensemble des points que je désire aborder avec mes étudiants reste le même,c'est pourquoi je ne les refais pas systématiquement chaque année.

TP 1 : prise en main de Turbo C, les boucles●

TP 2 : fonctions, aguments, pointeurs, récursivité●

TP 3 : tableaux statiques et dynamiques, comment agrandir un tableau dynamique●

TP 4 : Chaînes de caractères, tableaux de chaînes (et donc tableaux de tableaux)●

TP 5 : pointeurs et arbres●

pour l'année 99/2000, je vous propose quelques indications : TP 1, TP 2, TP 3, TP 4, TP 5. Mêmeremarque pour 2001/2002, ceux-ci sont disponibles (peut-être dès que le quatrième groupe a fini le TP),en fonction de l'avancement des TP.

retour au sommaire des documents d'informatique.

P. TRAU, ULP-IPST, 15/10/00

Correction des TP d'informatique IUP2 97/98

http://www-ipst.u-strasbg.fr/pat/program/tpinfo/ [21-11-2001 17:44:22]

Page 129: algo

Introduction (première partie)Organisation de l'ordinateur●

Langages de programmation●

Organisation de l'ordinateur- Multipostes : plusieurs consoles sur un même ordinateur (CPU puissant, tout est partageable)

- Réseau : plusieurs CPU et MC non partageable (sauf réseau de multipostes), MdM et périphériquespartageables ou locaux.

Langages de programmationUn ordinateur est une machine bête, ne sachant qu'obéir, et à très peu de choses :

* addition, soustraction, multiplication en binaire, uniquement sur des entiers,

* sortir un résultat ou lire une valeur binaire (dans une mémoire par exemple),

* comparer des nombres.

Sa puissance vient du fait qu'il peut être PROGRAMME, c'est à dire que l'on peut lui donner, à l'avance,la séquence (la suite ordonnée) des ordres à effectuer l'un après l'autre. Le grand avantage de l'ordinateurest sa rapidité. Par contre, c'est le programmeur qui doit TOUT faire. L'ordinateur ne comprenant que desordres codés en binaire (le langage machine), des langages dits "évolués" ont été mis au point pourfaciliter la programmation, au début des années 60, en particulier FORTRAN (FORmula TRANslator)pour le calcul scientifique et COBOL pour les applications de gestion. Puis, pour des besoinspédagogiques principalement, ont été créés le BASIC, pour une approche simple de la programmation, etPASCAL au début des années 70. Ce dernier (comme le C) favorise une approche méthodique etdisciplinée (on dit "structurée"). Le C a été développé conjointement au système d'exploitation UNIX,dans les Laboratoires BELL, par Brian W Kernigham et Dennis M Ritchie, qui ont défini en 78, dans"The C Language", les règles de base de ce langage. Le but principal était de combiner une approchestructurée (et donc une programmation facile) avec des possibilités proches de celles de l'assembleur(donc une efficacité maximale en exécution, quitte à passer plus de temps de programmation), tout enrestant standard (c'est à dire pouvoir être implanté sur n'importe quelle machine). Puis ce langage a éténormalisé en 88 (norme ANSI), cette norme apportant un nombre non négligeable de modifications aulangage.

Le C est un langage compilé, c'est à dire qu'il faut :

Langage C - Introduction (première partie)

http://www-ipst.u-strasbg.fr/pat/program/tpc01.htm (1 of 2) [21-11-2001 17:44:26]

Page 130: algo

* entrer un texte dans l'ordinateur (à l'aide d'un programme appelé EDITEUR),

* le traduire en langage machine (c'est à dire en codes binaires compréhensibles par l'ordinateur) : c'est lacompilation et, si plusieurs modules ont été compilés séparément, l'édition de liens (LINK ou BIND),

* l'exécuter.

Contrairement à un basic interprété, l'exécution sera beaucoup plus rapide puisqu'il n'y a plus detraduction à effectuer, mais la phase de mise au point sera plus complexe.

Bien que le langage soit normalisé, un certain nombre de points dépendent de la machine et ducompilateur utilisé (par exemple comment appeler le compilateur). Ces indications ne seront pas donnéesici. Si vous avez le choix, je vous conseille TURBO C, le plus pratique d'emploi (en particulier parcequ'il possède son propre éditeur de texte). Il permet une mise au point aussi simple que si le langage étaitinterprété

Langage C - Introduction (première partie)

http://www-ipst.u-strasbg.fr/pat/program/tpc01.htm (2 of 2) [21-11-2001 17:44:26]

Page 131: algo

Langage C - SommaireIntroduction (première partie)

Organisation de l'ordinateur❍

Langages de programmation❍

Connaissances de base●

Fonctions d'entrées/sorties les plus utilisées●

La syntaxe du C

Second exemple, définitions❍

Variables / identificateurs / adresse / pointeurs❍

Expressions / opérateurs

Arithmétiques

unaires■

deuxaires■

Relationnels

comparaisons■

logique booléenne■

binaires■

Affectation

affectation simple =■

incrémentation / décrémentation■

affectation élargie■

Opérateurs d'adresses■

Autres

conditionnel ? :■

séquentiel ,■

Ordre de priorité et associativité■

Instructions❍

Structures de contrôle

Boucles■

Langage C - Sommaire

http://www-ipst.u-strasbg.fr/pat/program/tpc_c.htm (1 of 3) [21-11-2001 17:44:30]

Page 132: algo

While (tant que)■

Do While (faire tant que)■

For (pour)■

Branchements conditionnels

If - Else (Si - Sinon)■

Switch - Case (brancher - dans le cas)■

Branchements inconditionnels

Break (interrompre)■

Continue (continuer)■

Goto (aller à)■

Return (retourner)■

Exit (sortir)■

Déclaration et stockage des variables

Déclarations locales■

Déclarations globales■

Déclaration de type■

Fonctions

Définitions générales■

Récursivité, gestion de la pile■

Arguments passés par adresse■

La fonction main■

Fonction retournant un pointeur et pointeur de fonction■

Les types de données du C

Variables scalaires

char : caractère (8 bits)■

int : entier■

float : réel■

Tailles et plages■

Conversions de type / cast■

Enumérations■

Tableaux

Tableaux unidimensionnels■

Tableaux et pointeurs / arithmétique des pointeurs■

Langage C - Sommaire

http://www-ipst.u-strasbg.fr/pat/program/tpc_c.htm (2 of 3) [21-11-2001 17:44:30]

Page 133: algo

Chaînes de caractères■

Bibliothèques de fonctions pour tableaux et chaînes■

Allocation dynamique de mémoire■

Tableaux multidimensionnels■

Structures et unions

Déclaration■

Utilisation■

Champs de bits■

Unions■

Structures chaînées■

Les fichiers de données

Fichiers bruts❍

Fichiers bufférisés❍

Directives du pré-compilateur●

Utiliser Turbo C (3.5 par exemple)●

Correction des exercices●

Autres sites sur le C●

Langage C - Sommaire

http://www-ipst.u-strasbg.fr/pat/program/tpc_c.htm (3 of 3) [21-11-2001 17:44:30]

Page 134: algo

Connaissances de baseregardons ce petit programme :

#include <stdio.h>#define TVA 18.6void main(void) { float HT,TTC; puts ("veuillez entrer le prix H.T."); scanf("%f",&HT); TTC=HT*(1+(TVA/100)); printf("prix T.T.C. %f\n",TTC); }

On trouve dans ce programme :

* des directives du pré processeur (commençant par #)

#include : inclure le fichier définissant (on préfère dire déclarant) les fonctions standard d'entrées/sorties(en anglais STanDard In/Out), qui feront le lien entre le programme et la console (clavier/écran). Danscet exemple il s'agit de puts, scanf et printf.

#define : définit une constante. A chaque fois que le compilateur rencontrera, dans sa traduction de lasuite du fichier en langage machine, le mot TVA, ces trois lettres seront remplacées par 18.6. Cestransformation sont faites dans une première passe (appelée pré compilation), où l'on ne fait que du"traitement de texte", c'est à dire des remplacements d'un texte par un autre sans chercher à encomprendre la signification.

* une entête de fonction. Dans ce cas on ne possède qu'une seule fonction, la fonction principale (mainfunction). Cette ligne est obligatoire en C, elle définit le "point d'entrée" du programme, c'est à direl'endroit où débutera l'exécution du programme.

* un "bloc d'instructions", délimité par des accolades {}, et comportant :

* des déclarations de variables, sous la forme : type listevariables;

Une variable est un case mémoire de l'ordinateur, que l'on se réserve pour notre programme. On définit lenom que l'on choisit pour chaque variable, ainsi que son type, ici float, c'est à dire réel (type dit à virguleflottante, d'où ce nom). Les trois types scalaires de base du C sont l'entier (int), le réel (float) et lecaractère (char). On ne peut jamais utiliser de variable sans l'avoir déclarée auparavant. Une faute defrappe devrait donc être facilement détectée, à condition d'avoir choisi des noms de variables

Langage C - Connaissances de base

http://www-ipst.u-strasbg.fr/pat/program/tpc02.htm (1 of 2) [21-11-2001 17:44:34]

Page 135: algo

suffisamment différents (et de plus d'une lettre).

* des instructions, toutes terminées par un ;. Une instruction est un ordre élémentaire que l'on donne à lamachine, qui manipulera les données (variables) du programme, ici soit par appel de fonctions (puts,scanf, printf) soit par affectation (=).

Détaillons les 4 instructions de notre programme :

puts affiche à l'écran le texte qu'on lui donne (entre parenthèses, comme tout ce que l'on donne à unefonction, et entre guillemets, comme toute constante texte en C).

scanf attend que l'on entre une valeur au clavier, puis la met dans la mémoire (on préfère dire variable)HT, sous format réel (%f).

une affectation : on commence par diviser TVA par 100 (à cause des parenthèses), puis on y ajoute 1,puis on le multiplie par le contenu de la variable HT. Le résultat de ce calcul est stocké (affecté) dans lavariable cible TTC. Une affectation se fait toujours dans le même sens : on détermine (évalue) toutd'abord la valeur à droite du signe =, en faisant tous les calculs nécessaires, puis elle est transférée dans lamémoire dont le nom est indiqué à gauche du =. On peut donc placer une expression complexe à droitedu =, mais à sa gauche seul un nom de variable est possible, aucune opération.

printf affichera enfin le résultat stocké dans TTC.

Langage C - Connaissances de base

http://www-ipst.u-strasbg.fr/pat/program/tpc02.htm (2 of 2) [21-11-2001 17:44:34]

Page 136: algo

Fonctions d'entrées/sorties les plusutiliséesLe langage C se veut totalement indépendant du matériel sur lequel il est implanté. Les entrées sorties,bien que nécessaires à tout programme (il faut lui donner les données de départ et connaître les résultats),ne font donc pas partie intégrante du langage. On a simplement prévu des bibliothèques de fonctions debase, qui sont néanmoins standardisées, c'est à dire que sur chaque compilateur on dispose de cesbibliothèques, contenant les même fonctions (du moins du même nom et faisant apparemment la mêmechose, mais programmées différemment en fonction du matériel). Ces bibliothèques ont été définies parla norme ANSI, on peut donc les utiliser tout en restant portable. Nous détaillerons ici deux bibliothèques: CONIO.H et STDIO.H.

Dans CONIO.H on trouve les fonctions de base de gestion de la console :

putch(char) : affiche sur l'écran (ou du moins stdout) le caractère fourni en argument (entreparenthèses). stdout est l'écran, ou un fichier si on a redirigé l'écran (en rajoutant >nomfichier derrièrel'appel du programme, sous DOS ou UNIX). Si besoin est, cette fonction rend le caractère affiché ouEOF en cas d'erreur.

getch(void) : attend le prochain appui sur le clavier, et rend le caractère qui a été saisi. L'appui sur unetouche se fait sans écho, c'est à dire que rien n'est affiché à l'écran. En cas de redirection du clavier, onprend le prochain caractère dans le fichier d'entrée.

getche(void) : idem getch mais avec écho. On pourrait réécrire cette fonction en fonction des deuxprécédentes :

char getche(void); { char caractere; caractere=getch(); putch(caractere); return(caractere); }

ou même {return(putch(getch))}

Dans la pratique, ce n'est pas ainsi que getche est réellement défini, mais en assembleur pour un résultatplus rapide.

Dans STDIO.H, on trouve des fonctions plus évoluées, pouvant traiter plusieurs caractères à la suite (parles fonctions de conio.h), et les transformer pour en faire une chaîne de caractères ou une valeur

Langage C - Fonctions d'entrées/sorties les plus utilisées

http://www-ipst.u-strasbg.fr/pat/program/tpc03.htm (1 of 3) [21-11-2001 17:44:39]

Page 137: algo

numérique, entière ou réelle par exemple. Les entrées sont dites "bufférisées", c'est à dire que le texten'est pas transmis, et peut donc encore être modifié, avant le retour chariot.

puts(chaîne) affiche, sur stdout, la chaîne de caractères puis positionne le curseur en début de lignesuivante. puts retourne EOF en cas d'erreur.

gets(chaîne) lecture d'une chaîne sur stdin. Tous les caractères peuvent être entrés, y compris les blancs.La saisie est terminée par un retour chariot. Gets retourne un pointeur sur le premier caractère entré (doncégal à son paramètre d'entrée, ou le pointeur NULL en cas d'erreur (fin du fichier stdin par exemple).

printf(format,listevaleurs) affiche la liste de valeurs (variables ou expressions) dans le format choisi.Le format est une chaîne de caractères entre guillemets (doubles quote "), dans laquelle se trouve un textequi sera écrit tel quel, des spécifications de format (débutant par %) qui seront remplacées par la valeureffective des variables, dans l'ordre donné dans listevaleurs, et de caractères spéciaux (\). Printf retournele nombre de caractères écrits, ou EOF en cas de problème.

Une spécification de format est de la forme :

% [flag][largeur][.précision][modificateur]type (entre [] facultatifs)

Le flag peut valoir : - (cadrage à gauche, rajout de blancs si nécessaire à droite), + (impression du signe,même pour les positifs), blanc (impression d'un blanc devant un nombre positif, à la place du signe), 0 (lajustification d'un nombre se ferra par rajout de 0 à gauche au lieu de blancs). D'autres Flags sontpossibles mais moins utiles, pour plus de détails voir l'aide en ligne de Turbo C.

La largeur est le nombre minimal de caractères à écrire (des blancs sont rajoutés si nécessaire). Si letexte à écrire est plus long, il est néanmoins écrit en totalité. En donnant le signe * comme largeur, leprochain argument de la liste de valeurs donnera la largeur (ex printf("%*f",largeur,réel)).

La précision définit, pour les réels, le nombre de chiffres après la virgule (doit être inférieur à la largeur).Dans la cas d'entiers, indique le nombre minimal de chiffes désiré (ajout de 0 sinon), alors que pour unechaîne (%s), elle indique la longueur maximale imprimée (tronqué si trop long). La précision peut,comme la largeur, être variable en donnant .*

Le modificateur peut être : h (short, pour les entiers), l (long pour les entiers, double pour les réels), L(long double pour les réels).

Le type est : c (char), s (chaîne de caractères, jusqu'au \0), d (int), u (entier non signé), x ou X (entieraffiché en hexadécimal), o (entier affiché en octal), f (réel en virgule fixe), e ou E (réel en notationexponentielle), g ou G (réel en f si possible, e sinon), p (pointeur), % (pour afficher le signe %).

Les caractères spéciaux utilisables dans le format sont \t (tabulation), \n (retour à la ligne), \\ (signe \), \nbtout code ASCII, en décimal, hexa ou octal (\32=\040=\0x20=' ').

scanf(format,listeadresse) lecture au clavier de valeurs, dans le format spécifié. Les arguments sont despointeurs sur les variables résultats (dans le cas de variables scalaires, les précéder par l'opérateur &).Scanf retourne le nombre de valeurs effectivement lues et mémorisées (pas les %*).

Le format peut contenir (entre ") : du texte (il devra être tapé exactement ainsi par l'utilisateur, et ne serapas stocké), des séparateurs blancs (l'utilisateur devra taper un ou plusieurs blancs, tabulations, retours à

Langage C - Fonctions d'entrées/sorties les plus utilisées

http://www-ipst.u-strasbg.fr/pat/program/tpc03.htm (2 of 3) [21-11-2001 17:44:39]

Page 138: algo

la ligne), et des spécifications de format, sous la forme %[*][largeur][modificateur] type.

* signifie que la valeur sera lue mais ne sera pas stockée (ex scanf("%d%*c%d",&i,&j) : lecture de deuxentiers séparés par n'importe quel caractère)

la largeur est la largeur maximale lue, scanf s'arrête avant s'il trouve un séparateur (blanc, tab, CR).

les modificateurs et types sont les mêmes que pour printf (excepté d,o,x : pour entiers short, D,O,X pourlong). Dans le cas des chaînes (%s), le blanc est également un séparateur. On ne pourra donc pas entrerune chaîne avec des blancs par scanf, il faut utiliser gets.

Scanf lit dans stdin en considérant les retours chariot (CR) comme des blancs. on peut donc séparer pardes CR plusieurs valeurs demandées dans le même scanf. Mais de même, si scanf a pu lire tous sesarguments sans arriver à la fin de la ligne, la suite servira au prochain scanf. Utilisez gets(bidon) avant(pour être sur de commencer sur une nouvelle ligne) ou après scanf (pour ignorer la fin de la ligne) sinécessaire.

getchar(void) fonctionne comme getche, mais utilise le même tampon que scanf.

On dispose aussi de sprintf(chaîne, format, listevaleurs) qui permet d'écrire dans une chaîne plutôt quesur l'écran, et donc faire des conversions numériques ->ASCII; et de sscanf(chaîne, format,listeadresse) qui lit dans une chaîne plutôt qu'au clavier. On possède encore d'autres fonctions dansSTDIO, en particulier pour gérer les fichiers.

Langage C - Fonctions d'entrées/sorties les plus utilisées

http://www-ipst.u-strasbg.fr/pat/program/tpc03.htm (3 of 3) [21-11-2001 17:44:39]

Page 139: algo

La syntaxe du CSecond exemple, définitions●

Variables / identificateurs / adresse / pointeurs●

Expressions / opérateurs

Arithmétiques

unaires■

deuxaires■

Relationnels

comparaisons■

logique booléenne■

binaires■

Affectation

affectation simple =■

incrémentation / décrémentation■

affectation élargie■

Opérateurs d'adresses❍

Autres

conditionnel ? :■

séquentiel ,■

Ordre de priorité et associativité❍

Instructions●

Structures de contrôle

Boucles

While (tant que)■

Do While (faire tant que)■

For (pour)■

Branchements conditionnels

If - Else (Si - Sinon)■

Switch - Case (brancher - dans le cas)■

Branchements inconditionnels❍

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (1 of 34) [21-11-2001 17:45:32]

Page 140: algo

Break (interrompre)■

Continue (continuer)■

Goto (aller à)■

Return (retourner)■

Exit (sortir)■

Déclaration et stockage des variables

Déclarations locales❍

Déclarations globales❍

Déclaration de type❍

Fonctions

Définitions générales❍

Récursivité, gestion de la pile❍

Arguments passés par adresse❍

La fonction main❍

Fonction retournant un pointeur et pointeur de fonction❍

Les types de données du C

Variables scalaires

char : caractère (8 bits)■

int : entier■

float : réel■

Tailles et plages■

Conversions de type / cast■

Enumérations■

Tableaux

Tableaux unidimensionnels❍

Tableaux et pointeurs / arithmétique des pointeurs❍

Chaînes de caractères❍

Bibliothèques de fonctions pour tableaux et chaînes❍

Allocation dynamique de mémoire❍

Tableaux multidimensionnels❍

Structures et unions

Déclaration❍

Utilisation❍

Champs de bits❍

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (2 of 34) [21-11-2001 17:45:32]

Page 141: algo

Unions❍

Structures chaînées❍

Second exemple, définitionsConsidérons le programme ci-dessous :

#include <stdio.h>void affiche_calcul(float,float); /* prototype */float produit(float,float);int varglob;

void main(void) { float a,b; /* déclaration locale */ varglob=0; puts("veuillez entrer 2 valeurs"); scanf("%f %f",&a,&b); affiche_calcul(a,b); printf("nombre d'appels à produit : %d\n",varglob); }

float produit(float r, float s) { varglob++; return(r*s); }

void affiche_calcul(float x,float y) { float varloc; varloc=produit(x,y); varloc=produit(varloc,varloc); printf("le carré du produit est %f\n",varloc); }

Un programme C est composé :

* de directivess du pré-processeur, commençant par #, terminées par un retour à la ligne (pas de ;)

* de déclarations globales (terminées par un ;)

* d'une suite de fonctions, écrites les unes après les autres (sans imbrication comme on le ferait en Pascal)

Les fonctions sont écrites sous la forme : entête { corps }

L'entête est de la forme : type_résultat nom (arguments) . Le type_résultat n'était obligatoire (avant la

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (3 of 34) [21-11-2001 17:45:32]

Page 142: algo

norme ANSI) que s'il était différent de int (entier). Il doit désormais être void (rien) si la fonction nerenvoie rien (dans un autre langage on l'aurait alors appelé sous-programme, procédure, ou sous-routine).Les arguments, s'ils existent, sont passés par valeur. Si la fonction ne nécessite aucun argument, il fautindiquer (void) d'après la norme ANSI, ou du moins ().

Le corps est composé de déclarations de variables locales, et d'instructions, toutes terminées par un ;

Variables / identificateurs / adresse / pointeursOn appelle variable une mémoire de l'ordinateur (ou plusieurs), à laquelle on a donné un nom, ainsi qu'untype (on a précisé ce qu'on mettra dans cette variable (entier, réel, caractère,...), pour que le compilateurpuisse lui réserver la quantité de mémoire nécessaire. Dans cette variable, on pourra y stocker une valeur, etla modifier au cours du programme.

Exemple : int a; a est une variable entière, le compilateur va lui réserver en mémoire la place nécessaire àun entier (2 octets en Turbo C). Le nom de cette variable est choisi par le programmeur. On préfère utiliserle terme identificateur plutôt que nom, car il permet d'identifier tout objet que l'on voudra utiliser (passeulement les variables). Les identificateurs doivent suivre quelques règles de base : il peut être formé delettres (A à Z), de chiffres et du caractère _ (souligné). Le premier caractère doit être une lettre (ou _ mais ilvaut mieux le réserver au compilateur). Par exemple valeur1 ou prem_valeur sont possibles, mais pas1ere_valeur. En C, les minuscules sont différentes des majuscules (SURFace et surFACE désignent deuxobjets différents). Le blanc est donc interdit dans un identificateur (utilisez _). Les lettres accentuées sontégalement interdites. La plupart des compilateurs acceptent n'importe quelle longueur d'identificateurs (touten restant sur la même ligne) mais seuls les 32 premiers caractères sont significatifs.

On considère comme blanc : soit un blanc (espace), soit un retour à la ligne, soit une tabulation, soit uncommentaire, soit plusieurs de ceux-ci. Les commentaires sont une portion de texte commençant par /* etfinissant par le premier */ rencontré. les commentaires ne peuvent donc pas être imbriqués. mais uncommentaire peut comporter n'importe quel autre texte, y compris sur plusieurs lignes.

Un identificateur se termine soit par un blanc, soit par un signe non autorisé dans les identificateurs(parenthèse, opérateur, ; ...). Le blanc est alors autorisé mais non obligatoire.

L'endroit où le compilateur a choisi de mettre la variable est appelé adresse de la variable (c'est en généralun nombre, chaque mémoire d'un ordinateur étant numérotée de 0 à ? ). Cette adresse ne nous intéresse querarement de manière explicite, mais souvent de manière indirecte. Par exemple, dans un tableau, composéd'éléments consécutifs en mémoire, en connaissant son adresse (son début), on retrouve facilement l'adressedes différentes composantes par une simple addition. On appelle pointeur une variable dans laquelle onplace (mémorise) une adresse de variable (où elle est) plutôt qu'une valeur (ce qu'elle vaut).

Les types de variables scalaires simples que l'on utilise le plus couramment sont le char (un caractère), l'int(entier) et le float (réel). Le char est en fait un cas particulier des int, chaque caractère étant représenté parson numéro de code ASCII.

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (4 of 34) [21-11-2001 17:45:32]

Page 143: algo

Expressions / opérateursUne expression est un calcul qui donne une valeur résultat (exemple : 8+5). Une expression comporte desvariables, des appels de fonction et des constantes combinés entre eux par des opérateurs (ex :MaVariable*sin(VarAngle*PI/180) ).

Une expression de base peut donc être un appel à une fonction (exemple sin(3.1416). Une fonction est unbout de programme (que vous avez écrit ou faisant partie d'une bibliothèque) auquel on "donne" des valeurs(arguments), entre parenthèses et séparés par des virgules. La fonction fait un calcul sur ces arguments pour"retourner" un résultat. Ce résultat pourra servir, si nécessaire, dans une autre expression, voire commeargument d'une fonction exemple atan(tan(x)). Les arguments donnés à l'appel de la fonction (ditsparamètres réels ou effectifs) sont recopiés dans le même ordre dans des copies (paramètres formels), quielles ne pourront que modifier les copies (et pas les paramètres réels). Dans le cas de fonctions devantmodifier une variable, il faut fournir en argument l'adresse (par l'opérateur &, voir plus bas), comme parexemple pour scanf.

Pour former une expression, les opérateurs possibles sont assez nombreux, nous allons les détailler suivantles types de variables qu'ils gèrent.

Arithmétiques

Ces opérateurs s'appliquent à des valeurs entières ou réelles.

unaires

Ce sont les opérateurs à un seul argument : - et + (ce dernier a été rajouté par la norme ANSI). Le résultatest du même type que l'argument.

deuxaires

Le terme "deuxaire" n'est pas standard, je l'utilise parce que binaire est pour moi associé à la base 2.

Ces opérateurs nécessitent deux arguments, placés de part et d'autre de l'opérateur. Ce sont + (addition), -(soustraction), * (produit), / (division), % (reste de la division). % nécessite obligatoirement deuxarguments entiers, les autres utilisent soit des entiers, soit des réels. Les opérandes doivent être du mêmetype, le résultat sera toujours du type des opérandes. Lorsque les deux opérandes sont de type différent(mais numérique évidement), le compilateur prévoit une conversion implicite (vous ne l'avez pas demandéemais il la fait néanmoins) suivant l'ordre : { char -> int -> long -> float -> double } et { signed -> unsigned}. On remarque qu'il considère les char comme des entiers, les opérations sont en fait faites sur les numérosde code (ASCII). Les calculs arithmétiques sont faits uniquement soit en long soit en double, pour éviterdes dépassements de capacité.

exemples :

int a=1,b=2,c=32000;float x=1,y=2;a=(c*2)/1000; /* que des int, le résultat est 64, bien que l'on soitpassé par un résultat intermédiaire (64000) qui dépassait la capacité

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (5 of 34) [21-11-2001 17:45:32]

Page 144: algo

des entiers (mais pas celle des long) */b=7/b; /* signe = donc en premier calcul de l'argument à droite : 7(entier) / 2 (entier) donne 3 (entier, reste 1, que l'on obtient par5%2). donc b=3 */x=7/b; /* 7 et b entiers => passage en réel inutile, calcul de 7/3 donne2 (entier, reste 1) puis opérateur = (transformation du 2 en 2.0 puistransfert dans X qui vaut donc 2.0) */x=7/y; /* un int et un float autour de / : transformation implicite de 7en réel (7.0), division des deux réel (3.5), puis transfert dans x */x=((float)(a+1))/b; /* calcul (entier) de a+1, puis transformationexplicite en float, et donc implicite de b en float, division 65.0/3.0-> 21.666... */

Relationnels

comparaisons

Ces opérateurs sont deuxaires : = = (égalité), != (différent), <, >, <=, >=. Des deux côtés du signeopératoire, il faut deux opérandes de même type (sinon, transformation implicite) mais numérique (lescaractères sont classés suivant leur numéro de code ASCII). Le résultat de l'opération est 0 si faux, 1 si vrai(le résultat est de type int). Exemple : (5<7)+3*((1+1)= =2) donne 4. Attention, le compilateur ne vousprévient pas si vous avez mis = au lieu de = = (= est aussi un opérateur, voir plus loin), mais le résultat seradifférent de celui prévu.

logique booléenne

Le résultat est toujours 0 (faux) ou 1 (vrai), les opérandes devant être de type entier (si char conversionimplicite), 0 symbolisant faux, toute autre valeur étant considérée vraie.

Opérateur unaire : ! (non). !arg vaut 1 si arg vaut 0, et 0 sinon.

Opérateurs deuxaires : && (ET, vaut 1 si les 2 opérandes sont non nuls, 0 sinon) et || (OU, vaut 0 si lesdeux opérandes sont nuls, 1 sinon). Le deuxième opérande n'est évalué que si le premier n'a pas suffi pourconclure au résultat (ex (a= =0)&&(x++<0) incrémente x si a est nul, le laisse intact sinon).

binaires

Ces opérateurs ne fonctionnent qu'avec des entiers. Ils effectuent des opérations binaires bit à bit. On peututiliser ~ (complément, unaire), & (et), | (ou inclusif), ^ (ou exclusif), >> (décalage à droite, le 2èmeopérande est le nombre de décalages), << (décalage à gauche). Contrairement aux opérateurs relationnels,les résultats ne se limitent pas à 0 et 1.

exemples : 7&12 donne 4 (car 0111&1100 donne 0100); ~0 donne -1 (tous les bits à 1, y compris celui designe); 8>>2 donne 32.

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (6 of 34) [21-11-2001 17:45:32]

Page 145: algo

Affectation

affectation simple =

En C, l'affectation (signe =) est une opération comme une autre. Elle nécessite deux opérantes, un à droite,appelé Rvalue, qui doit être une expression donnant un résultat d'un type donné, et un à gauche (Lvalue)qui doit désigner l'endroit en mémoire où l'on veut stocker la Rvalue. Les deux opérandes doivent être demême type, dans le cas d'opérandes numériques si ce n'est pas le cas le compilateur effectuera uneconversion implicite (la Lvalue doit être de type "plus fort" que la Rvalue). L'opération d'affectation rendune valeur, celle qui a été transférée, et peut donc servir de Rvalue.

Exemples : a=5 (met la valeur 5 dans la variable a. Si a est float, il y a conversion implicite en float);b=(a*5)/2 (calcule d'abord la Rvalue, puis met le résultat dans b); a=5+(b=2) (Le compilateur litl'expression de gauche à droite. la première affectation nécessite le calcul d'une Rvalue : 5+(b=2). Celle cicomporte une addition, dont il évalue le premier opérande (5) puis le second (b=2). Il met donc 2 dans b, lerésultat de l'opération est 2, qui sera donc ajouté à 5 pour être mis dans a. A vaut donc 7 et b, 2. Le résultatde l'expression est 7 (si l'on veut s'en servir).

Remarque : il ne faut pas confondre = et = =. Le compilateur ne peut pas remarquer une erreur(contrairement au Pascal ou Fortran) car les deux sont possibles. Exemple : if (a=0) est toujours faux carquelle que soit la valeur initiale de a, on l'écrase par la valeur 0, le résultat de l'opération vaut 0 et est doncinterprété par IF comme faux.

incrémentation / décrémentation

++a : ajoute 1 à la variable a. Le résultat de l'expression est la valeur finale de a (c'est à dire aprèsincrémentation). On l'appelle incrémentation préfixée.

a++ : ajoute 1 à la variable a. Le résultat de l'expression est la valeur initiale de a (c'est à dire avantincrémentation). C'est l'incrémentation postfixée.

de même, la décrémentation --a et a-- soustrait 1 à a.

exemple : j=++i est équivalent à j=(i=i+1)

affectation élargie

+= , -= , *= , /= , %= , <<= , >>= , &= , ^= , |=

a+=5 est équivalent à a=(a+5). Il faut encore ici une Rvalue à droite et une Lvalue à gauche.

Opérateurs d'adresses

Ces opérateurs sont utilisées avec des pointeurs. On utilise

&variable : donne l'adresse d'une variable●

*pointeur : réfère à la variable pointée (opérateur d'indirection)●

. : champ d'une structure●

-> : champ pointé●

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (7 of 34) [21-11-2001 17:45:32]

Page 146: algo

exemple : supposons déclarer : int i1=1,i2=2; int *p1,*p2; i1 et i2 sont deux mémoires contenant un entier,alors que p1 et p2 sont des pointeurs, puisqu'ils contiennent une adresse d'entier. p1=&i1; met dans p1l'adresse de i1. p2=p1; met la même adresse (celle de i1) dans p2. printf("%d\n",*p1) affiche ce qui estdésigné (pointé) par p1 donc i1 donc 1. p2=&i2;*p2=*p1; à l'adresse pointée par p2 mettre ce qui est pointépar p1, donc copier la valeur de i1 dans i2. printf("%d\n",i2) affiche donc 1.

Autres

conditionnel ? :

C'est un (le seul) opérateur ternaire. L'expression a?b:c vaut la valeur de b si a est vrai (entier, différent de0), et c si a est faux. Exemple : max=a>b?a:b

séquentiel ,

Cet opérateur permet de regrouper deux sous expressions en une seule. On effectue le premier opérandepuis le second, la valeur finale de l'expression étant celle du second opérande. On l'utilise pour évaluerdeux (ou plus) expressions là où la syntaxe du C ne nous permettait que d'en mettre une, exemple :for(i=j=0;i>10;i++,j++). Dans le cas d'une utilisation de cet opérateur dans une liste, utilisez les parenthèsespour distinguer les signes , : exemple (inutile) : printf("%d %d",(i++,j++),k) i est modifié mais sa valeurn'est pas affichée.

Ordre de priorité et associativité

opérateurs associativité description

() [] -> . ->

! ~ ++ -- - + & * (cast) <- unaires (* pointeurs)

* / % -> multiplicatifs

+ - -> addition

>> << -> décalages

< <= > >= -> relations d'ordre

= = != -> égalité

& -> binaire

^ -> binaire

| -> binaire

&& -> logique

| | -> logique

? : -> conditionnel (ternaire)

= += -= *= etc. <- affectation

, <- séquentiel

Dans ce tableau, les opérateurs sont classés par priorité décroissante (même priorité pour les opérateurs

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (8 of 34) [21-11-2001 17:45:32]

Page 147: algo

d'une même ligne). Les opérateurs les plus prioritaires se verront évaluer en premier. L'associativité définitl'ordre d'évaluation des opérandes. La plupart se font de gauche à droite ( 4/2/2 donne (4/2)/2 donc 1 (et pas4/(2/2))).

Les seules exceptions sont :

les opérateurs unaires, écrits à gauche de l'opérateur. L'opérande est évalué puis l'opération esteffectuée, le résultat est celui de l'opération; sauf dans le cas de l'incrémentation / décrémentationpostfixée, où le résultat de l'expression est la valeur de l'argument avant l'opération.

L'affectation : on calcule l'opérande de droite, puis on l'affecte à celui de gauche. Le résultat est lavaleur transférée.

La virgule : la valeur à droite est calculée avant celle à gauche (en particulier lors d'un appel defonction)

Les opérateurs logiques et conditionnel évaluent toujours leur premier argument. Le second parcontre n'est évalué que si c'est nécessaire.

InstructionsUne instruction peut être :

- soit une expression (pouvant comprendre une affectation, un appel de fonction...), terminé par un ; qui enfait signifie "on peut oublier le résultat de l'expression et passer à la suite",- soit une structure de contrôle (boucle, branchement...),- soit un bloc d'instructions : ensemble de déclarations et instructions délimités par des accolades {}. Unbloc sera utilisé à chaque fois que l'on désire mettre plusieurs instructions là où on ne peut en mettre qu'une.

Seule la première forme est terminée par un ;. Un cas particulier est l'instruction vide, qui se composeuniquement d'un ; (utilisé là où une instruction est nécessaire d'après la syntaxe).

Structures de contrôleNormalement, les instructions s'effectuent séquentiellement, c'est à dire l'une après l'autre. Pour accéder àune autre instruction que la suivante, on a trois solutions : le branchement inconditionnel, le branchementconditionnel et la boucle.

Boucles

Une boucle permet de répéter plusieurs fois un bloc d'instructions.

While (tant que)

structure : while (expression) instruction

Tant que l'expression est vraie (!=0), on effectue l'instruction, qui peut être simple (terminée par ;), bloc(entre {}) ou vide (; seul). L'expression est au moins évaluée une fois. Tant qu'elle est vraie, on effectuel'instruction, dès qu'elle est fausse, on passe à l'instruction suivante (si elle est fausse dès le début,l'instruction n'est jamais effectuée).

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (9 of 34) [21-11-2001 17:45:32]

Page 148: algo

exemple :

#include <stdio.h>void main(void) { float nombre,racine=0; puts("entrez un nombre réel entre 0 et 10"); scanf("%f",&nombre); while (racine*racine<nombre) racine+=0.01; printf("la racine de %f vaut %4.2f à 1%% près\n", nombre, racine); }

Exercice (while_puiss) : faire un programme qui affiche toutes les puissances de 2, jusqu'à une valeurmaximale donnée par l'utilisateur. On calculera la puissance par multiplications successives par 2. Cliquezici pour une solution.

Exercice (while_err) : que fait ce programme ?

#include <stdio.h>#include <math.h>#define debut 100#define pas 0.01void main(void) { float nombre=debut; int compte=0,tous_les; puts("afficher les résultats intermédiaires tous les ? (333 par exemple) ?"); scanf("%d",&tous_les); while (fabs(nombre-(debut+(compte*pas)))<pas) { nombre+=pas; if (!(++compte%tous_les)) printf("valeur obtenue %12.8f, au lieu de %6.2f en %d calculs\n", nombre,(float)(debut+(compte*pas)), compte); } printf("erreur de 100%% en %d calculs\n",compte); }

Cliquez ici pour une solution.

Do While (faire tant que)

structure : do instruction while (expression); (attention au ; final)

comme while, mais l'instruction est au moins faite une fois, avant la première évaluation de l'expression.

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (10 of 34) [21-11-2001 17:45:32]

Page 149: algo

exemple :

#include <stdio.h>void main(void) { int a; do { puts("entrez le nombre 482"); scanf("%d",&a); } while (a!=482); puts("c'est gentil de m'avoir obéi"); }

Exercice (do_while) : écrivez un programme de jeu demandant de deviner un nombre entre 0 et 10 choisipar l'ordinateur. On ne donnera pas d'indications avant la découverte de la solution, où l'on indiquera lenombre d'essais. La solution sera choisie par l'ordinateur par la fonction rand() qui rend un entier aléatoire(déclarée dans stdlib.h). Cliquez ici pour une solution.

For (pour)

structure : for ( expr_initiale;expr_condition;expr_incrémentation) instruction

Cette boucle est surtout utilisée lorsque l'on connaît à l'avance le nombre d'itération à effectuer.L'expr_initiale est effectuée une fois, en premier. Puis on teste la condition. On effectue l'instruction puisl'incrémentation tant que la condition est vraie. L'instruction et l'incrémentation peuvent ne jamais êtreeffectuées. La boucle est équivalente à :

expr_initiale; while (expr_condition) { instruction expr_incrémentation; }

Une ou plusieurs des trois expressions peuvent être omises, l'instruction peut être vide. for(;;); est donc uneboucle infinie.

exemple :

{ char c; for(c='Z';c>='A';c--)putchar(c); }

Exercice (for) : faire un programme qui calcule la moyenne de N notes. N et les notes seront saisies parscanf. Le calcul de la moyenne s'effectue en initialisant une variable à 0, puis en y ajoutant progressivementles notes saisies puis division par N. Cliquez ici pour une solution.

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (11 of 34) [21-11-2001 17:45:33]

Page 150: algo

Branchements conditionnels

On a souvent besoin de n'effectuer certaines instructions que dans certains cas. On dispose pour cela du IFet du SWITCH.

If - Else (Si - Sinon)

structure : if (expression) instruction1

ou : if (expression) instruction1 else instruction2

Si l'expression est vraie (!=0) on effectue l'instruction1, puis on passe à la suite. Sinon, on effectuel'instruction 2 puis on passe à la suite (dans le cas sans else on passe directement à la suite).

Exercice (jeu) : modifier le jeu de l'exercice (do_while) en précisant au joueur à chaque essai si saproposition est trop grande ou trop petite. Cliquez ici pour une solution.

L'instruction d'un if peut être un autre if (imbriqué)

exemple :

if(c1) i1; else if (c2) i2; else if (c3) i3; else i4; i5;

si c1 alors i1 puis i5, sinon mais si c2 alors i2 puis i5, ... Si ni c1 ni c2 ni c3 alors i4 puis i5.

Le else étant facultatif, il peut y avoir une ambiguïté s'il y a moins de else que de if. En fait, un else serapporte toujours au if non terminé (c'est à dire à qui on n'a pas encore attribué de else) le plus proche. Onpeut aussi terminer un if sans else en l'entourant de {}.

exemple : if(c1) if(c2) i1; else i2; : si c1 et c2 alors i1, si c1 et pas c2 alors i2, si pas c1alors (quel que soit c2) rien.

if (c1) {if (c2) i1;} else i2; : si c1 et c2 alors i1, si c1 et pas c2 alors rien, si pas c1 alorsi2.

Switch - Case (brancher - dans le cas)

Cette structure de contrôle correspond à un "goto calculé".

structure :

switch (expression_entière) { case cste1:instructions case cste2:instructions ........

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (12 of 34) [21-11-2001 17:45:33]

Page 151: algo

case csteN:instructions default :instructions }

L'expression ne peut être qu'entière (char, int, long). L'expression est évaluée, puis on passe directement au"case" correspondant à la valeur trouvée. Le cas default est facultatif, mais si il est prévu il doit être ledernier cas.

exemple : fonction vérifiant si son argument c est une voyelle.

int voyelle(char c) { switch(c) { case 'a': case 'e': case 'i': case 'o': case 'u': case 'y':return(1); /* 1=vrai */ default :return(0); } }

Remarque : l'instruction break permet de passer directement à la fin d'un switch (au } ). Dans le cas deswitch imbriqués on ne peut sortir que du switch intérieur.

Exemple :

switch (a) { case 1:inst1;inst2;....;break; case 2:....;break; default:..... } /*endroit où l'on arrive après un break*/

Exercice (calcul) : faire un programme simulant une calculatrice 4 opérations. Cliquez ici pour unesolution.

Branchements inconditionnels

Quand on arrive sur une telle instruction, on se branche obligatoirement sur une autre partie du programme.Ces instructions sont à éviter si possible, car ils rendent le programme plus complexe à maintenir, le faitd'être dans une ligne de programme ne suffisant plus pour connaître immédiatement quelle instruction on afait auparavant, et donc ne permet plus d'assurer que ce qui est au dessus est correctement terminé. Il nefaut les utiliser que dans certains cas simples.

Break (interrompre)

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (13 of 34) [21-11-2001 17:45:33]

Page 152: algo

Il provoque la sortie immédiate de la boucle ou switch en cours. Il est limité à un seul niveau d'imbrication.

exemples :do {if(i= =0)break;....}while (i!=0); /* un while aurait été mieux */for (i=0;i<10;i++){....;if (erreur) break;} /* à remplacer parfor(i=0;(i<10)&&(!erreur);i++){...} */

Continue (continuer)

Cette instruction provoque le passage à la prochaine itération d'une boucle. Dans le cas d'un while ou dowhile, saut vers l'évaluation du test de sortie de boucle. Dans le cas d'un for on passe à l'expressiond'incrémentation puis seulement au test de bouclage. En cas de boucles imbriquées, permet uniquement decontinuer la boucle la plus interne.

exemple :for (i=0;i<10;i++) {if (i= =j) continue; ...... }peut être remplacé par :for (i=0;i<10;i++) if (i!=j) { ...... }

Goto (aller à)

La pratique des informaticiens a montré que l'utilisation des goto donne souvent des programmes nonmaintenables (impossibles à corriger ou modifier). Les problèmes qu'ils posent ont amené lesprogrammeurs expérimentés à ne s'en servir qu'exceptionnellement.

structure : goto label;

Label est un identificateur (non déclaré, mais non utilisé pour autre chose), suivi de deux points (:), etindiquant la destination du saut. Un goto permet de sortir d'un bloc depuis n'importe quel endroit. Mais onne peut entrer dans un bloc que par son { (qui créera proprement les variables locales du bloc).

{..... {..... goto truc; ..... } ..... truc: ..... }

Return (retourner)

Permet de sortir de la fonction actuelle (y compris main), en se branchant à son dernier }. Return permetégalement (et surtout) de rendre la valeur résultat de la fonction.

structure : return ou return(valeur)

exemple :

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (14 of 34) [21-11-2001 17:45:33]

Page 153: algo

int max(int a, int b) {if (a>b) return(a); else return(b);}

Exit (sortir)

Ceci n'est pas un mot clef du C mais une fonction disponible dans la plupart des compilateurs (définie parANSI, dans STDLIB.H). Elle permet de quitter directement le programme (même depuis une fonction). Onpeut lui donner comme argument le code de sortie (celui que l'on aurait donné à return dans main). Cettefonction libère la mémoire utilisée par le programme (variables + alloc) et ferme (sur beaucoup decompilateurs) les fichiers ouverts.

structure : exit(); ou exit(valeur);

Déclaration et stockage des variablesUne variable doit être définie par le programmateur dans une déclaration, où l'on indique le nom que l'ondésire lui donner, son type (int, float,...) pour que le compilateur sache combien de mémoire il doit luiréserver et les opérateurs qui peuvent lui être associés, mais aussi comment elle doit être gérée (visibilité,durée de vie,...).

Déclarations locales

Dans tout bloc d'instructions, avant la première instruction, on peut déclarer des variables. Elles seront alors"locales au bloc" : elles n'existent qu'à l'intérieur du bloc. Ces variables sont mises en mémoire dans unezone de type "pile" : quand, à l'exécution, on arrive sur le début du bloc ({), on réserve la mémoirenécessaire aux variables locales au sommet de la pile (ce qui en augmente la hauteur), et on les retire enquittant le bloc. L'intérêt consiste à n'utiliser, à un instant donné, que la quantité nécessaire de mémoire, quipeut donc resservir par après pour d'autres variables. Le désavantage (rarement gênant et pouvant êtrecontrecarré par la classe STATIC) est qu'en quittant le bloc (par } ou un branchement), et y entrant ànouveau plus tard (par son {), les variables locales ne sont plus nécessairement recréées au même endroit,et n'auront plus le même contenu. De plus la libération/réservation de la pile aura fait perdre un peu detemps. Par contre, lorsque l'on quitte temporairement un bloc (par appel à une fonction), les variableslocales restent réservées. La sortie d'un bloc par un branchement gère la libération des variables locales,mais seule l'entrée dans un bloc par son { gère leur création.

Exemple :

#include <stdio.h> int doubl(int b) {int c; c=2*b; b=0; return(c); } void main(void) { int a=5; printf("%d %d\n",doubl(a),a); }

A l'entrée du bloc main, création de a, à qui l'on donne la valeur 5. Puis appel de doubl : création de b ausommet de la pile, on lui donne la valeur de a. Puis entrée dans le bloc, création sur la pile de c, on lui

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (15 of 34) [21-11-2001 17:45:33]

Page 154: algo

donne la valeur b*2=10, on annule b (mais pas a), on rend 10 à la fonction appelante, et on libère lesommet de la pile (c et b n'existent plus) mais a reste (avec son ancienne valeur) jusqu'à la sortie de main.On affichera donc : 10 5.

Une variable locale est créée à l'entrée du bloc, et libérée à la sortie. Cette période est appelée sa durée devie. Mais pendant sa durée de vie, une variable peut être visible ou non. Elle est visible : dans le textesource du bloc d'instruction à partir de sa déclaration jusqu'au }, mais tant qu'une autre variable locale demême nom ne la cache pas. Par contre elle n'est pas visible dans une fonction appelée par le bloc (puisqueson code source est hors du bloc).

autre exemple :

void main(void); {int a=1; [1] {int b=2; [2] {int a=3; [3] fonction(a); [4] } [5] fonction(a); [6] } [7] } [8]int fonction (int b) [a] {int c=0; [b] c=b+8; [c] } [d]

analysons progressivement l'évolution de la pile au cours du temps (en gras : variable visible) :

[1] a=1[2] a=1 | b=2[3] a=1 | b=2 | a=3 : seul le a le plus haut est visible (a=3), l'autre vit encore (valeur 1 gardée) mais n'estplus visible.[4a] a=1 | b=2 | a=3 | b=3 : entrée dans la fonction, recopie de l'argument réel (a) dans l'argument formel(b). Mais a n'est plus visible.[4b] a=1 | b=2 | a=3 | b=3 | c=0[4c] a=1 | b=2 | a=3 | b=3 | c=11 : quand le compilateur cherche la valeur de b, il prend la plus haute de lapile donc 3 (c'est la seule visible), met le résultat dans le c le plus haut. L'autre b n'est pas modifié.[4d] a=1 | b=2 | a=3 : suppression des variables locales b et c du sommet de la pile[5] a=1 | b=2 : sortie de bloc donc libération de la pile[6a] a=1 | b=2 | b=1 : l'argument réel (a) n'est plus le même qu'en [4a][6b] a=1 | b=2 | b=1 | c=0[6c] a=1 | b=2 | b=1 | c=9[6d] a=1 | b=2 : suppression b et c[7] a=1[8] la pile est vide, on quitte le programme

Notez que la réservation et l'initialisation prennent un peu de temps à chaque entrée du bloc. Mais neprésumez jamais retrouver une valeur sur la pile, même si votre programme n'a pas utilisé la pile entre

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (16 of 34) [21-11-2001 17:45:33]

Page 155: algo

temps (surtout sur système multitâche ou avec mémoire virtuelle).

Une déclaration a toujours la structure suivante :

[classe] type liste_variables [initialisateur]; (entre [] facultatif)

Le type peut être simple (char, int, float,...) ou composé (tableaux, structures..., voir plus loin).

La liste_variables est la liste des noms des variables désirées, séparées par des virgules s'il y en a plusieurs.Chaque nom de la liste peut être précédés d'une *, ceci spécifiant un pointeur.

L'initialisateur est un signe =, suivi de la valeur à donner à la variable lors de sa création (à chaque entréedu bloc par exemple). La valeur peut être une constante, mais aussi une expression avec des constantesvoire des variables (visibles, déjà initialisées).

La classe peut être :

auto (ou omise, c'est la classe par défaut pour les variables locales) : la variable est créée à l'entréedu bloc (dans la pile) et libérée automatiquement à sa sortie (comme expliqué plus haut).

register : la variable est créée, possède la même durée de vie et visibilité qu'une classe auto, maissera placée dans un registre du (micro)processeur. Elle sera donc d'un accès très rapide. Si tous lesregistres sont déjà utilisés, la variable sera de classe auto. Mais le compilateur peut avoir besoin desregistres pour ses besoins internes ou pour les fonctions des bibliothèques, s'il n'en reste plus le gainpeut se transformer en perte. De plus les compilateurs optimisés choisissent de mettre en registre desvariables auto, et souvent de manière plus pertinente que vous. Mais le compilateur ne sait pas àl'avance quelles fonctions seront appelées le plus souvent, dans ce cas une optimisation manuellepeut être utile, par exemples dans le cas des éléments finis où une même instruction peut être répétéedes milliards de fois.

static : la variable ne sera pas dans la pile mais dans la même zone que le code machine duprogramme. Sa durée de vie sera donc celle du programme. Elle ne sera initialisée qu'une fois, audébut du programme, et restera toujours réservée. En retournant dans un bloc, elle possédera doncencore la valeur qu'elle avait à la précédente sortie. Sa visibilité reste la même (limitée au bloc). Unevariable statique permet en général un gain en temps d'exécution contre une perte en place mémoire.

Déclarations globales

Une déclaration faite à l'extérieur d'un bloc d'instructions (en général en début du fichier) est dite globale.La variable est stockée en mémoire statique, sa durée de vie est celle du programme. Elle est visible de sadéclaration jusqu'à la fin du fichier. Elle sera initialisée une fois, à l'entrée du programme (initialisée à 0 sipas d'autre précision). Le format d'une déclaration globale est identique à une déclaration locale, seules lesclasses varient.

Par défaut, la variable est publique, c'est à dire qu'elle pourra même être visible dans des fichiers compilésséparément (et reliés au link).

La classe static, par contre, rend la visibilité de la variable limitée au fichier actuel.

La classe extern permet de déclarer une variable d'un autre fichier (et donc ne pas lui réserver de mémoireici, mais la rendre visible). Elle ne doit pas être initialisée ici. Une variable commune à plusieurs fichiersdevra donc être déclarée sans classe dans un fichier (et y être initialisée), extern dans les autres.

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (17 of 34) [21-11-2001 17:45:33]

Page 156: algo

Toute fonction, pour pouvoir être utilisée, doit également être déclarée. Une déclaration de fonction ne peutêtre que globale, et connue des autres fonctions. Une déclaration de fonction est appelée "prototype". Leprototype est de la forme :

[classe] type_retourné nom_fonction(liste_arguments);

elle est donc identique à l'entête de la fonction mais :- est terminée par un ; comme toute déclaration- les noms des arguments n'ont pas besoin d'être les mêmes, il peuvent même être omis (les types desarguments doivent être identiques).

Sans précision de classe, la fonction est publique. Sinon, la classe peut être extern (c'est ce que l'on trouvedans les fichiers .H) ou static (visibilité limitée au fichier). Le prototype peut être utilisé pour utiliser unefonction du même fichier, mais avant de l'avoir définie (par exemple si l'on veut main en début du fichier).En général, lorsque l'on crée une bibliothèque (groupe de fonctions et variables regroupées dans un fichiercompilé séparément), on prépare un fichier regroupant toutes les déclarations extern, noté .H, qui pourraêtre inclus dans tout fichier utilisant la bibliothèque.

exemples de déclarations globales :int i,j; /* publiques, initialisées à 0 */static int k=1; /* privée, initialisée à 1 */extern int z; /* déclarée (et initialisée) dans un autre fichier */float produit(float,float); /* prototype d'une fonction définie plusloin dans ce fichier */extern void échange(int *a, int *b); /* prototype d'une fonction définiedans un autre fichier */

Avant la norme ANSI, le prototype n'existait pas. Une fonction non définie auparavant était considéréecomme rendant un int (il fallait utiliser un cast si ce n'était pas le cas).

Déclaration de type

La norme ANSI permet de définir de nouveaux types de variables par typedef.

structure : typedef type_de_base nouveau_nom;

Ceci permet de donner un nom à un type donné, mais ne crée aucune variable. Une déclaration typedef estnormalement globale et publique.

exemple :typedef long int entierlong; /* définition d'un nouveau type */entierlong i; /* création d'une variable i de type entierlong */typedef entierlong *pointeur; /* nouveau type : pointeur = pointeur d'entierlong */pointeur p; /* création de p (qui contiendra une adresse), peut être initialisé par =&i */

Remarque : Le premier typedef pouvait être remplacé par un #define mais pas le second.

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (18 of 34) [21-11-2001 17:45:34]

Page 157: algo

Fonctions

Définitions générales

Une fonction est définie par son entête, suivie d'un bloc d'instructions

entête : type_retourné nom_fonction(liste_arguments) (pas de ;)

Avant la norme ANSI, le type_retourné pouvait être omis si int. Désormais il est obligatoire, si la fonctionne retourne rien on indique : void.

La liste_arguments doit être typée (ANSI), alors qu'auparavant les types étaient précisés entre l'entête et lebloc :ANSI: float truc(int a, float b) {bloc}K&R: float truc(a,b) int a;float b; {bloc}

Si la fonction n'utilise pas d'arguments il faut la déclarer (ANSI) nom(void) ou (K&R) nom(). L'appel sefera dans les deux cas par nom() (parenthèses obligatoires).

Les arguments (formels) sont des variables locales à la fonction. Les valeurs fournies à l'appel de lafonction (arguments réels) y sont recopiés à l'entrée dans la fonction. Les instructions de la fonctions'exécutent du début du bloc ({) jusqu'à return(valeur) ou la sortie du bloc (}). La valeur retournée par lafonction est indiquée en argument de return.

exemple :

float produit(float a;float b) { float z; z=a*b; return(z); }

Récursivité, gestion de la pile

Une fonction peut s'appeler elle-même :

int factorielle(int i) { if (i>1) return(i*factorielle(i-1)); else return(1); }

analysons la pile en appelant factorielle(3) :

i=1

i=2 i=2 i=2

i=3 i=3 i=3 i=3 i=3

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (19 of 34) [21-11-2001 17:45:34]

Page 158: algo

(a) (b) (c) (d) (e)

(a) appel de factorielle(3), création de i, à qui on affecte la valeur 3. comme i>1 on calculei*factorielle(i-1) : i=3,i-1=2 on appelle factorielle(2)

(b) création i, affecté de la valeur 2, i>1 donc on appelle factorielle(1)●

(c) création de i, i=1 donc on quitte la fonction, on libère le pile de son sommet, on retourne où lafonction factorielle(1) a été appelée en rendant 1.

(d) on peut maintenant calculer i*factorielle(1), i (sommet de la pile) vaut 2, factorielle(1) vaut 1, onpeut rendre 2, puis on "dépile" i

(e) on peut calculer i*factorielle(2), i vaut 3 (sommet de la pile), factorielle(2) vaut 2 3*2=6, onretourne 6, la pile est vidée et retrouve sont état initial.

Attention, la récursivité est gourmande en temps et mémoire, il ne faut l'utiliser que si l'on ne sait pasfacilement faire autrement :

int factorielle(int i) { int result; for(result=1;i>1;i--) result*=i; return(result); }

Arguments passés par adresse

Imaginons la fonction :

void échange(int i;int j){int k;k=i;i=j;j=k;}

Lors d'un appel à cette fonction par échange(x,y), les variables locales i,j,k sont créées sur la pile, i vaut lavaleur de x, j celle de y. Les contenus de i et j sont échangés puis la pile est libérée, sans modifier x et y.Pour résoudre ce problème, il faut passer par des pointeurs. On utilisera les opérateurs unaires : & (adressede) et * (contenu de). Définissons donc la fonction ainsi :

void échange(int *i;int *j){int k;k=*i;*i=*j;*j=k;}

On appelle la fonction par échange(&x,&y); les deux arguments formels de la fonction (i et j) sont despointeurs sur des int, c'est à dire qu'à l'appel, on crée sur la pile des variables i et j pouvant contenir uneadresse, dans i on recopie l'argument réel qui et l'adresse de x, et l'adresse de y dans j. en entrant dans lebloc, on crée une variable locale k pouvant contenir un entier. Puis on met dans k non pas la valeur de imais le contenu pointé par i (donc ce qui se trouve à l'adresse marquée dans i, qui est l'adresse de x), doncle contenu de x. On place la valeur pointée par j (donc y) à l'adresse pointée par j (donc x). Puis on place lavaleur de k à l'adresse pointée par j (y). On a donc échangé x et y.

On a tout intérêt à essayer cet exemple en se fixant des adresses et des valeurs, et voir l'évolution descontenus des variables.

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (20 of 34) [21-11-2001 17:45:34]

Page 159: algo

En conclusion, pour effectuer un passage d'argument par adresse, il suffit d'ajouter l'opérateur & devantl'argument réel (à l'appel de la fonction), et l'opérateur * devant chaque apparition de l'argument formel,aussi bien dans l'entête que le bloc de la fonction.

La fonction main

Si on le désire, la fonction main peut rendre un entier (non signé) au système d'exploitation (sous MSDOS,on récupère cette valeur par ERRORLEVEL). Une valeur 0 signale en général une fin normale duprogramme, sinon elle représente un numéro d'erreur. L'arrivée sur le } final retourne la valeur 0, dans lecas où on n'a pas indiqué de return(code).

De même, le système d'exploitation peut transmettre des arguments au programme. La déclaration complètede l'entête de la fonction main est :

int main(int argc,char *argv[], char *env[])

Le dernier argument est optionnel).

On peut aussi utiliser char **argv, mais cela peut paraître moins clair. argc indique le nombre demots de la ligne de commande du système d'exploitation, argv est un tableau de pointeurs sur chaque motde la ligne de commande, env pointe sur les variables de l'environnement (sous MSDOS obtenues par SET,mais aussi très utilisées sous UNIX par env).

Si votre programme s'appelle COPIER, et que sous MSDOS vous ayez entré la commande COPIER TRUCMACHIN alors argc vaut 3, argv[0] pointe sur "COPIER", argv[1] sur "TRUC" et argv[2] sur "MACHIN".argv[3] vaut le pointeur NULL. env est un tableau de pointeurs sur les variables d'environnement, on n'enconnaît pas le nombre mais le dernier vaut le pointeur NULL.

Fonction retournant un pointeur et pointeur de fonction

type*fonc(arguments) est une fonction qui renvoie un pointeur.

exemple :

int *max(int tableau[], int taille) { int i,*grand; for(grand=tableau,i=1;i<taille;i++) if(tableau[i]>*grand) grand=tableau+i; return(grand); }

Cette fonction rend l'adresse du plus grand entier du tableau.

type (*fonc)(arguments) est un pointeur sur une fonction

exemple :

int max(int,int);int min(int,int);

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (21 of 34) [21-11-2001 17:45:34]

Page 160: algo

void main(void); { int (*calcul)(int,int); /* calcul est un pointeur donc une variable qui peut être locale */ char c; puts("utiliser max (A) ou min (I) ?"); do c=getchar(); while ((c!='A')&&(c!='I')); calcul=(c= ='A')?&max:&min; printf("%d\n",(*calcul)(10,20)); }int max(int a,int b) {return(a>b?a:b);}int min(int a,int b) {return(a<b?a:b);}

Cette fonctionnalité du C est assez peu utilisée, mais est nécessaire dans les langages orientés objets.

Les types de données du CNous allons définir les différents types de variables existantes en C. On verra les types scalaires (entiers,...)et les types agrégés (combinaisons de scalaires, tableaux par exemple).

Variables scalaires

On appelle variable scalaire une variable ne contenant qu'une seule valeur, sur laquelle on pourra faire uncalcul arithmétique. On possède trois types de base (char, int, float) que l'on peut modifier par 3spécificateurs (short, long, unsigned).

char : caractère (8 bits)

Une constante caractère est désignée entre apostrophes (simples quotes). 'a' correspond à un octet (alors que"a" à deux octets : 'a' et '\0', pour plus de détails voir le paragraphe chaînes de caractères). On peut définircertains caractères spéciaux, par le préfixe \ (antislash) :

\n nouvelle ligne●

\t tabulation●

\b backspace●

\r retour chariot (même ligne)●

\f form feed (nouvelle page)●

\' apostrophe●

\\ antislash●

\" double quote●

\0 nul●

\nombre en octal sur 3 chiffres (ou moins si non suivi d'un chiffre).●

\xnombre : en hexa●

Les char sont considérés dans les calculs comme des int (on considère leur code ASCII). Par défaut en C un

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (22 of 34) [21-11-2001 17:45:34]

Page 161: algo

char est signé donc peut varier de -128 à +127. Pour utiliser les caractères spéciaux du PC (non standard), ilvaut mieux utiliser des unsigned char (de 0 à 255). Mais le comme C fait les calculs modulo 256, çamarche presque pareil.

int : entier

Si l'on désire une taille précise, utiliser short int (16 bits) ou long int (32 bits). Sans précision, int donnerales programmes les plus rapides pour une machine donnée (int = short sur PC, mais long sur les stations 32bits). Par défaut, les int sont signés, mais on peut préciser unsigned int.

Désormais certains compilateurs considèrent short comme 16 bits, int comme 32 bits et long comme 64bits.

float : réel

Un flottant est un nombre stocké en deux parties, une mantisse et un exposant. La taille de la mantissedéfinit le nombre de chiffres significatifs, alors que la taille de l'exposant définit le plus grand nombreacceptable par la machine. Les opérations sur les réels sont plus lents que sur les entiers. Pour une additionpar exemple, il faut d'abord décaler la mantisse pour égaliser les exposants puis faire l'addition. Les réelssont toujours signés. On peut par contre utiliser le spécificateur long pour des réels avec une précisionaccrue. On peut également utiliser le nom double au lieu de long float. Certains compilateurs acceptentmême des long double (quadruple précision).

Tailles et plages

type taille (en bits) plage de valeurs

char 8 -128 à +127

unsigned char 8 0 à 255

short (short int) 16 -32768 à 32767

unsigned short 16 0 à 65535

long (long int) 32 -2.147.483.648 à 2.147.483.647

unsigned long 32 0 à 4.294.967.295

float 32 -3.4e38 à 3.4e38 (7 chiffres significatifs)

double (long float) 64 -1.7e308 à 1.7e308 (15 chiffres significatifs)

long double (non standard) 80 3.4E-4932 à 1.1E+4932 (19 chiffres signif.)

Conversions de type / cast

Dans les calculs, les char sont automatiquement transformés en int. Quand un opérateur possède desarguments de type différent, une transformation de type est effectuée automatiquement, suivant l'ordre :char -> int -> long -> float -> doublesigned -> unsigned

Attention la transformation n'est effectuée que le plus tard possible, si nécessaire. 5/2+3.5 donnera donc5.5. De plus les opérations arithmétiques sont toujours effectuées sur des long ou double, pour une

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (23 of 34) [21-11-2001 17:45:34]

Page 162: algo

précision maximale quels que soient les résultats intermédiaires (voir exemples au chapitre expressionsarithmétiques).

On peut forcer une transformation en utilisant le cast, qui est un opérateur unaire. La syntaxe est :(type_résultat) valeur_à_transformer

exemple : {float x;int a=5; x=(float)a;}

Un cast transformant un réel en entier prendra la partie entière. Cette transformation doit être explicite, elleest impossible implicitement. Pour obtenir l'entier le plus proche , utiliser(int)(réel_positif+0.5).

Il faut bien noter que le cast n'est une opération de transformation que pour les types scalaires, pour tous lesautres types, le cast ne permet que de faire croire au compilateur que la variable est d'un autre type que cequ'il attendait, pour qu'il n'émette pas de message d'erreur (à utiliser avec grande prudence).

Enumérations

On peut définir un nouveau type (d'entiers) sous la forme :[classe] enum nomdutype {liste_valeurs} [liste_variables]; ([] facultatifs)

exemple : enum jour {lundi, mardi, mercredi, jeudi, vendredi, samedi,dimanche};

On a créé un nouveau type. toute variable de type jour pourra valoir soit lundi, soit mardi, etc... On peutdirectement mettre la liste des variables à créer (entre le "}" et le ";"), ou indiquer :enum nomdutype liste_variables;

exemple : enum jour aujourd_hui=mardi;)

En fait le type jour est un type int, avec lundi=0, mardi=1,... On peut donc faire toutes les opérationsentières (aujourd_hui++ par exemple). Il n'y a aucun test de validité (dimanche+1 donne 7). Ceci permet derendre les programmes plus clairs. On obtiendrait un résultat équivalent avec #define. Attention, printfaffichera un entier, mais on peut faire:

char *nom[7]={"lundi", "mardi", "mercredi", "jeudi", "vendredi","samedi"," dimanche"};puis printf("%s",nom[aujourd_hui]);

On peut aussi prévoir une codification non continue :enum truc {a=4,b,c,d=2,e,f} : d=2,e=3,f=a=4,b=5,c=6

En utilisant typedef, on n'a pas besoin de répéter enum dans la déclaration de variables :typedef enum {coeur,carreau,pique,trèfle}couleurs;couleurs i,j,k;

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (24 of 34) [21-11-2001 17:45:34]

Page 163: algo

Tableaux

Tableaux unidimensionnels

Un tableau est un regroupement, dans une même variable, de plusieurs variables simples, toutes de mêmetype.

déclaration : [classe] type nom [nombre_d'éléments];

exemple : int tab[10];

Ceci réserve en mémoire un espace contigu pouvant contenir 10 entiers. Le premier est tab[0], jusqu'àtab[9]. Attention, en utilisant tab[10] ou plus, aucune erreur ne sera signalée et vous utiliserez une partie demémoire qui a certainement été réservée pour autre chose. Il est possible de définir un tableau de n'importequel type de composantes (scalaires, pointeurs, structures et même tableaux). Il est également possible dedéfinir un type tableau par typedef :typedef float vecteur[3];vecteur x,y,z;

On peut aussi initialiser un tableau. Dans ce cas la dimension n'est pas nécessaire. Mais si elle est donnée,et est supérieure au nombre de valeurs données, les suivantes seront initialisées à 0 :vecteur vect0={0,0,0};int chiffres[]={0,1,2,3,4,5,6,7,8,9};int tableau[20]={1,2,3}; /* les 17 autres à 0 */

On peut également déclarer un tableau sans en donner sa dimension. Dans ce cas là le compilateur ne luiréserve pas de place, elle aura du être réservée autre part (par exemple tableau externe ou argument formeld'une fonction).

Exercice (moyenne) : Ecrire le programme qui lit une liste de Nb nombres, calcule et affiche la moyennepuis l'écart entre chaque note et cette moyenne. Cliquez ici pour une solution.

Tableaux et pointeurs / arithmétique des pointeurs

En déclarant, par exemple, int TAB[10]; l'identificateur TAB correspond en fait à l'adresse du débutdu tableau. Les deux écritures TAB et &TAB[0] sont équivalentes (ainsi que TAB[0] et *TAB). On définitl'opération d'incrémentation pour les pointeurs par TAB+1=adresse de l'élément suivant du tableau.L'arithmétique des pointeurs en C a cette particularité que l'opération dépend du type de variable pointée,ajouter 1 consistant à ajouter à l'adresse la taille de l'objet pointé. On définit donc l'addition(pointeur+entier): TAB+i=&TAB[i], la soustraction (pointeur - entier), mais également la soustraction(pointeur - pointeur) qui donne un nombre d'éléments. Les opérations de comparaisons entre pointeurs sontdonc également possibles.

Déclarons : int TAB[10],i,*ptr;

Ceci réserve en mémoire- la place pour 10 entiers, l'adresse du début de cette zone est TAB,- la place pour l'entier i,- la place pour un pointeur d'entier (le type pointé est important pour définir l'addition).

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (25 of 34) [21-11-2001 17:45:34]

Page 164: algo

Analysons les instructions suivantes :

ptr=TAB; /*met l'adresse du début du tableau dans ptr*/for(i=0;i<10;i++) { printf("entrez la %dième valeur :\n",i+1); /* +1 pour commencer à 1*/ scanf("%d",ptr+i); /* ou &TAB[i] puisque scanf veut une adresse*/ }puts("affichage du tableau");for(ptr=TAB;ptr<TAB+10 /* ou &TAB[10] */;ptr++) printf("%d ",*ptr);puts(" ");/* attention actuellement on pointe derrière le tableau ! */ptr-=10; /* ou plutôt ptr=TAB qui lui n'a pas changé */printf("%d",*ptr+1); /* affiche (TAB[0])+1 */printf("%d",*(ptr+1)); /* affiche TAB[1] */printf("%d",*ptr++); /* affiche TAB[0] puis pointe sur TAB[1] */printf("%d",(*ptr)++); /* affiche TAB[1] puis ajoute 1 à TAB[1]*/

TAB est une "constante pointeur", alors que ptr est une variable (donc TAB++ est impossible). Ladéclaration d'un tableau réserve la place qui lui est nécessaire, celle d'un pointeur uniquement la place d'uneadresse.

Pour passer un tableau en argument d'une fonction, on ne peut que le passer par adresse (recopier le tableauprendrait de la place et du temps).

exemple utilisant ces deux écritures équivalentes :

#include <stdio.h>void annule_tableau(int *t,int max) { for(;max>0;max--)*(t++)=0; }void affiche_tableau(int t[], int max) { int i; for(i=0;i<max;i++) printf("%d : %d\n",i,t[i]); }void main(void) { int tableau[10]; annule_tableau(tableau,10); affiche_tableau(tableau,10); }

Exercice (rotation) : Ecrire un programme qui lit une liste de Nb nombres, la décale d'un cran vers le haut

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (26 of 34) [21-11-2001 17:45:34]

Page 165: algo

(le premier doit se retrouver en dernier), l'affiche puis la décale vers le bas. On pourra décomposer leprogramme en fonctions. Cliquez ici pour une solution.

Exercice (classer) : Classer automatiquement un tableau de Nb entiers puis l'afficher dans l'ordre croissantpuis décroissant. On pourra utiliser des fonctions de l'exercice précédent. On pourra créer un (ou plusieurs)tableau temporaire (donc local). Si vous vous en sentez la force, prévoyez le cas de valeurs égales. Cliquezici pour une solution.

Chaînes de caractères

En C, comme dans les autres langages, certaines fonctionnalités ont été ajoutées aux tableaux dans le casdes tableaux de caractères. En C, on représente les chaînes par un tableau de caractères, dont le dernier estun caractère de code nul (\0). Une constante caractères est identifiée par ses délimiteurs, les guillemets "(double quote).

exemples :puts("salut");char mess[]="bonjour"; /* évite de mettre ={'b','o',..,'r',\0} */puts (mess);

mess est un tableau de 8 caractères (\0 compris). On peut au cours du programme modifier le contenu demess, à condition de ne pas dépasser 8 caractères (mais on peut en mettre moins, le \0 indiquant la fin de lachaîne). Mais on peut également initialiser un pointeur avec une chaîne de caractères :char *strptr="bonjour";

Le compilateur crée la chaîne en mémoire de code (constante) et une variable strptr contenant l'adresse dela chaîne. Le programme pourra donc changer le contenu de strptr (et donc pointer sur une autre chaîne),mais pas changer le contenu de la chaîne initialement créée.

Exercice (chaînes) : écrire un programme qui détermine le nombre et la position d'une sous-chaîne dansune chaîne (exemple ON dans FONCTION : en position 1 et 6). Cliquez ici pour une solution.

Bibliothèques de fonctions pour tableaux et chaînes

Toutes les fonctions standard d'entrée / sortie de chaînes considèrent la chaîne terminée par un \0, c'estpourquoi en entrée elles rajoutent automatiquement le \0 (gets, scanf), en sortie elles affichent jusqu'au \0(puts, printf). La bibliothèque de chaînes (inclure string.h) possède des fonctions utiles à la manipulation dechaînes :

int strlen(chaîne) donne la longueur de la chaîne (\0 non compris)●

char *strcpy(char *destination,char *source) recopie la source dans ladestination, rend un pointeur sur la destination

char *strncpy(char *destination,char *source,int longmax) idem strcpymais s'arrête au \0 ou longmax (qui doit comprendre le \0)

char *strcat(char *destination,char *source) recopie la source à la suite de ladestination, rend un pointeur sur la destination

char *strncat(char *destination,char *source,int longmax) idem●

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (27 of 34) [21-11-2001 17:45:34]

Page 166: algo

int strcmp(char *str1,char*str2) rend 0 si str1= =str2, <0 si str1<str2, >0 si str1>str2.Idem strncmp

Des fonctions similaires, mais pour tous tableaux (sans s'arrêter au \0) sont déclarées dans mem.h. Lalongueur est à donner en octets (on peut utiliser sizeof) :

int memcmp(void *s1,void *s2,int longueur);●

void *memcpy(void *dest,void *src,int longueur);●

On possède également des fonctions de conversions entre scalaires et chaînes, déclarées dans stdlib.h

int atoi(char *s) traduit la chaîne en entier (s'arrête au premier caractère impossible, 0 si erreur dès lepremier caractère)

de même atol et atof●

Dans ctype.h, on trouve des fonctions utiles (limitées au caractères) :

int isdigit(int c) rend un entier non nul si c'est un chiffre ('0' à '9'), 0 sinon.●

de même : isalpha (A à Z et a à z, mais pas les accents), isalnum (isalpha||isdigit), isascii (0 à 127),iscntrl (0 à 31), islower (minuscule), isupper, isspace (blanc, tab, return...), isxdigit (0 à 9,A à F,a àf)...

int toupper(int c) rend A à Z si c est a à z, rend c sinon. Egalement tolower●

Allocation dynamique de mémoire

La taille déclarée d'un tableau est définie à la compilation. Dans le cas d'une taille inconnue à l'avance, ilfaut donc surdimensionner le tableau (et donc réserver des mémoires dont on ne servira que rarement, audépends d'autres variables ou tableaux. En C, le lien entre les tableaux et pointeurs permet de réserver, lorsde l'exécution, une zone de mémoire contiguë, de la taille désirée (mais pas plus). Il faut d'abord déclarerune variable pointeur qui contiendra l'adresse du début du tableau. A l'exécution, lorsque l'on connaît lataille désiré, on peut réserver une zone mémoire (dans la zone appelée "tas" ou "heap") par les fonctions :

- void *malloc(int taille) : réserve une zone mémoire contiguë de taille octets, et retourne un pointeur sur ledébut du bloc réservé. Retourne le pointeur NULL en cas d'erreur (en général car pas assez de mémoire).

- void *calloc(int nb, int taille) : équivalent à malloc(nb*taille).

exemple :

float *tab; int nb; puts("taille désirée ?"); scanf("%d",&nb); tab=(float*)calloc(nb,sizeof(float));

malloc et calloc nécessitent un cast pour que le compilateur ne signale pas d'erreur.

- void free(void *pointeur) libère la place réservée auparavant par malloc ou calloc. Pointeur est l'adresseretournée lors de l'allocation. En quittant proprement le programme, la mémoire allouée estautomatiquement restituée même si on omet d'appeler free.

- void *realloc(void *pointeur,int taille) essaie, si possible, de réajuster la taille d'un bloc de mémoire déjàalloué (augmentation ou diminution de taille). Si nécessaire, le bloc est déplacé et son contenu recopié. En

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (28 of 34) [21-11-2001 17:45:34]

Page 167: algo

retour, l'adresse du bloc modifié (pas nécessairement la même qu'avant) ou le pointeur NULL en casd'erreur.

Ces fonctions sont définies dans stdlib.h ou alloc.h (suivant votre compilateur).

Une erreur fréquente consiste à "perdre" l'adresse du début de la zone allouée (par tab++ par exemple) etdonc il est alors impossible d'accéder au début de la zone, ni de la libérer.

Tableaux multidimensionnels

On peut déclarer par exemple int tab[2][3] : matrice de 2 lignes de 3 éléments. Un tableau peut êtreinitialisé : int t[2][3]={{1,2,3},{4,5,6}} mais cette écriture est équivalente à {1,2,3,4,5,6}, car il place dansl'ordre t[0][0],t[0][1],t[0][2],t[1][0],t[1][1],t[1][2], c'est à dire ligne après ligne. Dans un tableaumultidimensionnel initialisé, seule la dimension la plus à gauche peut être omise (ici int t[][3]={...} étaitpossible).

t correspond à l'adresse &t[0][0], mais t[1] est aussi un tableau (une ligne), donc désigne l'adresse &t[1][0].En fait, une matrice est un tableau de lignes. On peut expliciter cela par typedef :typedef int ligne[3];typedef ligne matrice[2];

En utilisant pointeurs et allocation dynamique, pour gérer un tableau de NBLIG lignes de NBCOLéléments, , on peut :

soit créer une matrice complète : allocation par t=malloc(NBLIG* NBCOL* sizeof(élément)), accèsà l'élément l,c par *(t+l*NBCOL+c).

soit créer un tableau de NBLIG pointeurs de lignes, puis chaque ligne séparément. Ceci permet uneoptimisation si les lignes n'ont pas toutes la même longueur (traitement de textes par exemple) maisaussi de manipuler facilement les lignes (exemple : échanger deux lignes sans recopier leur contenu).Cette méthode est plus rapide que la précédente, car les adresses de chaque début de ligne sontimmédiatement connues, sans calcul.

soit utiliser des pointeurs de pointeurs (même principe que le cas précédent, mais remplacement dutableau de pointeurs (dimension prévue à l'avance) par une allocation dynamique.

Exercice (matrices) : faire le calcul de multiplication d'une matrice (M lignes, L colonnes) par une matrice(L,N) : résultat (M,N).Cliquez ici pour une solution.

Exercice (déterminant) : écrire un programme qui calcule le déterminant d'une matrice carrée (N,N),sachant qu'il vaut la somme (sur chaque ligne) de l'élément de la ligne en 1ère colonne par le déterminantde la sous-matrice obtenue en enlevant la ligne et la 1ère colonne (en changeant le signe à chaque fois). Ledéterminant d'une matrice (1,1) est sont seul élément. On utilisera bien évidement la récursivité. Il existe(heureusement) d'autres méthodes plus rapides. Cliquez ici pour une solution.

Structures et unionsDans un tableau, tous les constituants doivent être du même type. Ce n'est pas le cas des structures, qui sontdes variables composées de plusieurs variables (ou CHAMPS) de types différents. Chaque champ n'est plus

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (29 of 34) [21-11-2001 17:45:34]

Page 168: algo

désigné par un numéro comme dans un tableau, mais par un identificateur.

Déclaration

déclaration : struct nom_type {déclaration des champs} liste_variables ;

exemple :

struct identite { char nom[30]; char prenom[20]; int age; }jean,jacques,groupe[20];

Toute variable de type identité (jean, jacques, groupe[i]) comporte trois champs : nom, prenom et age.sizeof(jacques) retournera 52. Les champs peuvent être de n'importe quel type valable (scalaires, tableaux,pointeurs...), y compris une structure (à condition d'être déclaré plus haut). nom_type et liste_variables sontoptionnels mais au moins l'un des deux doit être présent. Les noms de champs ont une portée limitée à lastructure (c'est à dire qu'un autre objet peut avoir le même nom, s'il n'est pas cité dans cette structure).Nom_type (ici identite) est le nom d'un nouveau type, il peut être utilisé plus loin pour déclarer d'autresvariables, voire d'autres types:struct identite lui;struct prisonnier {long numero; struct identite id;} moi;

Il est également possible d'utiliser typedef, et (pas sur tous les compilateurs) d'initialiser une structure :typedef struct {int jour;int mois;int année;}date;date aujourdhui={24,12,1992}; /*évite de répéter struct*/

Utilisation

On accède à une composante par NOM_VARIABLE . NOM_CHAMP , par l'opérateur unaire "."

gets(jean.nom);printf("initiales : %c %c\n",lui.nom[0],lui.prenom[0]);printf("nom %s \n",groupe[10].nom);scanf("%d",&moi.id.age);

Une composante d'enregistrement s'utilise comme une variable du même type (avec les mêmes possibilitésmais aussi les mêmes limitations). Depuis la norme ANSI, on peut utiliser l'affectation pour des structures(recopie de tous les champs), ainsi que le passage des structures en arguments de fonction passés parvaleur. Sur les compilateurs non ANSI, il faut utiliser des pointeurs.

On utilise des pointeurs de structures comme des pointeurs sur n'importe quel autre type. L'opérateur ->permet une simplification d'écriture (il signifie champ pointé) :date *ptr;ptr=(struct date *)malloc(sizeof(date));*ptr.jour=14;ptr->mois=7;

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (30 of 34) [21-11-2001 17:45:35]

Page 169: algo

Champs de bits

En ne définissant que des champs entiers (signés ou non), on peut définir la taille (en bits) de chaquechamp. Il suffit pour cela de préciser, derrière chaque champ, sa taille après un ":".struct état{unsigned ReadOnly:1;int Crc:6;}

Les champs sont créés à partir des bits de poids faible. Le nom du champ est optionnel (dans le cas dechamps réservés, non utilisés par le programme). Les champs n'ont alors pas d'adresse (impossible d'utiliser& sur un champ). On utilise ces structures comme les autres.

Unions

déclaration : union nom_type {déclaration des champs} liste_variables ;

Les différents champs commenceront tous à la même adresse (permet d'utiliser des variables pouvant avoirdes types différents au cours du temps, mais un seul à un instant donné). Les champs peuvent être de touttype, y compris structures. On les utilise comme les structures, avec les opérateurs "." et "->".

Exercice (tel) A l'aide d'un tableau de personnes (nom, prénom, numéro dans la rue, rue, code postal, ville,numéro de téléphone), faire un programme de recherche automatique de toutes les informations sur lespersonnes répondant à une valeur d'une rubrique donnée (tous les PATRICK , tous ceux d'Obernai,travaillant à l'IPST, etc...). On suppose que le tableau est déjà initialisé. Cliquez ici pour une solution.

Structures chaînées

Le principal problème des données stockées sous forme de tableaux est que celles-ci doivent être ordonnées: le "suivant" doit toujours être stocké physiquement derrière. Imaginons gérer une association. Un tableaucorrespond à une gestion dans un cahier : un adhérent par page. Supposons désirer stocker les adhérents parordre alphabétique. Si un nouvel adhérent se présente, il va falloir trouver où l'insérer, gommer toutes lespages suivantes pour les réécrire une page plus loin, puis insérer le nouvel adhérent. Une solution un peuplus simple serait de numéroter les pages, entrer les adhérents dans n'importe quel ordre et disposer d'unindex : un feuille où sont indiqués les noms, dans l'ordre, associés à leur "adresse" : le numéro de page.Toute insertion ne nécessitera de décalages que dans l'index. Cette méthode permet l'utilisation de plusieursindex (par exemple un second par date de naissance). La troisième solution est la liste chaînée : les pagessont numérotées, sur chaque page est indiquée la page de l'adhérent suivant, sur le revers de couverture onindique l'adresse du premier. L'utilisation d'une telle liste nécessite un véritable "jeu de piste", maisl'insertion d'un nouvel adhérent se fera avec le minimum d'opérations.

Appliquons cela , de manière informatique, à une liste d'entiers, avec pour chaque valeur l'adresse (numérode mémoire) du suivant :

Si l'on veut insérer une valeur dans la liste, les modifications à apporter sont minimes :

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (31 of 34) [21-11-2001 17:45:35]

Page 170: algo

En C on définira un type structure regroupant une valeur entière et un pointeur :struct page {int val; struct page *suivant; };

Un pointeur (souvent global) nous indiquera toujours le début de la liste:struct page *premier;

Au fur et à mesure des besoins on se crée une nouvelle page :nouveau=(struct page *)malloc(sizeof(struct page));

En n'oubliant pas de préciser le lien avec le précédent :precedent->suivant=nouveau;

le dernier élément ne doit pas pointer sur n'importe quoi, on choisit généralement soit le pointeur NULL,soit le premier (la liste est dite bouclée).

exemple :

#include <stdio.h>#include <conio.h>#include <ctype.h>#include <alloc.h> /*ou stdlib.h*/struct page {int val; struct page *suivant; };struct page *premier;

int encore(void) /* demande si on en veut encore*/ { printf("encore (O/N) ? "); return(toupper(getche())= ='O'); }void lecture(void) { struct page *precedent,*nouveau; premier=(struct page *)malloc(sizeof(struct page)); puts("entrez votre premier entier"); scanf("%d",&premier->val); precedent=premier; while (encore()) { nouveau=(struct page *)malloc(sizeof(struct page)); precedent->suivant=nouveau; precedent=nouveau;

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (32 of 34) [21-11-2001 17:45:35]

Page 171: algo

puts("\nentrez votre entier"); scanf("%d",&nouveau->val); } precedent->suivant=NULL; }void affiche(struct page *debut) { printf("\nliste : "); while(debut!=NULL) { printf("%d ",debut->val); debut=debut->suivant; } printf("\n"); }void main(void) { lecture(); affiche(premier); }

Exercice (liste) : modifier la fonction lecture ci-dessus pour que la liste soit stockée dans l'ordre inverse deson introduction (chaque nouvel élément est placé devant la liste déjà existante).Cliquez ici pour une solution de cet exercice (et du suivant).

Les modifications sont aisées, une fois que l'on a repéré l'endroit de la modification. Exemple : suppressiond'un élément :

void suppression(void) { struct page *actu,*prec; actu=premier; while (actu!=NULL) { printf("\nvaleur : %d - supprimer celui_ci (O/N) ? ", actu->val); if (toupper(getche())= ='O') { if(actu= =premier)premier=actu->suivant; else prec->suivant=actu->suivant; free(actu); break; } else { prec=actu; actu=prec->suivant;

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (33 of 34) [21-11-2001 17:45:35]

Page 172: algo

} } }

Exercice (insertion) : ajouter au programme précédent une procédure d'insertion d'une valeur dans la liste.La solution de l'exercice précédent contient également cette insertion

Ce type de données (structure pointant sur un même type) est utilisé dans d'autres cas. Par exemple, pourreprésenter un arbre, il suffit pour chaque élément de connaître l'adresse de chaque fils :

Remarque : si le nombre de fils n'est pas constant, on a intérêt à stocker uniquement le fils aîné, ainsi que lefrère suivant(voir partie algorithmique et structures de données).

Langage C - La syntaxe du C

http://www-ipst.u-strasbg.fr/pat/program/tpc04.htm (34 of 34) [21-11-2001 17:45:35]

Page 173: algo

Les fichiers de donnéesFichiers bruts●

Fichiers bufférisés●

Les données stockées en mémoire sont perdues dès la sortie du programme. Les fichiers sur supportmagnétique (bande, disquette, disque) sont par contre conservables, mais au prix d'un temps d'accès auxdonnées très supérieur. On peut distinguer les fichiers séquentiels (on accède au contenu dans l'ordre dustockage) ou à accès direct (on peut directement accéder à n'importe quel endroit du fichier). Les fichierssont soit binaires (un float sera stocké comme il est codé en mémoire , d'où gain de place maisincompatibilité entre logiciels), soit formaté ASCII (un float binaire sera transformé en décimal puis onécrira le caractère correspondant à chaque chiffre). Les fichiers étant dépendants du matériel, ils ne sontpas prévus dans la syntaxe du C mais par l'intermédiaire de fonctions spécifiques.

Fichiers brutsC'est la méthode la plus efficace et rapide pour stocker et récupérer des données sur fichier (mais aussi lamoins pratique). On accède au fichier par lecture ou écriture de blocs (groupe d'octets de taille définie parle programmeur). C'est au programmeur de préparer et gérer ses blocs. On choisira en général une taillede bloc constante pour tout le fichier, et correspondant à la taille d'un enregistrement physique (secteur,cluster...). On traite les fichiers par l'intermédiaire de fonctions, prototypées dans stdio.h (ouverture etfermeture) et dans io.h (les autres), disponibles sur la plupart des compilateurs (DOS, UNIX) mais passtandardisés.

La première opération à effectuer est d'ouvrir le fichier. Ceci consiste à définir le nom du fichier(comment il s'appelle sous le système) et comment on veut l'utiliser. On appelle pour cela la fonction :

int open(char *nomfic, int mode);

nomfic pointe sur le nom du fichier (pouvant contenir un chemin d'accès). Mode permet de définircomment on utilisera le fichier. On utilise pour cela des constantes définies dans fcntl.h :

O_RDONLY lecture seule, O_WRONLY écriture seule, O_RDWR lecture et écriture. On peut combinercet accès avec d'autres spécifications, par une opération OU (|) :

O_APPEND positionnement en fin de fichier (permet d'augmenter le fichier), O_CREAT crée le fichiers'il n'existe pas, au lieu de donner une erreur, sans effet s'il existe (rajouter en 3ème argument S_IREAD |S_IWRITE | S_IEXEC déclarés dans stat.h pour être compatible UNIX et créer un fichier lecture/écriture/ exécution autorisée, seul S_IWRITE utile sur PC), O_TRUNC vide le fichier s'il existait,O_EXCL renvoie une erreur si fichier existant (utilisé avec O_CREAT).

Langage C - Les fichiers de données

http://www-ipst.u-strasbg.fr/pat/program/tpc05.htm (1 of 5) [21-11-2001 17:45:46]

Page 174: algo

Deux modes spécifiques au PC sont disponibles : O_TEXT change tous les \n en paire CR/LF etinversement, O_BINARY n'effectue aucune transformation.

La fonction rend un entier positif dont on se servira par la suite pour accéder au fichier (HANDLE), ou -1en cas d'erreur. Dans ce cas, le type d'erreur est donné dans la variable errno, détaillée dans errno.h.

On peut ensuite, suivant le mode d'ouverture, soit lire soit écrire un bloc (l'opération est alors directementeffectuée sur disque) :

int write(int handle, void *bloc, unsigned taille);

On désigne le fichier destination par son handle (celui rendu par open), l'adresse du bloc à écrire et lataille (en octets) de ce bloc. Le nombre d'octets écrits est retourné, -1 si erreur.

int read(int handle, void *bloc, unsigned taille);

lit dans le fichier désigné par son handle, et le met dans le bloc dont on donne l'adresse et la taille. Lafonction retourne le nombre d'octets lus (<=taille, <si fin du fichier en cours de lecture, 0 si on était déjàsur la fin du fichier, -1 si erreur).

int eof(int handle)

dit si on se trouve (1) ou non (0) sur la fin du fichier.

Lorsque l'on ne se sert plus du fichier, il faut le fermer (obligatoire pour que le fichier soit utilisable parle système d'exploitation, entre autre mise à jour de sa taille :

int close(int handle)

fermeture, rend 0 si ok, -1 si erreur.

Le fichier peut être utilisé séquentiellement (le "pointeur de fichier" est toujours placé derrière le blocque l'on vient de traiter, pour pouvoir traiter le suivant). Pour déplacer le pointeur de fichier en n'importeque autre endroit, on appelle la fonction :

long lseek(int handle, long combien, int code);

déplace le pointeur de fichier de combien octets, à partir de : début du fichier si code=0, position actuellesi 0, fin du fichier si 2. La fonction retourne la position atteinte (en nb d'octets), -1L si erreur.

long filelength(int handle);

rend la taille d'un fichier (sans déplacer le pointeur de fichier).

Exemple : copie de fichier (les noms de fichiers sont donnés en argument du programme)

#include <stdio.h>#include <fcntl.h>#include <io.h>#include <sys\stat.h>#define taillebloc 1024int main(int argc,char *argv[])

Langage C - Les fichiers de données

http://www-ipst.u-strasbg.fr/pat/program/tpc05.htm (2 of 5) [21-11-2001 17:45:46]

Page 175: algo

{ int source, destination; char buffer[taillebloc]; int nb_lus,nb_ecrits; if (argc!=3) {puts("erreur arguments");return(1);} if((source=open(argv[1],O_RDONLY|O_BINARY))<0) {puts("erreur ouverture");return(2);} if((destination=open(argv[2], O_WRONLY| O_CREAT| O_TRUNC| O_BINARY, S_IREAD| S_IWRITE| S_IEXEC))<0) {puts("erreur ouverture");return(2);} do { nb_lus=read(source,(char *)buffer,taillebloc); if (nb_lus>0) nb_ecrits= write(destination,(char*)buffer, nb_lus); } while ((nb_lus==taillebloc)&&(nb_ecrits>0)); close(source); close(destination); return(0); }

Fichiers bufférisésLes opérations d'entrée / sortie sur ces fichiers se font par l'intermédiaire d'un "buffer" (bloc en mémoire)géré automatiquement. Ceci signifie qu'une instruction d'écriture n'impliquera pas une écriture physiquesur le disque mais dans le buffer, avec écriture sur disque uniquement quand le buffer est plein.

Les fichiers sont identifiés non par un entier mais par un pointeur sur une structure FILE (définie par untypedef dans stdio.h). Les fonctions disponibles (prototypées dans stdio.h) sont :

FILE *fopen(char *nomfic, char *mode) : ouvre le fichier, suivant le mode : r (lecture seule), w(écriture, si le fichier existe il est d'abord vidé), a (append : écriture à la suite du contenu actuel, créationsi inexistant), r+ (lecture et écriture, le fichier doit exister), w+ (lecture et écriture mais effacement audépart du fichier si existant), a+ (lecture et écriture, positionnement en fin de fichier si existant, créationsinon). Sur PC, on peut rajouter t ou b au mode pour des fichiers texte (gestion des CR/LF, option pardéfaut) ou binaires, ou le définir par défaut en donnant à la variable _fmode la valeur O_TEXT ouO_BINARY. fopen rend un identificateur (ID) qui nous servira pour accéder au fichier. En cas d'erreur,le pointeur NULL est retourné, le type d'erreur est donné dans une variable errno, détaillée dans errno.h.La fonction void perror(char *s mess) affichera le message correspondant à l'erreur, en général on luidonne le nom du fichier.

int fread(void *bloc, int taille, int nb, FILE *id) : lit nb éléments dont on donne la taille unitaire enoctets, dans le fichier désigné par id, le résultat étant stocké à l'adresse bloc. La fonction rend le nombred'éléments lus (<nb si fin de fichier), 0 si erreur.

int fwrite(void *bloc, int taille, int nb, FILE *id) : écriture du bloc sur fichier, si le nombre rendu est

Langage C - Les fichiers de données

http://www-ipst.u-strasbg.fr/pat/program/tpc05.htm (3 of 5) [21-11-2001 17:45:46]

Page 176: algo

différent de nb, il y a eu erreur (tester ferror ou errno).

int fclose(FILE *id) : ferme le fichier, en y recopiant le reste du buffer si nécessaire. Cette fonction estobligatoire pour être sur d'avoir l'intégralité des données effectivement transférées sur le disque.Retourne 0 si tout s'est bien passé.

int fflush(FILE *id) : transfère effectivement le reste du buffer sur disque, sans fermer le fichier (àappeler par exemple avant une instruction qui risque de créer un "plantage").

int fseek(FILE *id, long combien, int code) : déplace le pointeur de fichier de combien octets, à partirde : début du fichier (mode=0), position actuelle (mode=1) ou fin du fichier (mode=2). Retourne 0 si toutc'est bien passé. Cette fonction n'est utilisable que si l'on connaît la taille des données dans le fichier(impossible d'aller directement à une ligne donnée d'un texte si on ne connaît pas la longueur de chaqueligne).

int feof(FILE *id) dit si on est en fin de fichier ou non (0).

Les fichiers bufférisés permettent aussi des sorties formatées :

au niveau caractère : char fgetc(FILE *id), char fputc(char c, FILE *id), et même char ungetc(charc, FILE *id) qui permet de "reculer" d'un caractère. Cette fonction correspond donc à{fseek(id,-1,1);c=fgetc(id)}.

au niveau chaîne de caractères :

char *fgets(char *s, int max, FILE *id) : lit une chaîne en s'arrêtant au \n ou à max-1 caractères lus,résultat dans la zone pointée par s, et retour du pointeur s ou NULL si erreur.

char fputs(char *s, FILE *id) : écrit la chaîne dans le fichier sans ajouter de \n, rend le dernier caractèreécrit ou EOF si erreur.

int fprintf(FILE *id, char *format, listearguments) : rend le nb d'octets écrits, ou EOF si erreur. Les\n sont transformés en CR/LF si fichier en mode texte (spécifique PC).

int fscanf(FILE *id, char *format, listeadresses) : rend le nombre de variables lues et stockées, 0 sierreur).

En général, on utilise les fichiers bufférisés :

- Soit en accès direct, en lecture et écriture, avec tous les éléments de même type et même taille (souventune structure, en format binaire), ceci permettant d'accéder directement à un élément donné (le 48ème, leprécédent, l'avant dernier...).

- Soit en accès séquentiel, avec des éléments de type différent, tous formatés sous forme ASCII, enlecture seule ou écriture seule (il est peu probable que le remplacement d'un élément se fasse avec lemême nombre d'octets et nécessiterait un décalage dans le fichier), ces fichiers seront compréhensiblespar n'importe quel autre programme (éditeur de texte, imprimante...). Un tel fichier s'utilise commel'écran et le clavier, par des fonctions similaires.

Exercice (agenda) : modifier l'agenda de l'exercice tel en permettant de sauver les données sur disque.On utilisera un fichier binaire à accès direct. On pourra ensuite apporter les améliorations suivantes :

Langage C - Les fichiers de données

http://www-ipst.u-strasbg.fr/pat/program/tpc05.htm (4 of 5) [21-11-2001 17:45:46]

Page 177: algo

recherche rapide par dichotomie sans lire tout le fichier (en le supposant classé par ordre alphabétique),création de fichiers index classés alphabétiquement sur les noms, département et ville pour accès rapidepar dichotomie, les autres se faisant par recherche séquentielle, avec possibilité d'ajout, suppression,édition du fichier.

Exercice (fic_formaté) : modifier le programme de produit de matrices en lui permettant de donner surla ligne de commande trois noms de fichiers : les deux premiers contiendront la description des matricesà multiplier, le dernier sera créé et contiendra le résultat. Les fichiers seront formatés, contiendront enpremière ligne le nombre de lignes puis le nombre de colonnes, puis chaque ligne du fichier contiendraune ligne de la matrice.

Langage C - Les fichiers de données

http://www-ipst.u-strasbg.fr/pat/program/tpc05.htm (5 of 5) [21-11-2001 17:45:46]

Page 178: algo

Directives du pré-compilateurAttention, les directives se terminent par le retour à la ligne et pas un ";".

#include <nomfic> permet d'insérer à cet endroit un fichier, qui serra cherché dans le répertoirecorrespondant à la bibliothèque du C (sur PC dans \TC\INCLUDE)

#include "nomfic" permet d'insérer à cet endroit un fichier, comme s'il était écrit ici, en le cherchantdans le répertoire actuel (le votre)

#define nom valeur : remplace chaque occurrence du nom par la valeur. On ne peut prendre en comptequ'une ligne (le retour à la ligne terminant la définition). En C on a l'habitude de noter les constantesnumériques en majuscules.

exemple :

#define PI 3.1415926#define begin {#define end }

#define macro(parametres) définition : permet la définition d'une macro, les paramètres serontsubstitués lors de la réécriture. Il ne faut pas de blanc entre le nom de la macro et la "(" pour différencierd'un define simple.

#define double(a) a*2remplacera double (i+5) par i+5*2. Il faut donc utiliser des parenthèses, même si elles semblent inutiles :#define double(a) (a)*2

autre exemple:#define max(x,y) x>y?x:yreplacera max(a,max(b,c)) par a>b>c?b:c?a:b>c?b:c

#define max(x,y) (((x)>(y)?(x):(y)replacera max(a,max(b,c)) par (((a)>( (((b)>(c))?(b):(c)) )) ? (a) : (((( b)>(c)) ? (b) : (c))) ce qui donne desparenthèses superflues mais le résultat escompté.

Une macro ressemble à une fonction, mais sera d'exécution plus rapide : le texte est directement inséré àl'endroit voulu, mais pas de gestion de pile.

#undef nom : annule le précédent #define nom ...

#if (expression) : les lignes qui suivent ne seront lues (et compilées que si l'expression est vraie

#endif : fin de portée du #if précédent

Langage C - Directives du pré-compilateur

http://www-ipst.u-strasbg.fr/pat/program/tpc06.htm (1 of 2) [21-11-2001 17:45:50]

Page 179: algo

#else : possible mais optionnel, faire attention en cas de #if imbriqués

#ifdef nom : comme #if mais vrai s'il y a eu auparavant un #define nom

#ifndef nom : vrai si variable non définie

exemples:

#ifndef entier #define entier int /* si une autre bibliothèque incluse plus haut l'a déjà défini, on ne le redéfinit plus */#endif#ifdef biblio_graphique initialise_ecran(); efface_ecran(); trace(dessin);#else puts("si on avait eu un écran graphique j'aurai fait un dessin");#endif/* biblio_graphique peut être défini dans un "header" (fichier.h) inclus ou non plus haut */

Langage C - Directives du pré-compilateur

http://www-ipst.u-strasbg.fr/pat/program/tpc06.htm (2 of 2) [21-11-2001 17:45:50]

Page 180: algo

Utiliser Turbo C (3.5 par exemple)Turbo C est d'après moi le compilateur le plus intéressant sur PC en phase d'apprentissage : éditeurintégré, lié aux messages d'erreur, éditeur multifenêtres, aide en ligne, débogueur puissant. Placez vousdans votre répertoire (pas celui de Turbo C pour ne pas mélanger avec vos fichier) et appelez TC.

Les commandes sont accessibles par menus, il vaut mieux posséder une souris. Sinon, on accède à unecommande d'un menu par ALT et lettre en surbrillance, on change d'option par TAB, on valide parESPACE. Au menu principal, on peut :

FILE : gérer les fichiers : en créer un nouveau (new), reprendre un fichier déjà existant (open, puischoisir le fichier dans la liste), sauver le fichier actuel (save ou save as), quitter TC (quit ou ALT X).

EDIT : couper - coller, et surtout remettre une ligne de texte dans son état initial (restore line), surtoutaprès l'avoir effacée par erreur par CTRL Y.

SEARCH : recherche ou remplacement d'un texte dans tout le fichier (CTRL L pour rechercher lesuivant).

RUN : exécuter le programme. On peut exécuter le programme pas à pas : Aller jusqu'à la ligne danslaquelle est le curseur, avancer d'une ligne (trace into ou step over). Ceci permet de voir dans quel ordres'exécutent les instructions.

COMPILE : compiler pour voir les erreurs, il faut faire un EXE pour pouvoir utiliser le programme horsde TC.

DEBUG : en mode pas à pas on peut voir ou modifier l'état d'une variable (evaluate, inspect), voir l'étatde la pile (imbrication des fonctions et arguments réels : call stack) voir dans une fenêtre à tout momentl'état d'une variable (add watch).

PROJECT : un projet contient la liste de fichiers nécessaires au fonctionnement d'un programme (fichiersséparés).

OPTION : on peut tout choisir : répertoires, niveau de messages d'erreur de compilation, mode 43 lignes(environnement preferences) et même couleurs.

WINDOW : choix des fenêtres ouvertes, déplacement, changement de taille... Entre autres la fenêtreOUTPUT correspond à l'écran tel que le gère votre programme, utile pour voir à la fois vos résultats etvotre programme.

HELP : aide

En vous plaçant sur une commande d'un menu, l'appui sur F1 vous détaille ce que permet cettecommande. Dans une fenêtre de texte , l'appui sur CTRL F1 vous donne une aide sur le mot sous lecurseur, uniquement si c'est un mot clef du C (mais connaît toutes les fonctions, sait dans quel header elle

Langage C - Utiliser Turbo C (3.5 par exemple)

http://www-ipst.u-strasbg.fr/pat/program/tpc07.htm (1 of 2) [21-11-2001 17:45:53]

Page 181: algo

est déclarée). par exemple, tapez printf puis CTRL F1, vous aurez une indication sur tous les formatspossibles ainsi que des exemples.

En choisissant l'option menus longs, les touches de raccourci sont indiquées à côté des fonctions desmenus.

Dernier conseil, sauvez votre source avant de l'exécuter, au cas ou votre programme planterait la machine(automatisation possible sous options)

Langage C - Utiliser Turbo C (3.5 par exemple)

http://www-ipst.u-strasbg.fr/pat/program/tpc07.htm (2 of 2) [21-11-2001 17:45:53]

Page 182: algo

Correction des exercices

langage C / Patrick TRAU1. while_puiss2. while_err3. do_while4. for5. jeu6. calcul7. moyenne8. rotation9. classer10. chaînes11. matrices12. déterminant13. tel14. liste et insertion15. agenda

1. while_puiss

#include <stdio.h>void main(void) { int puissance=1,max; puts("nombre maximal désiré (ne pas dépasser 16000) ?"); scanf("%d",&max); while (puissance<max) printf("%d\n",puissance*=2); }

retour au sujet de cet exercice

2. while_errCe programme démontre les erreurs de calcul toujours effectuées sur des nombres réels. On additione successivement 0.01(qui n'a pas de représentation finie en binaire) à un réel initialement nul. On compte le nombre de calculs jusqu'à obtenir uneerreur de 100%. Dans ce cas il faut 16246 calculs. On peut essayer d'autres pas et d'autres débuts.

retour au sujet de cet exercice

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (1 of 18) [21-11-2001 17:46:06]

Page 183: algo

3. do_while

#include <stdio.h>#include <stdlib.h> /* pour rand() */#include <time.h> /* pour trouver l'heure pour srand */void main(void) { int solution,reponse,nb_essais=0; {time_t t;srand((unsigned) time(&t)); } /* initialiser le générateur à partir du compteur de temps, pour qu'il soit plus aléatoire */ solution=rand()%11; /* reste sera toujours entre 0 et 10 */ do { nb_essais++; puts("proposez votre nombre entre 0 et 10"); scanf("%d",&reponse); } while (reponse!=solution); printf("trouvé en %d essais\n",nb_essais); }

retour au sujet de cet exercice

4. for

#include <stdio.h>void main(void) { int i,N; float note,somme=0,moyenne; puts("nombre de notes ? "); scanf("%d",&N); for(i=0;i<N;i++) { printf("entrez votre %dième note",i+1); scanf("%f",&note); somme+=note; } moyenne=somme/N; printf("moyenne calculée :%5.2f\n",moyenne); }

retour au sujet de cet exercice

5. jeu

#include <stdio.h>#include <stdlib.h> /* pour rand() */#include <time.h> /* pour trouver l'heure pour srand */void main(void)

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (2 of 18) [21-11-2001 17:46:06]

Page 184: algo

{ int solution,reponse,nb_essais=0; { time_t t;srand((unsigned) time(&t)); } /* initialiser le générateur*/ solution=rand()%11; /* reste sera toujours entre 0 et 10 */ do { nb_essais++; puts("proposez votre nombre entre 0 et 10"); scanf("%d",&reponse); if (reponse>solution) puts("trop grand"); else if (reponse!=solution) puts("trop petit"); } while (reponse!=solution); printf("trouvé en %d essais\n",nb_essais); if (nb_essais==1) puts("vous avez eu un peu de chance"); else if (nb_essais<4) puts("bravo"); else if (nb_essais>6) puts("ce score me semble bien minable"); }

retour au sujet de cet exercice

6. calcul

#include <stdio.h>void main(void) { float val1,val2,res; char op; int fin=0; do { puts("calcul à effectuer (par ex 5*2), ou 1=1 pour finir ? "); scanf("%f%c%f",&val1,&op,&val2); switch (op) { case '*':res=val1*val2;break; case '/':res=val1/val2;break; case '+':res=val1+val2;break; case '-':res=val1-val2;break; case '=':fin++; /* pas besoin de break, je suis déjà au } */ } if (!fin) printf("%f%c%f=%f\n",val1,op,val2,res); } while (!fin); }

retour au sujet de cet exercice

7. moyenne

#include <stdio.h>#define max 100

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (3 of 18) [21-11-2001 17:46:06]

Page 185: algo

typedef float tableau[max];tableau tab;int Nb;void lecture(void) { int i; puts("entrez le nombre de notes à traiter :"); do scanf("%d",&Nb); while ((Nb<=0)||(Nb>max)); for(i=0;i<Nb;i++) { printf("valeur n° %d ? ",i+1); scanf("%f",&tab[i]); } }float moyenne(void) { int i; float somme=0; for (i=0;i<Nb;i++) somme+=tab[i]; return(somme/Nb); }void affichage(float moy) { int i; printf("la moyenne des %d notes est %f\n",Nb,moy); for(i=0;i<Nb;i++) printf("%dième note : écart : %f\n",i+1,tab[i]-moy); }void main(void) { lecture(); affichage(moyenne()); }

retour au sujet de cet exercice

8. rotation

#include <stdio.h>typedef int composante;void lecture(composante *t,int *nb) { int i; puts("nombre de valeurs à entrer ? "); scanf("%d",nb); for(i=1;i<=*nb;i++) { printf("%dième valeur : ",i); scanf("%d",t++); } }void affiche(composante *t, int max) { int i;

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (4 of 18) [21-11-2001 17:46:06]

Page 186: algo

for(i=0;i<max;i++) printf("%d ",*t++); puts(" "); }void decale_bas(composante *deb, int max) { composante c,*t; t=deb+(max-1); c=*t; while (t>deb) {*t=*(t-1);t--;} *t=c; }void decale_haut(composante *t, int nb) { composante c;int i; c=*t; for (i=1;i<nb;i++) {*t=*(t+1);t++;} *t=c; }void main(void) { composante tableau[100]; int nombre; lecture(tableau,&nombre); puts("tableau initial :"); affiche(tableau,nombre); decale_haut(tableau,nombre); puts("décalage vers le haut :"); affiche(tableau,nombre); decale_bas(tableau,nombre); puts("décalage vers le bas :"); affiche(tableau,nombre); }

retour au sujet de cet exercice

9. classer

#include <stdio.h>#define dim 100typedef int composante;void lecture(composante *t,int *nb) { int i; puts("nombre de valeurs à entrer ? "); scanf("%d",nb); for(i=1;i<=*nb;i++) { printf("%dième valeur : ",i); scanf("%d",t++); } }void affiche(composante *t, int max) {

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (5 of 18) [21-11-2001 17:46:06]

Page 187: algo

int i; for(i=0;i<max;i++) printf("%d ",*t++); puts(" "); }int indice_min(composante t[],int indice_dep, int nb_indices)/* cherche l'indice de la valeur du tableau : * -soit égale à t[indice_dep], mais d'indice > à indice_dep; * -soit la plus petite mais >t[indice_deb] */ { int i,indice_resultat=-1; for(i=indice_dep+1;i<nb_indices;i++) if (t[i]==t[indice_dep]) return(i);/* si on est encore là c'est qu'il n'y en pas d'égal */ for(i=0;i<nb_indices;i++) if ((t[i]>t[indice_dep]) && ((indice_resultat<0) || (t[i]<t[indice_resultat])))indice_resultat=i; return(indice_resultat);}void copier(composante *source, composante *dest, int nb)/* copie le tableau source dans le tableau dest */ { int i; for(i=0;i<nb;i++) *(dest++)=*(source++); }void classe(composante tab[], int nb) { composante tempo[dim]; /* un malloc(sizeof(composante)*nb) aurait été mieux mais on n'en a pas encore parlé en cours */ int i,ind_faits,indice;/* 1er : recherche du plus petit, le 1er si ex aequo */ indice=0; for(i=1;i<nb;i++) if(tab[i]<tab[indice]) indice=i; tempo[ind_faits=0]=tab[indice];/* les suivants : recherche le + petit mais > au précédent */ for(ind_faits=1;ind_faits<nb;ind_faits++) { indice=indice_min(tab,indice,nb); tempo[ind_faits]=tab[indice]; } copier(tempo,tab,nb); }void main(void) { composante tableau[dim]; int nombre; lecture(tableau,&nombre); puts("tableau initial :"); affiche(tableau,nombre); classe(tableau,nombre); puts("tableau classé :"); affiche(tableau,nombre); }

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (6 of 18) [21-11-2001 17:46:06]

Page 188: algo

retour au sujet de cet exercice

10. chaînes

#include <stdio.h>#define taille 255int debut_egal(char *ch,char *sch)/* répond si sch est exactement le début de ch */ { while (*sch && *ch) { if (*sch!=*ch) return(0); else {ch++;sch++;} } return(!(*sch)); }void recherche(char *ch,char *sch) { int pos=0; while (*ch) { if (debut_egal(ch,sch)) printf("trouvé en position %d\n",pos); ch++;pos++; } }void main(void) { char ch[taille],sch[taille]; puts("chaîne à tester ? "); gets(ch); puts("sous-chaîne à trouver ?"); gets(sch); recherche(ch,sch); }

retour au sujet de cet exercice

11. matrices

#include <stdio.h>#define DIM 10typedef float ligne[DIM];typedef ligne matrice[DIM];typedef float *pointeur;

void lecture(matrice t,int *lig,int *col)/* lit à l'écran une matrice */ { int l,c; float f; puts("nombre de lignes de la matrice ?"); scanf("%d",lig);

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (7 of 18) [21-11-2001 17:46:06]

Page 189: algo

puts("nombre de colonnes de la matrice ?"); scanf("%d",col); for (l=0;l<*lig;l++) for(c=0;c<*col;c++) { printf("élément [%d,%d] ? ",l,c); scanf("%f",&f); t[l][c]=f; } }void zero(float *t)/* met toute la matrice à 0 */ { int i; for(i=0;i<DIM*DIM;i++) *t++=0; }void unit(matrice t)/* remplit la matrice unité (1 diagonale, 0 autre) */ { int i; zero(t); for(i=0;i<DIM;i++) t[i][i]=1; }void init(matrice t)/* initialisation de matrice à numlig.numcol */ { int i,j; for(i=0;i<DIM;i++) for(j=0;j<DIM;j++) t[i][j]=i+j/10.0; }void affiche(matrice t,int l,int c)/* puts("affichage du tableau ligne par ligne :"); */ { int i,j; for(i=0;i<l;i++) { printf("ligne %d : ",i); for(j=0;j<c;j++) printf("%3.1f ",t[i][j]); printf("\n"); } }void produit(matrice a,matrice b,matrice c,int m,int l,int n)/* calcul du produit */ { int im,il,in; zero(c); for(im=0;im<m;im++) for(in=0;in<n;in++) for(il=0;il<l;il++) c[im][in]+=a[im][il]*b[il][in]; }void main(void) { int m,l,n,i; matrice a,b,c; lecture(a,&m,&l);

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (8 of 18) [21-11-2001 17:46:06]

Page 190: algo

lecture(b,&i,&n); if(i!=l) puts("calcul impossible : dimensions incompatibles"); affiche(a,m,l); puts("--- FOIS ---"); affiche(b,l,n); puts("--- FAIT ---"); produit(a,b,c,m,l,n); affiche(c,m,n); }

retour au sujet de cet exercice

12. determinant

#include <stdio.h>#include <stdlib.h>#define DIM 10typedef float ligne[DIM];typedef ligne matrice[DIM];typedef float *pointeur;long nb_appels;

void lecture(matrice t,int *lig)/* lit une matrice (au clavier) */ { int l,c; float f; puts("dimension de la matrice ?"); scanf("%d",lig); for (l=0;l<*lig;l++) for(c=0;c<*lig;c++) { printf("élément [%d,%d] ? ",l,c); scanf("%f",&f); t[l][c]=f; } }void zero(matrice t,int dim)/* met toute la matrice à 0 */ { int i,j; for(i=0;i<dim;i++)for(j=0;j<dim;j++) t[i][j]=0; }void unit(matrice t, int dim)/* remplit la matrice unité (1 diagonale, 0 autre) */ { int i; zero(t,dim); for(i=0;i<dim;i++) t[i][i]=1; }void affiche(matrice t,int l)/* puts("affichage du tableau ligne par ligne :"); */ { int i,j;

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (9 of 18) [21-11-2001 17:46:06]

Page 191: algo

for(i=0;i<l;i++) { printf("ligne %d : ",i); for(j=0;j<l;j++) printf("%3.1f ",t[i][j]); printf("\n"); } }void copiesauflc(matrice source,matrice dest,int dim,int ligavirer) { int l,c,ld=0; for (l=0;l<dim;l++) if (l!=ligavirer) { for (c=1;c<dim;c++) dest[ld][c-1]=source[l][c]; ld++; } }float determinant(matrice m,int dim) { matrice sous_m; int l,signe=1; float det=0; nb_appels++; if (dim==1) return(m[0][0]); for(l=0;l<dim;l++) { copiesauflc(m,sous_m,dim,l); det+=signe*m[l][0]*determinant(sous_m,dim-1); signe=-signe; } return(det); }void produit(matrice a,matrice b,matrice c,int dim)/* calcul du produit */ { int im,il,in; zero(c,dim); for(im=0;im<dim;im++) for(in=0;in<dim;in++) for(il=0;il<dim;il++) c[im][in]+=a[im][il]*b[il][in]; }void main(int argc,char *argv[]) { int taille; matrice mat;/* lecture(mat,&taille); */ taille=atoi(argv[1]); /* test avec matrice unité, */ unit(mat,taille); /* au moins je connais le résultat*/ affiche(mat,taille); printf("déterminant : %20.17f ",determinant(mat,taille)); printf(" en %ld appels\n",nb_appels); }

retour au sujet de cet exercice

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (10 of 18) [21-11-2001 17:46:07]

Page 192: algo

13. tel

#include <stdio.h>#include <string.h>#include <stdlib.h>#define DIM 100enum champs {nom,prenom,num,rue,cp,ville,tel};char *nomchamp[7]={"Nom", "Prénom", "Numéro", "Rue", "Code Postal", "Ville", "Tel"};typedef struct { char nom[15]; char prenom[20]; int num; char rue[60]; long codepostal; char ville[20]; char tel[15]; } fiche;

fiche *rech_nom(fiche *,char *);fiche *rech_prenom(fiche *,char *);fiche *rech_num(fiche *,char *);fiche *rech_rue(fiche *,char *);fiche *rech_cp(fiche *,char *);fiche *rech_ville(fiche *,char *);fiche *rech_tel(fiche *,char *);fiche *rech_nom(fiche *,char *);

typedef fiche *ptrfiche;typedef ptrfiche (*ptrfonction)(ptrfiche,char*);ptrfonction tabfonction[7]={rech_nom, rech_prenom, rech_num, rech_rue, rech_cp, rech_ville, rech_tel};

void affiche(fiche *f) { if(f->nom[0]) printf("%s %s\n%d, %s\n%ld %s\nTel : %s\n", f->nom, f->prenom, f->num, f->rue, f->codepostal, f->ville, f->tel); else printf("fiche inconnue\n"); }int idem(char *s1,char *s2)/* compare deux chaines, dit si elles sont égales (1), ou non (0). On pourrait supposer égalité quand la chaine s2 est incluse dans s1 */ { return(strcmp(s1,s2)?0:1); }

fiche *rech_nom(fiche *pf,char *n) {while ((pf->nom[0])&&(!idem(pf->nom,n)))pf++; return(pf);}

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (11 of 18) [21-11-2001 17:46:07]

Page 193: algo

fiche *rech_prenom(fiche *pf,char *n) {while ((pf->nom[0])&&(!idem(pf->prenom,n)))pf++; return(pf);}fiche *rech_num(fiche *pf,char *n) {while ((pf->nom[0])&&(pf->num!=atoi(n)))pf++; return(pf);}fiche *rech_rue(fiche *pf,char *n) {while ((pf->nom[0])&&(!idem(pf->rue,n)))pf++; return(pf);}fiche *rech_cp(fiche *pf,char *n) {while ((pf->nom[0])&&(pf->codepostal!=atoi(n)))pf++; return(pf);}fiche *rech_ville(fiche *pf,char *n) {while ((pf->nom[0])&&(!idem(pf->ville,n)))pf++; return(pf);}fiche *rech_tel(fiche *pf,char *n) {while ((pf->nom[0])&&(!idem(pf->tel,n)))pf++; return(pf);}

int choix(void) { char lig[40]; enum champs i,rep; for (i=nom;i<=tel;i++) printf("%d:%s ",i,nomchamp[i]); printf("\nou -1 pour quitter. Type de recherche désirée ? "); gets(lig); sscanf(lig,"%d",&rep); return(rep); }

void lecture(fiche *tab) { char lig[40]; do { printf("nom (rien pour finir) ?"); gets(tab->nom); if(tab->nom[0]) { printf(" prénom ? "); gets(tab->prenom); printf(" N° ? "); gets(lig); sscanf(lig,"%d",&(tab->num)); printf(" rue ? "); gets(tab->rue); printf(" code postal ? "); gets(lig); sscanf(lig,"%ld",&(tab->codepostal)); printf(" ville ? "); gets(tab->ville); printf("n° de téléphone ? "); gets(tab->tel); }

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (12 of 18) [21-11-2001 17:46:07]

Page 194: algo

} while ((tab++)->nom[0]); }

void main(void) { enum champs c; char clef[40]; fiche tab[DIM]; lecture(tab); do { if (((c=choix())<0)||(c>6)) break; printf("quel(le) %s recherche-t'on ? ",nomchamp[c]); gets(clef); affiche(tabfonction[c](tab,clef)); } while (c>=0); }

retour au sujet de cet exercice

14. liste et insertion

#include <stdio.h>#include <conio.h>#include <ctype.h>#include <alloc.h>

struct page {int val; struct page *suivant; };struct page *premier;

int encore(void) /* demande si on en veut encore*/ { printf("encore (O/N) ? "); return(toupper(getche())=='O'); }

void lecture(void) { struct page *precedent,*nouveau; premier=(struct page *)malloc(sizeof(struct page)); puts("entrez votre premier entier"); scanf("%d",&premier->val); precedent=premier; while (encore()) { nouveau=(struct page *)malloc(sizeof(struct page)); precedent->suivant=nouveau; precedent=nouveau; puts("\nentrez votre entier"); scanf("%d",&nouveau->val); }

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (13 of 18) [21-11-2001 17:46:07]

Page 195: algo

precedent->suivant=NULL; }

void affiche(struct page *debut) { printf("\nliste : "); while(debut!=NULL) { printf("%d ",debut->val); debut=debut->suivant; } printf("\n"); }

void suppression(void) { struct page *actu,*prec; actu=premier; while (actu!=NULL) { printf("\nvaleur : %d - supprimer celui-ci (O/N) ? ",actu->val); if (toupper(getche())=='O') { if(actu==premier)premier=actu->suivant; else prec->suivant=actu->suivant; free(actu); break; } else { prec=actu; actu=prec->suivant; } } }void ajouter(void) { struct page *nouveau,*prec; printf("\najouter en premier (O/N) ? "); if (toupper(getche())=='O') { nouveau=(struct page *)malloc(sizeof(struct page)); nouveau->suivant=premier; premier=nouveau; printf("\nnouvelle valeur ? "); scanf("%d",&(nouveau->val)); } else { prec=premier; while(prec!=NULL) { printf("\nvaleur : %d - insérer après celui_ci (O/N) ? ", prec->val); if (toupper(getche())=='O')

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (14 of 18) [21-11-2001 17:46:07]

Page 196: algo

{ nouveau=(struct page *)malloc(sizeof(struct page)); nouveau->suivant=prec->suivant; prec->suivant=nouveau; printf("\nnouvelle valeur ? "); scanf("%d",&(nouveau->val)); break; } else prec=prec->suivant; } } }

void main(void) { lecture(); affiche(premier); do { suppression(); affiche(premier); } while(encore()); do { ajouter(); affiche(premier); } while(encore()); }

retour au sujet de cet exercice

15. agenda

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <ctype.h>#include <conio.h>

/* définitions des types et variables associées */enum champs {nom,prenom,num,rue,cp,ville,tel};char *nomchamp[7]={"Nom","Prénom","Numéro","Rue", "Code Postal","Ville","Tel"};typedef struct { char nom[15]; char prenom[20]; int num; char rue[60]; long codepostal; char ville[20];

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (15 of 18) [21-11-2001 17:46:07]

Page 197: algo

char tel[15]; } fiche;#define taille sizeof(fiche)typedef fiche *ptrfiche;

/* définitions des fonctions de recherche, regroupées dans un tableau */fiche *rech_nom(fiche *,char *);fiche *rech_prenom(fiche *,char *);fiche *rech_num(fiche *,char *);fiche *rech_rue(fiche *,char *);fiche *rech_cp(fiche *,char *);fiche *rech_ville(fiche *,char *);fiche *rech_tel(fiche *,char *);fiche *rech_nom(fiche *,char *);

typedef ptrfiche (*ptrfonction)(ptrfiche,char*);ptrfonction tabfonction[7]= {rech_nom, rech_prenom, rech_num, rech_rue, rech_cp, rech_ville, rech_tel};

/* variables globales */FILE *fic; /* fichier de données */char *nomfic="agenda.dat";int nb; /* nb de fiches dans le fichier */

void init(void)/* ouvre le fichier, détermine le nb de fiches de fic */ { if ((fic=fopen(nomfic,"a+b"))==NULL) { puts("ouverture impossible du fichier de données"); exit(1); } fseek(fic,0,2); nb=(int)ftell(fic)/taille; printf("%d fiches présentes dans l'agenda\n",nb); }

void ajouter(void) { char lig[40]; fiche f; printf("nom ? "); gets(f.nom); printf(" prénom ? "); gets(f.prenom); printf(" Numero ? "); gets(lig); sscanf(lig,"%d",&(f.num)); printf(" rue ? "); gets(f.rue); printf(" code postal ? "); gets(lig); sscanf(lig,"%ld",&(f.codepostal)); printf(" ville ? ");

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (16 of 18) [21-11-2001 17:46:07]

Page 198: algo

gets(f.ville); printf("n° de téléphone ? "); gets(f.tel); fseek(fic,0L,2); if(fwrite(&f,taille,1,fic)!=1) { puts("impossible d'ajouter cette fiche au fichier "); exit(0); } nb++; }

void affiche(fiche *f) { if((f!=NULL)&&(f->nom[0])) printf("%s %s\n%d, %s\n%ld %s\nTel : %s\n",f->nom, f-> prenom, f->num, f->rue,f->codepostal,f->ville,f->tel); else printf("fiche inconnue\n"); }

int idem(char *s1,char *s2)/* compare deux chaines, dit si elles sont égales (1), ou non (0). On considère égales majuscules et minuscules. Une des chaines peut se terminer par *, on supposera identique si tout ce qui précède l'* était identique */ { for(;;) { if (((!*s1)&&(!*s2))||(*s1=='*')||(*s2=='*')) return(1); if ((toupper(*s1)!=toupper(*s2))||(!*s1)||(!*s2)) return(0); s1++;s2++; } }

fiche *rech_nom(fiche *pf,char *n) { int nblu; fseek(fic,0L,0); do nblu=fread(pf,taille,1,fic); while ((nblu==1)&&(!idem(pf->nom,n))); if (nblu==1) return(pf); else return(NULL); }

/* les autres recherches sont à continuer */

int choix(void) { char lig[40]; enum champs i,rep; for (i=nom;i<=tel;i++) printf("%d:%s ",i,nomchamp[i]); printf("\nou -1 pour quitter. Type de recherche désirée ? "); gets(lig);

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (17 of 18) [21-11-2001 17:46:07]

Page 199: algo

sscanf(lig,"%d",&rep); return(rep); }

void recherche(void) { enum champs c; char clef[40]; fiche f; do { if (((c=choix())<0)||(c>6)) break; printf("quel(le) %s recherche-t'on ? ",nomchamp[c]); gets(clef); affiche(tabfonction[c](&f,clef)); } while (c>=0); }

void main(void) { char rep; init(); do { puts("Ajouter une fiche, Recherche d'une fiche, Quitter le prog ? "); switch (rep=toupper(getch())) { case 'A':ajouter();break; case 'R':recherche();break; case 'Q':fclose(fic);puts("Au revoir");break; default :puts("option non prévue"); } } while (rep!='Q'); }

retour au sujet de cet exercice

Correction des exercices

http://www-ipst.u-strasbg.fr/pat/program/tpcex.htm (18 of 18) [21-11-2001 17:46:07]

Page 200: algo

Liens vers d'autres sites sur le CJe ne suis pas le seul à publier mon cours sur Internet. Voici d'autres liens, pour compléter (ou remplacer)ce que je propose.

Le cours d'Irène Charon (ENST Paris) : le language est présenté progressivement à partird'exemples. C'est un très bon complément à qui n'a pas trop aimé ma méthode de présentation(mes étudiants par exemple)

Le cours de Alain Dancel : Très bon cours, très complet.●

cours ANSI-C de Fred Faber (Lycée Technique des Arts et Métiers, Luxembourg)●

le cours d'Yves Papegay (Inria) (sous Unix)●

vous cherchez un compilateur (freeware, évidement) ? DJGPP pour DOS, ou GNU-Win32 pour Win95/NT, ou GCC pour Unix (c'est le seul que j'ai essayé). De nouveaux arrivants : Pacific : sous DOS(freeware), avec un environnement sympa (un peu comme Turbo C), et une doc en pdf (la versionWindows est payante). Désormais, Inprise (Borland) vous propose ses compilateurs gratuitement !(pour certaines versions Turbo C, Turbo Pascal, Borland C, Delphi..., évidement pas les plus récentes).

Langage C - Liens externes

http://www-ipst.u-strasbg.fr/pat/program/tpcliens.htm [21-11-2001 17:46:11]