Jean-Jacques BOURDIN

Université Paris 8
Labo IA, Dépt. Programmation et Informatique Fondamentale
2, rue de la Liberté
93526 Saint-Denis Cedex
FRANCE


Programmation Impérative
Imperative Programming

Summer 2024
Flow control




Overview

Ch I) Let‘s try!

Ch II) Easy C

    II.A) Variables, Expressions, Types, Instructions
    II.B) Operators
    II.C) Control Flow
    II.D) Data Structures

Ch III) C Addresses

Ch IV) C more than that



 

 


    II.C) Flow control
Structures de Contrôle

    II.C.1) Plant-Page
"If there are two paths you can go by There is still time to change the road you‘re on"

Déjà vu.
Il faut simplement remarquer qu'il est possible d'enchaîner les if et les else, c'est même parfois plus joli (mais plus logique ?).
int fibifif (int n) {
  if (n == 0) {
     return 1;
  }
  else if (n == 1) {
          return 1;
       }
       else {
          return fibifif(n-1) + fibifif(n-2);
       }
  }
}

    II.C.2) Pink Floyd
If I were to sleep, I could dream
If I were afraid, I could hide
If I go insane, please don't put
Your wires in my brain

Just another "if"?
Il s'agit d'un if étendu où la comparaison ne se passe que sur la valeur "littérale". Exemple :
int fibsw (int n) {
  switch (n) {
  case 0:
    return 1;
  case 1:
    return 1;
  default:
    return fibsw(n - 1) + fibsw(n - 2);
  }
}

Let's try another example:
void lecase (int n) {
  switch (n) {
  case 0:
	printf("C est nul\n");
  case 1:
	printf("C est unique\n");
  case 2:
	printf("La paire\n");
  case 3:
	printf("La trinite\n");
  }
  printf("\n");
}

int main(){
  lecase(5);
  lecase(3);
  lecase(1);
  lecase(2);
  lecase(0);
  return 0;
}

What's that?
neige: a.out
La trinite

C est unique
La paire
La trinite

La paire
La trinite

C est nul
C est unique
La paire
La trinite
neige: 
The "case"s are not working as "if then" but as entry point in a sequence.
    II.C.3) Harrison
  1. while
    While my guitar gently weeps (G. Harrison)

    Trad. tant que ma guitare pleure doucement

    While the condition stands, we do the work. It‘s an iteration.
    Tant que la condition est remplie, on fait ce qui suit. Il s'agit d‘une itération.
    int somw (int n) {
      int i, som;
      
      i = 0;
      som = 0;
      while (i < n) {
        som = som + i;
        i = i + 1;
      }
      return som;
    }

  2. do while
    Looks a lot like a while but the first iteration is always done.
    C‘est exactement la même chose que le while, mais on ne fait le test qu‘après une première itération.
    int somdo (int n) {
      int i, som;
     
      i = 0;
      som = 0;
      do {
        som = som + i;
        i = i + 1;
      } while (i < n);
      return som;
    }

    Write with while or do-while each of the following fonctions:
    Vous devez écrire avec des whiles ou des do-while, donc en itératif :
    1. Somme des carrés des n premiers entiers
    2. Somme des cubes des n premiers entiers
    3. Somme des puissance quatre des n premiers entiers
    4. Produit des n premiers entiers
    5. Produit des carrés des n premiers entiers
    6. Produit des cubes des n premiers entiers
    7. Produit des puissances quatre des n premiers entiers
    8. Exponentiation (x puissance n)
    9. Somme des puissances p des n premiers entiers
      sompn(2,4) = 0^4 + 1^4 + 2^4 = 17
    10. Additions par incrémentations successives
      On suppose ne savoir faire des additions que de +1 ou -1.
      L'addition de deux valeurs add(a+b) peut être ramenée à l'addition de a+1 et celle de b-1 n'est-ce pas ?
      Écrivez la fonction itérative qui fait ainsi l'addition de deux valeurs.
    11. Soustractions de deux valeurs
      Ici encore avec uniquement des +1 et -1.
    12. Multiplication russe
      Il s'agit de faire la multiplication par additions successives.
    13. Division entière itérative
    14. Reste de la Division entière
    15. Plus grand divieur commun de deux entiers
    16. Plus petit multiple commun de deux entiers
    17. Une fonction main qui appelle et affiche les résultats des précédentes

 

    II.C.4) Halley
