Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Langage C
  3. Les contrôles des blocs d'instructions
Extrait - Langage C Maîtriser la programmation procédurale (avec exercices pratiques) (2e édition)
Extraits du livre
Langage C Maîtriser la programmation procédurale (avec exercices pratiques) (2e édition)
2 avis
Revenir à la page d'achat du livre

Les contrôles des blocs d'instructions

Blocs d’instructions et conditions

Voici quelques questions pour vous aider à synthétiser et retenir des contenus qui nous paraissent essentiels dans cette section :

Qu’est-ce qu’un bloc d’instruction ?

À quoi sert un bloc d’instructions ?

Pourquoi définir une condition ?

Comment définir une condition ?

Quels sont les opérateurs de comparaison ?

Comment sont évaluées des conditions ?

Comment fonctionne l’opérateur unaire « NON » noté ! (point exclamation à gauche d’une expression) ?

1. Qu’est-ce qu’un bloc d’instructions ?

a. Définition

  • Un bloc d’instructions est UNE instruction composée de plusieurs instructions qui se suivent.

  • En C (et tous les langages dérivés), il est délimité avec les opérateurs { } (accolades ouvrante et fermante).

  • Un bloc peut contenir d’autres blocs imbriqués.

  • Dans un fichier source, il ne peut pas y avoir d’instruction en dehors d’un bloc (sauf directives macroprocesseur et déclarations de variables globales ou de fonctions). Pour être valides, toutes les instructions doivent être localisées dans un bloc. Le bloc au sommet est celui de la fonction main() qui réunit in fine toutes les instructions du programme.

b. Exemple

#include <stdio.h> 
#include <stdlib.h> 
 
int main() 
{  //------------------------- ouv bloc main B1 
int x,pasx;    // déclarations de variables locales au bloc main 
               // elles sont visibles (accessibles) dans ce bloc 
               // et tous les sous-blocs 
 
   {  //----------ouv B2 
      int c; 
      x=0; 
      c=rand()%256; 
      pasx=rand()%5; 
   }  // ---------ferm B2 
   x=640; 
 
   {  // ---------ouv B3 
      //c=10;...

Sauts conditionnels

Voici quelques questions pour vous aider à synthétiser et retenir des contenus qui nous paraissent essentiels dans cette section :

Comment fonctionne l’instruction if ?

Comment fonctionne l’instruction if suivie de else ?

Comment fonctionne l’instruction if suivie d’un ou plusieurs else if ?

1. L’instruction if

SI et seulement si l’expression est vraie, ALORS le bloc des instructions associées au if est exécuté. Il ne peut y avoir qu’un seul bloc associé au if.

if ( expression1 vraie){ 
    bloc instructions; 
} 

Par exemple, soit une variable a, dans un programme on peut écrire :

if ( a >=100 ){    // test 
    printf( "a est supérieur ou égal à 100 \n"); // instruction 
} 

Derrière un if il ne peut y avoir qu’un seul bloc, c’est-à-dire une seule instruction. S’il y a plusieurs instructions il faut ouvrir et fermer le bloc mais s’il n’y en a qu’une, c’est inutile. L’exemple précédent peut s’écrire sans erreur à la compilation :

if ( a >=100 ) 
    printf( "a est supérieur ou égal à 100 \n"); 

Attention à l’indentation, c’est inutile pour la machine, en revanche c’est absolument nécessaire professionnellement pour rendre son code lisible.

Dans le cas d’une succession de if, chacun fait l’objet d’une évaluation :

if ( expression1 vraie){ 
    bloc instructions 1; 
} 
if ( expression2 vraie){ 
    bloc instructions 2; 
} 
if ( expression3 vraie){ 
    bloc instructions 3; 
} 

Seuls les blocs dont la condition est vraie seront effectués : aucun, quelques-uns ou tous.

Des if peuvent être imbriqués, dans ce cas ils ne seront peut-être pas tous effectués, la série s’arrêtera au premier test faux rencontré :

if ( expression1 vraie){ 
    bloc instructions 1; 
    if ( expression2 vraie){ 
        bloc instructions...

Branchements

Voici quelques questions pour vous aider à synthétiser et retenir des contenus qui nous paraissent essentiels dans cette section :

Comment fonctionne le switch ?

Qu’est-ce qu’un case ?

Qu’est-ce qu’un break ?

1. Branchement sélectif : switch, case et break

Une suite de if, else if, else comme :

if (i==0){ 
   instructions0; 
} 
else if (i==1){ 
   instructions1; 
} 
else if (i==7){ 
   instructions7; 
} 
else if (i==55){ 
   instructions55; 
} 
else{ 
   instructions_n; 
} 

peut être remplacée par un switch qui est un aiguillage. Il fonctionne de la façon suivante :

switch(valeur_expression){ 
 
   case expression_constante_1 : 
          instructions1; 
          break; 
 
   case expression_constante_2 : 
          instructions2; 
          break; 
 
   case expression_constante_3 : 
          instructions3; 
          break; 
 
   default : 
          instructions_n; 
          break; 
} 

Le bloc des instructions à exécuter est décidé à partir de la valeur de l’expression en paramètre du switch :

  • Si ce paramètre vaut expression_constante_1, instructions1 sont exécutées.

  • Si ce paramètre vaut expression_constante_2, instructions2 sont exécutées.

  • Si ce paramètre vaut expression_constante_3, instructions3 sont exécutées.

  • Si ce paramètre a une autre valeur que les différents cas proposés, instructions_n sont exécutées.

Il n’y a pas de limite au nombre de cas possibles. Mais chaque cas est identifié par une valeur constante, c’est-à-dire non variable après...

Les tests multiconditions (ET/OU)

Voici quelques questions pour vous aider à synthétiser et retenir des contenus qui nous paraissent essentiels dans cette section :

C’est quoi le ET ?

Combien de ET je peux avoir dans une même expression ?

C’est quoi le OU ?

Combien de OU je peux avoir dans une même expression ?

Est-il possible d’avoir une expression qui mélange ET et OU ?

Qui alors est prioritaire le ET ou le OU ? Que faire si on a oublié ?

1. Conjonction ET : opérateur &&

a. ET avec deux expressions membres

Soient deux expressions, E1, E2.

l'expression E1 && E2 : 
   - est vraie (vaut 1) si E1 ET E2 sont vraies, 
   - est fausse sinon (vaut 0). 

Exemple :

int a = rand()%300; 
    if (a >= 100 && a<=200) 
           printf("a compris entre 100 et 200\n"); 

Le test vaut 1 si la valeur de a est comprise dans la fourchette 100-200 bornes comprises, 0 sinon.

Autre exemple, à la douane :

#include <stdio.h>  
 
int main() 
{ 
    char papier = 0, declarer = 0; 
 
    printf("Vous avez vos papiers ? (o/n)\n"); 
    scanf_s("%c", &papier, 1); 
    // lorsqu'il y a plusieurs appels successifs de scanf_s()  
    // il s'avère nécessaire de réinitialiser le buffer d'entrée (stdin) 
    // avec la fonction rewind()  
    rewind(stdin); 
 
    printf("Quelque chose a declarer ? (o/n)\n"); 
    scanf_s("%c", &declarer, 1); 
    rewind(stdin); 
 
    if (papier == 'o' && declarer == 'n') 
        printf("C'est bon, vous pouvez passer\n"); 
    else 
        printf("Attendez la s'il vous plait\n"); 
 
    return 0; 
} 

Si le voyageur a ses papiers et n’a rien à déclarer...

Boucles

Voici quelques questions pour vous aider à synthétiser et retenir des contenus qui nous paraissent essentiels dans cette section :

À quoi sert une boucle ?

Fonctionnement et syntaxe de la boucle while ?

Fonctionnement et syntaxe pour la boucle do{…}while ?

Qu’est-ce qui différencie un while d’un do-while ?

Fonctionnement et syntaxe pour la boucle for ?

Est-il possible d’avoir une boucle dans une boucle ?

L’instruction  « break » peut-elle être utilisée avec une boucle ?

Pourquoi faire ?

À quoi sert l’instruction « continue » ?

1. Boucle TANT QUE : le while

La boucle while a la forme suivante :

while (expression vraie){ 
    instructions; 
} 

Tant que la valeur de l’expression est vraie, c’est-à-dire non nulle et différente de 0, les instructions du bloc lié à la boucle sont répétées. Pour que la boucle puisse s’arrêter, il faut que l’expression devienne fausse et pour ce faire une des composantes du test doit être modifiée dans le bloc des instructions. Par exemple :

int a=3,i=0; 
   while (i<a){ 
       i++; 
       printf("i vaut %d\n",i); 
   } 
   printf("Fin de la boucle avec i=%d \n",i); 

Tant que i est inférieur à a, les instructions sont exécutées :

au départ a vaut 3 et i vaut 0 : 
 
i < a : le test est vrai, les instructions sont effectuées, i est 
augmenté de 1 et i vaut 1. 
 
i < a : le test est vrai, les instructions sont effectuées, i est 
augmenté de 1 et i vaut 2. 
 
i < a : le test est vrai, les instructions sont effectuées, i est 
augmenté de 1 et i vaut 3. 
 
i < a : le test est faux, fin de la boucle, poursuite de l'exécution 
avec les instructions qui suivent le bloc de la boucle. 

Le test peut être faux dès le départ et dans ce cas les instructions du bloc de la boucle ne sont pas exécutées, par exemple  :

#include <stdio.h>  ...

Utilisations typiques de boucles

Voici quelques questions pour vous aider à synthétiser et retenir des contenus qui nous paraissent essentiels dans cette section :

Comment créer un menu utilisateur ?

Qu’est-ce qu’une boucle d’événement dans un jeu vidéo en console ?

Pourquoi les fonctions _kbhit() et _getch() ?

Comment afficher les valeurs ascii des touches de n’importe quelle touche du clavier grâce à une boucle d’événements ?

Comment et pourquoi contrôler la rapidité d’exécution ?

Comment déplacer un joueur avec les flèches du clavier ?

1. Créer un menu utilisateur

Un programme qui se termine du fait d’une action de l’utilisateur repose toujours sur une boucle, c’est la base de sa dynamique. Pour créer un menu, le principe est de donner un choix de commandes à l’utilisateur via une interface et de mettre fin à la boucle si l’utilisateur le demande avec une commande spécifique. L’interface simple que nous proposons offre à l’utilisateur quatre choix :

printf ( "1 : Affiche bonjour\n" 
         "2 : Affiche il fait beau\n" 
         "3 : Entrer un nombre entier\n" 
         "0 : Quitter\n"); 

Ensuite le programme capture le choix de l’utilisateur et applique les traitements correspondants. Si l’utilisateur entre d’autres nombres que 0, 1, 2 ou 3, le programme signale qu’ils ne correspondent pas à des commandes :

#include <stdio.h> 
#include <stdlib.h> 
 
int main() 
{ 
int choix, res; 
    do{                                              // 1  
 
       printf ( "1 : Affiche bonjour\n"              // 2 
                "2...

Fonctions

Voici quelques questions pour vous aider à synthétiser et retenir des contenus qui nous paraissent essentiels dans cette section :

Qu’est-ce qu’une fonction ?

Où écrire sa fonction ?

Pourquoi écrire une fonction dans un programme ?

Comment utilise-t-on une fonction ?

Qu’est-ce qu’un appel de fonction ?

Comment récupère-t-on la valeur de retour ?

À quoi servent les paramètres ?

Que signifie passer une valeur à un paramètre ?

Quelle est la visibilité d’une fonction dans un programme ?

Qu’est-ce qu’une fonction récursive ?

1. Principe

La fonction est l’unité de traitement fondamentale du C, à la différence du C++ qui repose essentiellement sur la classe et l’objet :

  • Elle se retrouve souvent comme une étape dans la suite des opérations réalisées par un algorithme.

  • Elle permet de factoriser (généraliser) du code qui se répète. Lorsque dans un programme une séquence d’actions se répète, en général il y a une fonction à écrire pour éclaircir et alléger le code.

  • Elle permet de compléter une structure en établissant des actions possibles sur les données de la structure (voir le chapitre Les structures). Par exemple, dans un jeu vidéo un personnage devra être capable de se déplacer, de combattre, etc., et toutes les actions possibles du personnage seront déterminées par des fonctions associées à la structure représentant le personnage. Cette utilisation préfigure l’objet du C++.

Techniquement, la fonction est un bloc d’instructions doté d’un nom et de deux mécanismes :

  • Un mécanisme d’entrée de valeur : ce sont les paramètres en entrée.

  • Un mécanisme de sortie de valeur : la valeur de retour (unique).

Une fois écrite, la fonction est "appelée". L’appel de la fonction permet d’insérer le bloc des instructions de la fonction dans le déroulement du programme à l’endroit où elle est appelée. À ce moment, nous donnons pour son exécution des valeurs aux paramètres et, s’il...

Gestion des variables

L’écriture des fonctions nécessite de mieux connaître quelles sont la visibilité et la durée de vie d’une variable dans un programme.

Voici quelques questions pour vous aider à synthétiser et retenir des contenus qui nous paraissent essentiels dans cette section :

  • Quelle est la visibilité d’une variable ?

  • Quelle est la durée de vie d’une variable ?

  • Qu’est-ce qu’une variable globale ?

  • Qu’est-ce qu’une variable locale ?

  • Qu’est-ce qu’une variable static ?

1. Visibilité des variables

La visibilité et la durée de vie d’une variable sont relatives au lieu de sa déclaration dans le programme. Le niveau d’imbrication de bloc est appelé la profondeur de sa déclaration.

a. Profondeur de la déclaration

La déclaration est dite de profondeur 0 lorsqu’elle est en dehors de tout bloc d’instructions et de profondeur n avec n supérieur ou égal à 1 lorsqu’elle est dans un bloc ; n correspond au niveau d’imbrication du bloc concerné, par exemple :

#include<stdlib.h>            // niveau 0 en global, hors bloc 
int x=0; 
void test(int a); 
 
int main() 
{                             // bloc niveau 1 
int i=0; 
      {                       // bloc niveau 2 
      int  y=9; 
          {                   // bloc niveau 3 
          int w=rand(); 
              test(w); 
          } 
      } 
      test(i); 
} 
 
void test(int a) 
{                             // autre bloc niveau 1 
int b; 
            ...// instructions de la fonction 
} 

Le paramètre int a de la fonction test() est considéré comme de niveau 1, local à...

Style, commentaires et indentations

Voici quelques questions pour vous aider à synthétiser et retenir des contenus qui nous paraissent essentiels dans cette section :

Qu’est-ce que le style et à quoi sert-il ?

Comment choisir ses noms ?

Quelles sont les règles à respecter pour l’indentation et les accolades ?

À quoi faire attention dans un test (du point de vue du style) ?

Qu’est-ce qu’un commentaire pertinent ?

1. Pourquoi soigner le style ?

Le but du style de la programmation est de s’assurer que le code sera facile à lire et partageable au sein d’une équipe. Un bon style est indispensable à toute bonne programmation. 

Un programme sans rigueur est peu lisible, peu fiable, difficile à corriger et à comprendre. Il devient vite impossible à développer et se trouve finalement figé dans son incompréhensibilité. Plus un programme est rendu incompréhensible par l’absence de rigueur de sa présentation moins il est possible de continuer son développement, d’apporter des modifications ou des nouvelles fonctionnalités, voire tout simplement de le déboguer. Le style est finalement en relation avec l’efficacité de la conception. Aujourd’hui le style s’est normalisé et il est associé à des conseils et des recommandations qui varient très peu d’une communauté de développement à une autre.

Le style n’est pas secondaire, c’est une question de discipline, de rigueur et d’efficacité dans le travail. Montrez votre code et rien qu’à son style tout employeur saura si vous êtes professionnel ou non.

Le créateur du langage C, Brian Kernighan nous dit ceci à propos du style : "le code sera simple et limpide - logique claire et évidente, expressions naturelles, utilisation d’un langage conventionnel, noms compréhensibles et significatifs, formatage impeccable, commentaires utiles - et évitera les spécificités soi-disant astucieuses ainsi que les constructions inhabituelles. Il est important de rester cohérent car les tierces personnes trouveront ainsi votre code plus lisible - et vous aurez le même avis pour le leur - si vous faites tout sur le même...