Suivez-nous sur X
|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : C - les structures de contrôle
(Article écrit par Batchman et extrait d'A-News (Amiga News) - mars 1990)
|
|
Maintenant que nous maîtrisons les variables
(déclaration, types et classes de stockage), nous allons commencer à mettre quelques instructions
autour, histoire d'égayer un peu le paysage.
Ceux qui connaissent Pascal ou Ada ne seront pas dépaysés mais les basico-dépendants vont tomber de haut.
Le C est un langage structuré. Il est toujours possible de programmer salement mais, pour bénéficier
de la puissance de ce langage, il est nécessaire de respecter quelques règles simples.
Programmez structuré
Vous allez le voir, le langage C est relativement pauvre en instructions : il y a peu de mots-clefs. Les structures
de contrôle sont :
- Le test.
- L'aiguillage.
- Les boucles finies ou conditionnelles.
Le test
C'est le classique "si .. alors .. sinon", qui prend ici la syntaxe suivante :
if (condition) instruction ; else instruction ;
|
Si la condition est vérifiée, la première instruction est exécutée. Dans le cas contraire, c'est la deuxième.
Notez bien ces points :
- La condition est entre parenthèses. Elle est le résultat d'un test.
- Il n'y a pas de "alors" (ou "then").
- "instruction" représente une instruction ou bien un bloc, c'est-à-dire des instructions encadrées par
des accolades {} (les "begin" et "end" du Pascal).
- La partie "else" est facultative. Si elle est absente et si la condition est fausse, le programme passe directement à la suite.
Quelques exemples :
if (a == b) printf("a et b sont égaux\n");
else printf("a et b sont différents\n");
|
if (a != b) printf("a et b sont différents\n");
|
if (a != b) {
printf("a et b sont différents\n");
a = b;
printf("maintenant, a et b sont égaux\n");
}
|
Nous reviendrons dans le prochain article sur les opérateurs, mais vous pouvez déjà noter que
"==" représente le test d'égalité et "!=" le test d'inégalité.
Notez également que dans le dernier exemple, trois instructions doivent être exécutées dans le cas où la
condition est vérifiée : elles doivent être obligatoirement placées entre accolades.
L'aiguillage
Dans le cas où vous voudriez tester les différentes valeurs que peut prendre une variable, vous avez
la possibilité d'écrire une cascade de if :
if (a == 1) ...;
else if (a == 2) ...;
else if (a == 3) ...;
else ...;
|
Il existe une écriture plus simple, et plus efficace, du point de vue du code généré :
switch (a) {
case 1: instruction1;
case 2: instruction2;
case 3: instruction3;
default: instruction_par_defaut;
}
|
Si la variable "a" vaut "1", la première ligne est exécutée, si elle vaut "2", la deuxième est exécutée,
si elle vaut "3", la troisième est exécutée... Si elle ne correspond à aucune des valeurs, c'est l'option
default qui est choisie. Cette clause est facultative.
Mais ce n'est pas si simple, les concepteurs du C ont cru bon de poser ici une mine. En effet,
l'instruction exécutée est celle qui correspond à l'alternative choisie mais elle n'est pas la seule :
les instructions des cas suivants sont aussi exécutées ! Sauf si vous le demandez explicitement avec
un "break" : dans ce cas, le programme saute directement après l'aiguillage.
En clair, si a vaut "2" par exemple, l'instruction2 est exécutée, mais aussi l'instruction3 et l'instruction
par défaut. Pour éviter ce problème, il faut écrire :
switch (a) {
case 1: instruction1;
break;
case 2: instruction2;
break;
case 3: instruction3;
break;
default: instruction_par_defaut;
}
|
Dans ce cas, si a vaut "2", seule l'instruction2 est exécutée. Ça correspond à un usage plus courant
et il est gênant de devoir mettre ces "break". Mais n'épiloguons pas sur ce choix contestable.
Les boucles
Il faut distinguer trois types de boucles :
while (condition) instruction;
|
L'opération ou le bloc représenté par instruction est exécuté tant que la condition est vraie. Le test est
effectué avant l'instruction, donc, si la condition est fausse des le départ, l'instruction n'est pas exécutée.
Exemples :
while (a != b) a = a + 1;
|
while (a != b) {
a = a + 1;
b = b - 1;
}
|
La boucle "répéter" :
do instruction while (condition);
|
Ici aussi, l'instruction est exécutée tant que la condition est vraie. Mais le test est effectué après
l'instruction, ce qui signifie que l'on rentre au moins une fois dans la boucle, même si la condition est
fausse dès le début.
Vous pouvez donc écrire :
do a = a + 1 while (a != b);
|
do {
a = a + 1;
b = b + 1;
} while (a != b);
|
La boucle "pour" (for) est radicalement différente : le nombre d'itérations est ici en principe fixe. La syntaxe est la suivante :
for (instruction1; condition; instruction2) instruction3;
|
La boucle "for" est généralement indexée sur un indice. Le rôle de l'instruction1
est d'initialiser cet indice, la condition le teste et l'instruction2 est exécutée à chaque itération,
c'est-à-dire, à chaque tour de boucle.
L'instruction3 représente l'instruction ou le bloc répété. Pourquoi ne pas regrouper cette opération avec
l'instruction2 ? Ça serait possible mais on réserve généralement l'instruction2 à l'incrémentation de l'indice de boucle.
Cette séquence est rigoureusement équivalente à :
instruction1;
while (condition) {
instruction2;
instruction3;
}
|
Exemples :
for (i=0; i<=100; i=i+1) a[i] = a[i] + 1;
|
for (i=0; i<=100; i=i+1) {
a[i] = a[i] + 1;
b[i] = b[i] + 1;
}
|
Il faut préciser que chacune des trois expressions figurant entre parenthèses est facultative. Exemple classique,
la boucle infinie peut s'écrire :
Autre possibilité intéressante à noter, instruction1 et instruction2 peuvent être des listes d'instructions,
séparées par des virgules. Ceci est utile dans les cas où l'initialisation et/ou l'incrémentation ne se
fait pas en une seule opération. Par exemple, on peut avoir :
for (i=0,j=1; j =10; i=i+1,j=j+1) a[i,j]=a[i,j]+1;
|
Les instructions d'échappement
Ces instructions permettent de sortir d'une fonction, d'un bloc ou du programme, en bref, d'interrompre une séquence.
Nous avons déjà vu "break", qui permet de sortir des "switch". Cette instruction autorise aussi
la sortie des boucles, par exemple, pour traiter un cas particulier.
Exemple :
for (i=0; i<=100; i=i+1) {
if (b == 5) break;
a[i] = a[i] + 1;
appel_d_une_fonction(&b);
}
|
Dans cet exemple, il y a un cas particulier si la variable "b" vaut "5". Il faut alors sortir de la boucle.
C'est ce que permet le "break".
Autre possibilité, plutôt que de sortir de la boucle, vous pouvez vouloir ne rien faire et passer directement
à l'itération suivante. Bien que je trouve que vous ayez des goûts bizarres, voici la solution :
c'est l'instruction continue. En clair, continue revient directement au début de la boucle, sans exécuter
les instructions qui suivent dans le corps de la boucle, ni passer par la case départ.
Exemple :
for (i=0; i<=100; i=i+1) {
if (b == 5) continue;
a[i] = a[i] + 1;
appel_d_une_fonction(&b);
}
|
Dans un autre style de réjouissances, "return()" permet de sortir d'une fonction, en fixant sa valeur de retour.
Tout de suite, un exemple bête mais qui illustre bien les possibilités de cette instruction :
int valeur_absolue(x)
int x; {
if (x >= 0) return(x);
else return(-x);
}
|
Dès que le "return" est exécuté, le programme revient à la fonction appelante. S'il reste des instructions
dans cette fonction, elles sont ignorées. Bien sûr, le type de la variable retournée doit être le même
que celui de la fonction (ici int). Par exemple, pour une fonction de type "void", il faut écrire "return();".
"exit()" est l'instruction qui permet de sortir d'un programme. Si le programme retourne une valeur
(comme souvent en Unix), vous pouvez la spécifier, de la même façon que dans le cas des fonctions avec
"return()". En général, la valeur retournée est "0" dans le cas d'une fin normale, et "-1"
en cas d'interruption précipitée des réjouissances. Mais vous pouvez très bien adopter un code
différent pour chaque erreur, afin de renseigner le programme appelant (le Shell, par exemple) sur
la cause de l'erreur.
Exemples :
if (b == 0) then exit(-1);
else c = a/b;
|
Enfin, je mentionne le "goto" pour mémoire. Mais, faites-moi plaisir, ne l'utilisez pas. Les matheux
ont montré qu'il était possible d'écrire n'importe quel programme dans un langage évolué comme le
C, sans utiliser de "goto". La seule incartade que je tolérerai dans mon infinie bonté, sera l'usage
en cas de panique. En effet, on peut admettre, dans le cas où se produit une erreur grave, de sauter
en catastrophe à un traitement qui termine l'exécution. En tout cas, pas de "goto" dans tous les sens
à l'intérieur d'un programme, pour passer d'un bloc à l'autre. Sinon, je vous raie de la liste de mes lecteurs.
La syntaxe du "goto" :
goto label;
...
label;
...
|
Voilà, c'est tout pour les structures de contrôle du C. Comme vous le constatez, il y a relativement peu
de choses mais elles sont essentielles. Le mois prochain, nous parlerons opérateurs.
|