Nous avons vu jusqu'à maintenant des ordres (ou instructions) simples (ou élémentaires), indiquant d'effectuer une action très élémentaire. La programmation prend tout son intérêt avec les structures de contrôle qui sont de nouveaux types d'ordres permettant d'effectuer des ordres composés.
Il y a deux types apparents de structures de contrôle :
Avant d'étudier les structures de contrôle à proprement parler, nous allons voir une première façon de regrouper les instructions (simples ou non), à savoir le séquencement, ainsi que les conditions qui interviennent dans les structures de contrôle.
| Introduction | La première méthode permettant de composer des ordres élémentaires est d'effectuer un premier tel ordre, puis un second, puis un troisième, etc. Ceci est tellement évident qu'il ne nous apparaît pas, bien souvent, comme une composition d'ordres simples. Ceci en est pourtant une, certainement la plus élémentaire de toutes, appelée le séquencement. |
| Syntaxe du séquencement en langage C. | Si on veut un séquencement des 3 instructions par exemple, on écrit un bloc :
{
Instruction1 ;
Instruction2 ;
Instruction3 ;
}
en indiquant les instructions dans l'ordre dans lequel on désire les voir effectuer et en les entourant par une accolade ouvrante '{' pour indiquer le début du séquencement et une accolade fermante '}' pour indiquer la fin du séquencement. |
| Remarques. |
|
| Instruction vide. | Le langage C possède la notion d'instruction vide qui ne fait rien. Ainsi :
{
Instruction1 ;
Instruction2 ;
Instruction3 ;
;
}
sera considéré comme une instruction valable : c'est un séquencement de quatre instructions, la derniére instruction étant l'instruction vide. |
Les structures de contrôle suivantes vont faire appel à la notion de condition. Commençons donc par étudier celleci.
Booléen |
|
| Notion. | Vous avez normalement étudié, en Mathématiques, la logique propositionnelle avec la notion fondamentale de proposition ne pouvant prendre que l'une des valeurs de vérité 'vrai' ou 'faux' (tout au moins en logique classique). Vous avez également vu que la logique propositionnelle est liée à l'algèbre de Boole. Cette logique est implémentée en langage C avec un vocabulaire légèrement différent. |
| Booléens. | Outre les nombres et les textes, on veut en général manipuler dans un langage de programmation les valeurs de vérité, appelées dans ce contexte valeurs booléennes ou booléens. |
| Cas du langage C. | Il n'existe pas de type booléen explicite en langage C. Les entiers de type 'int' en tiennent lieu : la valeur 0 correspond à la valeur de vérité faux et les autres entiers à la valeur de vérité vrai. |
Connecteur logique |
|
| Notion. | Vous avez également vu en logique propositionnelle la notion de connecteur logique et, en particulier, les connecteurs logiques naturels de négation (le non), de conjonction (le et), de disjonction (le ou inclusif), d'implication (le si ... alors ...) et d'équivalence (le si, et seulement si). Vous avez vu aussi que tous les connecteurs logiques peuvent être engendrés à partir de deux d'entre eux bien choisis (par exemple la négation et la conjonction, ou la négation et la disjonction) ou même d'un seul (par exemple le symbole de Sheffer). |
| Cas du langage C. | On n'a retenu que les connecteurs de négation, de conjonction et de disjonction. Si P et Q sont des expressions booléennes, c'est-à-dire des expressions dont la valeur est un booléen (donc un 'int' en langage C), on obtient la négation de P, la conjonction de P et de Q, et enfin la disjonction de P et de Q en écrivant respectivement :
|
On a, par exemple, le programme logique.c suivant :
#include <stdio.h>
int main(void)
{
int P, Q, R, E;
printf("P = "); /* prompteur pour P */
scanf("%d",&P); /* lecteur pour P */
printf("Q = ");
scanf("%d",&Q);
printf("R = ");
scanf("%d",&R);
E = (P && Q && R) || (P && !Q && !R) || (!P && !Q);
printf("E = %d", E);
}
| Relations prédéfinies |
|
| Liste. | Les relations prédéfinies en langage C sont la relation d'égalité la relation de diséquation (c'est le terme informatique pour 'différent de') et les relations d'inégalité, notées de la façon suivante :
|
| Relations définissables |
|
| Introduction. | Ces relations prédéfinies permettent d'en définir d'autres, en utilisant les connecteurs logiques d'une part, les fonctions d'autre part. L'ensemble des valeurs x dont l'image par le polynôme x2- 5x + 6 est négative peut s'écrire soit : X*X - 5*X + 6 <= 0soit : (2 <= X) && (X <= 3) (l'équivalence est facile si vous savez résoudre les équations du second degré). |
| Syntaxe. | Nous ne définirons pas formellement la syntaxe de formation de telles relations pour l'instant. Une utilisation au niveau intuitif devrait être suffisant. |
Reprenons, pour motiver les structures de contrôle, le problème initial du chapitre précédent, à savoir celui qui consiste à calculer un certain nombre de valeurs de la fonction :
f(x) = ( sin(x) + ln(x) ) / ( e^x + 2 ) .
| Syntaxe. | La forme de cette instruction est : while (condition) instruction où 'instruction' est appelée le corps de la boucle, et où 'condition' est une expression booléenne. La partie while (condition)est appelée l'en-tête de la boucle. |
| Remarques. |
|
| Sémantique. | La condition est évaluée. Si elle est fausse alors l'exécution de la boucle est achevée et on passe à l'instruction suivante. Si elle est vraie alors le corps de la boucle est exécutée une fois puis on revient au début de cette instruction (on évalue donc la condition...). |
| Remarque. | Il est essentiel, du point de vue de la signification mais non de la syntaxe, que le corps de la boucle puisse changer la valeur de la condition, sinon la boucle continuera indefiniment. |
| Exemple. | Améliorons le programme concernant notre problème pris en exemple. Décidons, par exemple, qu'une valeur ne nous intéresse pas (disons x = 1000) ; nous nous arrèterons si nous introduisons cette valeur comme donnée. Ceci donne lieu au programme suivant :
#include <stdio.h>
#include <math.h>
int main(void)
{
float x, y;
printf("x = "); /* prompteur pour x */
scanf("%f",&X); /* nouveau lecteur pour x */
while (x != 1000.0) /* boucle tant que "x différent de 1000.0" */
{
y = (sin(x) + log(x))/(exp(x) + 2); /* calcul */
printf("f(%f) = %f", x, y);
printf("\n"); /* Passage à la ligne esthétique */
printf("x = "); /* nouveau prompteur pour x */
scanf("%f",&X); /* nouveau lecteur pour x */
}
}
|
| Commentaires. |
|
| Syntaxe. | La forme de cette instruction est : do instruction while (condition) ; où instruction est une instruction, encore appelèe corps de la boucle, et condition est une expression booléenne. |
| Signification. | Le corps de la boucle est effectué au moins une fois puis la condition est évaluée. Si elle est fausse alors l'exécution de la boucle est achevée et on va à l'instruction suivante. Si elle est vraie alors on repart de do. |
| Remarque. | Comme pour le type de boucle précédent, il est essentiel que le corps de la boucle puisse changer la valeur de la condition, sinon la boucle continuera indéfiniment. |
| Exemple. | Toujours en utilisant la valeur signal x = 1000, on peut utiliser le programme suivant pour résoudre notre problème :
#include <stdio.h>
#include <math.h>
int main(void)
{
float x, y;
printf("x = ");
scanf("%f",&X);
do
{
y = (sin(x) + log(x))/(exp(x) + 2);
printf("f(%f) = %f \n", x, y);
printf("x = ");
scanf("%f",&X);
} while (x != 1000.0);
}
|
| Syntaxe. | La forme de cette instruction est : for (Initialisation ; Condition ; Réinitialisation ) instruction où :
|
| Exemple. |
for (i = 1; i <= 100; i = i+1) sum = sum + i; |
| Sémantique. | La première phase consiste à initialiser les variables de contrôle (et autres variables) grâce à l'initialisation. On teste alors la condition de bouclage. Si elle n'est pas réalisée l'instruction est terminée. Si elle est réalisée on exécute une fois le corps de la boucle, on réinitialise les variables grâce à réinitialisation puis on recommence en testant la condition de bouclage. |
| Exemple. | Nous pouvons utiliser ce type de boucle pour résoudre notre problème si nous connaissons a priori le nombre de valeurs de x que nous voulons évaluer. Par exemple pour calculer dix valeurs de f(x) nous pouvons utiliser le programme suivant :
#include <stdio.h>
#include <math.h>
int main(void)
{
float x, y;
int i;
for (i=1 ; i <= 10 ; i = i+1) /* pour i allant de 1 à 10, de 1 en 1 */
{
printf("x = ");
scanf("%f",&X);
y = (sin(x) + log(x))/(exp(x) + 2);
printf("f(%f) = %f \n", x, y);
}
}
|
| Commentaire. | Dans le programme précédent la variable de contrôle i n'intervient pas dans le corps de la boucle, ce qui ne sera pas le cas en général, comme le montre l'exercice suivant. Ecrire un programme C qui demande un entier naturel N comme donnée et retourne la somme des entiers naturels de 0 à cet entier, chacun à la puissance cinq, c'est-à-dire 05 +15 + ... + N5.
#include <stdio.h>
int main(void)
{
int i, N, S=0; /* seule la variable S est inititalisée */
printf("N = ");
scanf("%d",&N);
for (i = 1; i <= N; i = i + 1)
S = S + i*i*i*i*i; /* on ajout a S son ancienne valeur puis 'i'^5 */
printf("S = %d.", S); /* une fois sorti de la boucle, on affiche la somme */
}
|
| Commentaire. | Pour une bonne utilisation d'une boucle POUR, la valeur de I ne doit pas être changée dans le corps de la boucle (par exemple I ne doit pas apparaître dans le membre de gauche d'une affectation). |
Si on veut être sûr que le programme termine il faut essayer d'utiliser le troisième type de boucle, la boucle FOR. Mais ceci n'est pas toujours possible. Entre les deux premiers types c'est souvent une question de goût.
En fait, dans tous les langages de programmation structurée, il suffit de l'un des deux premiers types de boucles pour obtenir les deux autres (si on dispose de l'alternative que nous verrons dans la section suivante). En langage C la sémantique de la boucle Pour est telle qu'il suffit même de ce seul type de boucle.
Cours, éxercices ou graphismes libre de droit. Un mail est souhaitable | Webmestre : Aublet Bastien (bastien.aublet@hotmail.fr)