One o'clock, two o'clock, three o'clock, rock
  1. Principle

    for is almost like while but for initial, and ending parts.

    For, c'est exactement la même chose que while à part que les instructions d'avant (l'initialisation) et de fin de boucle (incrémentation) sont, en général, incluses dans les "paramètres" de l'instruction.

    First example, the computation of the sum of the n first integer numbers.
    Premier
    exemple, le calcul de la somme des n premiers entiers :

    int somf (int n) {
      int i, som;
      
      i = 0;
      som = 0;
      for (/* void_1 */ ; i < n; /* void_2 */ ) {
        som = som + i;
        i = i + 1;
      }
      return som;
    }

    Was it a for or a while?
    Dans ce cas le "for" est un "while".

     

  2. Deuxième exemple :
    int somf2 (int n) {
      int i, som;
      
      /*void_1*/
      som = 0;
      for ( i = 0 ; i < n; i = i + 1 ) {
        som = som + i;
        /* void_2 */
      }
      return som;
    }

  3. Exercices
    Don‘t hesitate to write again your recursive functions with a for.
    Il faut, à ce stade, reprendre une partie de la liste des fonctions (sommes, factorielles, exponentiation, y compris Fibonacci) avec des for.

 

    II.C.5)Percy Mayfield
and don‘t you come back no more, no more, no more
Special statements
Instructions d'échappement
  1. return

    Déjà vu.

    Return exits from the function when it's executed.

  2. break

    Break exits from a control flow. Examples:

    Pour interrompre une itération (sortir de la structure de contrôle). Exemples :
    int sombr (int n) {
       int i, s;
       i = 0;
       s = 0;
       while (1) {
          s = s + i;
          i = i + 1;
          if (i > n) {
             break;
         }
       }
       return s;
    }
    
    a do while would have been clearer.
    Un do while aurait fait la même chose mais eut été plus clair...
    int valeur (int n) {
       int s;
    
       s = 0;
       switch (n) {
       case 0:
         s = 0;
       case 1:
         s = s + 1;
       case 2:
         s = s + 2;
       case 3:
         s = s + 3;
       default:
         s = s + n;
       }
       return s;
    }

    Qu'obtient-on après l'appel de :
    valeur (2);
    valeur (3);
    valeur (1);
    valeur (5);
    
    Autre version, sans doute plus claire :
    int valeur (int n) {
       int s;
    
       s = 0;
       switch (n) {
       case 0:
         s = 0;
         break;
       case 1:
         s = s + 1;
         break;
       case 2:
         s = s + 2;
         break;
       case 3:
         s = s + 3;
         break;
       default:
         s = s + n;
         break;
       }
       return s;
    }

    Every case needs a break or a return or of a comment /*NOBREAK*/

    Tous les case doivent être suivis d'un break ou d‘un return ou, sinon, d'un /*NOBREAK*/

  3. continue
    To go to the next iteration, use continue
    Pour reprendre une itération (revenir à la structure de contrôle). In this example, one sees that continue goes to the next iteration.
    Sur cet exemple, où on voit que le continue passe bien à l'itération suivante  :
    #include <stdio.h>
    
    int impair (int n) {
      int i, res;
      res = 0;
      for (i = 0; i < n; i = i + 2) 
    	;
      return i - n;
    }
    int somp (int n) {
      int s, i;
    
      s = 0;
      for (i=0; i <=  n; i = i + 1) {
    	if (impair(i)) {
    	  printf("%d est impair\n",i);
    	  continue;
    	}
    	s = s + i;
      }
      return s;
    }
    int main () {
      int a;
    
      a = 5;
      printf("Somme des pairs jusqu a %d : \t %d\n", a, somp(a));
      a = 6;
      printf("Somme des pairs jusqu a %d : \t %d\n", a, somp(a));
      a = 7;
      printf("Somme des pairs jusqu a %d : \t %d\n", a, somp(a));
    }
    
    Blanc14.local: a.out
    1 est impair
    3 est impair
    5 est impair
    Somme des pairs jusqu a 5 : 	 6
    1 est impair
    3 est impair
    5 est impair
    Somme des pairs jusqu a 6 : 	 12
    1 est impair
    3 est impair
    5 est impair
    7 est impair
    Somme des pairs jusqu a 7 : 	 12
    
  4. goto and label

    Don‘t use it except for handling errors.
    Le plus souvent utilisé pour les gestions d‘erreurs graves.

    /* Just let's have mo'fun */
    #include <stdlib.h>
    #include <stdio.h>
    
    int funct (int n) {
      int a, b, c;
      a = 1;
      b = 1;
      c = 2;
      if (c > n) {
    	return a;
      }
     cas_general:
      a = a + b;
      b = a - b;
      c = c + 1;
      if (c <= n) {
    	goto cas_general;
      }
      return a;
    }
    int fonct (int n) {
      int a, b;
      a = 1;
      b = 1;
      do {
    	a = a + b;
    	b = a - b;
    	n = n - 1;
    	if (1 > n) {
    	  goto cas_sortie;
    	}
      } while(1);
     cas_sortie:
      return b;
    }
    int finct (int n) {
      int a, b, c;
      if (n > 24) {
    	a = -1;
    	goto la_sortie;
      }
      a = 1;
      b = 1;
      c = 2;
     cas_retour:
      if (c > n)
    	goto la_sortie;
      a = a + b;
      b = a - b;
      c = c + 1;
      goto cas_retour;
     la_sortie:
      return a;
    }
    main () {
      int i;
      for (i = 0; i < 10; i = i + 1) {
    	printf("Pour %d on a \t%d\t",i,funct(i));
    	printf("et\t %d ",fonct(i));
    	printf("et\t %d\n",finct(i));
      }
    }
    

    Qui donne à l‘exécution :
    Pour 0 on a 	1	et	 1 et	 1
    Pour 1 on a 	1	et	 1 et	 1
    Pour 2 on a 	2	et	 2 et	 2
    Pour 3 on a 	3	et	 3 et	 3
    Pour 4 on a 	5	et	 5 et	 5
    Pour 5 on a 	8	et	 8 et	 8
    Pour 6 on a 	13	et	 13 et	 13
    Pour 7 on a 	21	et	 21 et	 21
    Pour 8 on a 	34	et	 34 et	 34
    Pour 9 on a 	55	et	 55 et	 55
    

    label and GOTO work only inside a function. To go to another function, one will use the long jumps, see you next year.

    Pour l‘instant, les labels et gotos ne fonctionnent que au sein d‘une fonction. Pour passer d‘une fonction à une autre, il faudra utiliser les saut plus longs, les "long jump" (rendez-vous en Programmation Avancée).

     

  5. Quelques rappels
  6. Other examples

    #include <stdio.h>
    
    float racine (float x) {
      float y, pas;
      pas = 0.0001;
    
      y = 0.0; // initialisation
      while ( 1 ) { 
        if ( y * y >= x) {
          break;
        }
        y += pas; //incrémentation
      }
      /*
      y = 0.0; // initialisation
      while ( y * y < x) { // test
        //    printf(" %f ", y);
        y += pas; //incrémentation
      }
    
      for (y = 0.0; y * y < x; y += pas) {
        printf(" %f ", y);
      }
      */
      printf("\n");
      return y;
    }
    int impair (int n) {
      while (n > 1) {
        n -= 2;
      }
      if (n==1) {
        return 1;
      }
      return 0;
    }
    int sommepairs (int n) {
      int i, somp;
      somp = 0;
      for (i = 0; i ≤ n; i++) {
        if (impair(i)) {
          continue;
        }
        somp = somp + i;
      }
      return somp;
    }
    int sommepairsgt (int n) {
      int i, somp;
      somp = 0;
      i = 0;
     debut_boucle:
      if (impair(i)) {
        goto incrementation;
      }
      somp += i;
     incrementation:
      i += 1;
      if (i ≤ n) {
        goto debut_boucle;
      }
      return somp;
    }
    int main () {
      float val, rac;
      int a, b, c;
      
      val = 2.0;
      rac = racine (val);
      printf("la racine de %f est %f\n", val, rac);
      for (a = 0; a < 10; a++) { 
        b = sommepairs(a);
        c = sommepairsgt(a);
       printf("jusqu a %d on a %d ou %d\n", a, b, c);
      }
    }
    

 

 

 

 

 


Dernière mise à jour le 6/9/2024 16h00