Menu

Boucle while en C : syntaxe, exemples et erreurs courantes

Comment la boucle while du C répète jusqu'à ce qu'une condition change - la règle du test en premier, les boucles à sentinelle, la lecture d'entrée jusqu'à EOF, while(1), et la conversion entre for et while.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Répéter sans décompte

Une boucle for est le bon outil quand vous savez - ou pouvez calculer - combien de passages il vous faut. Beaucoup de travaux ne viennent pas avec un décompte. Lire chaque ligne d'un fichier jusqu'à sa fin. Redemander un mot de passe jusqu'à ce qu'il soit bon. Diviser un nombre par deux jusqu'à atteindre 1. Pour cela, la question n'est pas « combien de fois » mais « jusqu'à quand », et c'est exactement ce qu'exprime while.

Personne n'a calculé « sept » à l'avance. La boucle continue simplement tant que la condition tient.

Syntaxe et la règle du test en premier

while (condition) {
    // corps - s'execute tant que la condition est non nulle
}

La condition est testée avant chaque passage, y compris le premier. Trois conséquences :

  • Une boucle dont la condition est fausse au départ s'exécute zéro fois. while (0) { ... } n'exécute jamais le corps.
  • Ce que teste la condition doit être initialisé avant la boucle, sinon vous testez une valeur aberrante.
  • Quelque chose dans le corps doit finir par rendre la condition fausse, sinon la boucle ne se termine jamais.

Comme pour if, les parenthèses sont obligatoires et il n'y a pas de point-virgule après. Ce point-virgule égaré est la version boucle du même bug :

/* BUG: l'instruction vide est le corps - ceci tourne indefiniment */
while (i < 10);
{
    printf("%d\n", i);
    i++;
}

i n'est jamais incrémenté, donc la condition ne change jamais. gcc -Wall signale le corps vide.

La règle de véracité du C s'applique ici exactement comme dans if/else : la boucle continue tant que l'expression est non nulle, et s'arrête quand elle vaut zéro.

La forme standard : initialiser, tester, mettre à jour

Presque toute boucle while correcte a trois morceaux répartis en trois endroits :

Ce sont les trois mêmes parties que contient un en-tête de for, simplement pas rassemblées sur une ligne. D'où la réponse honnête à « for ou while ? » : si les trois morceaux portent sur un seul compteur, un for les met là où un lecteur peut les vérifier ensemble. Si la mise à jour est éparpillée dans un long corps, ou si la condition porte sur autre chose qu'un décompte, while est la forme la plus claire.

Oublier le morceau 3 est le bug de la boucle while. Si une boucle bloque, la première chose à vérifier est si le corps change réellement ce que la condition lit.

Les boucles à sentinelle

Une sentinelle est une valeur spéciale qui signifie « arrête ». Sommer des nombres jusqu'à ce que l'utilisateur saisisse 0 :

Le 99 après le 0 n'est jamais atteint - la sentinelle a terminé la boucle. Notez que le nombre de valeurs n'est jamais connu d'avance, ce qui est précisément pourquoi c'est un while.

Les chaînes C fonctionnent pareil : elles se terminent par une sentinelle '\0', donc en parcourir une est un while de manuel :

Lire l'entrée jusqu'à EOF

Le while le plus courant dans le monde réel lit l'entrée jusqu'à ce qu'il n'y en ait plus. La règle est de tester la valeur de retour de la fonction d'entrée, pas la valeur qu'elle a stockée.

getchar renvoie le caractère suivant, ou la constante EOF quand l'entrée est épuisée :

Deux détails qui comptent. c est un int parce que EOF est une valeur négative qui ne tient pas dans un char sur de nombreux systèmes - le déclarer char peut faire que la comparaison ne réussisse jamais. Et l'affectation est dans la condition : (c = getchar()) != EOF lit un caractère, le stocke et compare en une étape. Les parenthèses internes sont obligatoires, car != s'attache plus fort que = ; sans elles, vous stockeriez le résultat de la comparaison dans c. C'est l'un des rares endroits où une affectation dans une condition est idiomatique plutôt qu'un bug.

La même forme fonctionne avec scanf, dont la valeur de retour est le nombre d'éléments convertis avec succès :

int n;
while (scanf("%d", &n) == 1) {
    /* n contient un nombre valide */
}

La boucle se termine en fin de fichier et à la première entrée qui n'est pas un nombre, ce qui est généralement ce que vous voulez.

Ce que vous ne devriez pas écrire, c'est while (!feof(f)). feof indique si une lecture a déjà échoué, il est donc encore faux quand vous êtes sur le dernier élément, le corps s'exécute une fois de plus, et la lecture échoue - traitant des données périmées. Testez la lecture elle-même.

while (1) et break

Parfois, la condition de sortie n'est connue qu'au milieu du corps - après la lecture, mais avant le traitement. La réponse idiomatique est une boucle intentionnellement infinie avec une sortie explicite :

while (1) est toujours vrai, donc la seule façon d'en sortir est break (ou return, ou exit). Vous verrez for (;;) employé dans le même but ; ils compilent vers la même chose, et le choix d'une base de code est une question de style.

Utilisez cette forme quand le test de sortie appartient réellement au milieu du corps. Quand le test tient naturellement en haut, mettez-le dans la condition où un lecteur peut le voir - un while (1) dont l'unique break est la première instruction n'est qu'une condition déguisée.

Convertir entre for et while

Toute boucle for peut s'écrire en while et inversement. La correspondance est mécanique :

/* for */                          /* while equivalent */
for (init; cond; maj) {            init;
    corps;                         while (cond) {
}                                      corps;
                                       maj;
                                   }

Ainsi, ces deux-là affichent la même chose :

Le seul endroit où l'équivalence fuit est continue. Dans une boucle for, continue saute vers la mise à jour de l'en-tête, donc le compteur avance quand même. Dans la version while, continue saute directement à la condition et saute le i++ de la fin du corps - une boucle infinie instantanée :

/* BUG: continue saute i++, donc la boucle tourne indefiniment au premier nombre pair */
int i = 0;
while (i < 10) {
    if (i % 2 == 0) {
        continue;
    }
    printf("%d ", i);
    i++;
}

Si une boucle while utilise continue, assurez-vous que la mise à jour a lieu avant - ou utilisez un for, où l'en-tête le garantit.

Pièges courants

  • Rien ne met à jour la condition. Le corps doit changer ce que la condition lit. Si un programme bloque, regardez ici en premier.
  • Un point-virgule après l'en-tête. while (cond); fait de l'instruction vide le corps.
  • Tester une variable jamais initialisée. La condition s'exécute avant le corps, donc la valeur qu'elle lit doit déjà exister.
  • char au lieu d'int pour getchar. EOF ne tient pas dans un char ; la comparaison peut alors ne jamais être vraie, ou un octet légitime peut être pris pour EOF.
  • while (!feof(f)). Boucle une fois de trop. Testez la lecture.
  • Supposer que le corps s'exécute au moins une fois. Ce n'est pas le cas. Quand vous avez besoin d'un passage garanti - afficher un menu avant de vérifier le choix - c'est une boucle do-while.

Questions fréquentes

Comment écrit-on une boucle while en C ?

while (condition) { corps }. La condition est testée avant chaque passage, donc le corps ne s'exécute que tant que la condition est non nulle, et pas du tout si elle est fausse au départ. Quelque chose dans le corps doit finir par changer la condition, sinon la boucle ne se termine jamais.

Quelle est la différence entre for et while en C ?

Ils sont également puissants - tout for peut être réécrit en while. Utilisez for quand un compteur, sa limite et son pas vont ensemble dans un en-tête, et while quand la condition d'arrêt n'est pas un décompte : lire jusqu'à la fin de fichier, réessayer jusqu'au succès, ou boucler jusqu'à ce qu'un drapeau bascule.

Comment lire l'entrée jusqu'à EOF en C ?

Testez la valeur de retour de la fonction d'entrée, pas la valeur qu'elle a lue : while (scanf("%d", &n) == 1) { ... } s'arrête en fin de fichier ou à la première entrée non numérique, et while ((c = getchar()) != EOF) { ... } lit caractère par caractère. Ne bouclez jamais sur while (!feof(f)) - cela fait un tour de trop au-delà de la fin.

Pourquoi ma boucle while est-elle infinie en C ?

Généralement parce que rien dans le corps ne change la valeur que la condition teste, ou parce qu'un point-virgule égaré après l'en-tête (while (i < 10);) a fait de l'instruction vide le corps. Les deux compilent sans broncher, alors vérifiez que le corps met bien à jour la variable de la condition.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER