Jean-Jacques BOURDIN

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


Programmation Impérative
Imperative Programming

Winter and Spring 2023




Overview

Ch I) Let's try!

    I.A) Functions

    I.B) Main Street

    I.C) Conditions

    I.D) Recursivity

    I.E) Convergence

    I.F) Tail Recursive

Ch II) Easy C

    II.A) Variables, Expressions, Types, Instructions

    II.B) Operators

    II.C) Control Flow

    II.D) Data Structures

    II.E) Compilation

Ch III) C Addresses

    III.A) Déjà vu

    III.B) Arrays

    III.D) Lists

    III.D) Trees

    III.C) Functions' Pointeers

Ch IV) C more than that

    IV.A) Compilation

    IV.B) Files

    IV.BC Arithmetics

 

 


Overview


    The C Language

    Le Langage C

History, qualities, problems, future...
Quand, pourquoi, pourquoi pas, jusqu'à quand, qui, qu'est-ce...

    Organisation du Cours

    About this course

Class + Lab
Cours + TP
Two written tests, one project (by pairs of students)
Deux partiels, un projet à faire en binômes.

Bibliographie sommaire

Some bindings will help you to use emacs. You'll find some at this page , you can also type, within emacs, Esc x and "describe-bindings".
Une série de raccourcis est disponible dans ce fichier, vous en trouverez d'autres en tapant Esc x puis "describe-bindings" sous emacs.

 

 

 

 


Ch I) Let's try!


    I.A) Functions

    I.B) Main Street

    This function has to be linked to another one, the most important one: the main function.
    Cette fonction doit être accompagnée de celle qui la commande, la grande fonction, la principale, main.

    Both will be inside a simple file:
    L'ensemble sera écrit et placé dans un fichier :
    cours23_01.c.
  1. A file
    int square (int n) {
      return n * n;
    }
    int main () {
      printf("le carre de 3 est %d\n",square(2));
    }
    

     

  2. to Compile
    Then you have to translate this file to machine language. Our compiler is called gcc.
    Il faut ensuite traduire ce texte en langage machine. Notre traducteur (compilateur) se nomme gcc:
    otake: cat cours23_01.c
    int square (int n) {
      return n * n;
    }
    main () {
      printf("le carre de 3 est %d\n",square(2));
    }
    otake: gcc cours23_01.c
    otake: ls -l
    -rw-r--r--    1 jj       users        103 Jan 18 18:06 cours23_01.c
    -rwxr-xr-x    1 jj       users      12264 Jan 18 18:07 a.out
    

  3. and execute
    otake: a.out
    le carre de 3 est 4

    You may correct a semantic error.
    Vous pouvez corriger afin d'arriver à une phrase plus logique.

    I.C) Conditions

"S'il fait laid à droite, je prends à gauche" (Michel de Montaigne)

You might need to do something if a certain condition is met. For example you don't take the road if there is a no entry sign.
Parfois il est nécessaire d'agir de façon différenciée, d'où le if.
/* which one is bigger? */
int maxi2 (int a, int b) {
    if ( a < b ) {
       return b;
    }
    else {
       return a;
    }
}

Vous devez écrire :

  1. la fonction qui trouve le plus grand parmi trois nombres entiers ;
  2. la fonction qui trouve le plus grand parmi quatre nombres entiers ;
  3. la fonction qui trouve le plus petit parmi cinq nombres entiers ;
  4. la fonction qui trouve le second plus grand parmi trois nombres entiers ;
  5. la fonction qui trouve le second plus grand parmi quatre nombres entiers ;
    sec4(7,3,2,9)==7
  6. la fonction qui trouve le second plus grand parmi cinq nombres entiers ;

 

    I.D) Recursivity

Be careful
Every time one wants to use the recursivity, one has to follow the following steps:

  1. Find an example with an easy to find result.
  2. Find a general rule, recursive.
  3. Verify that the general rule tends to the easy solution.

Attention :

Toute formulation récursive doit suivre les étapes suivantes :
  1. Trouver un cas particulier dont la valeur est donnée.
  2. rouver une règle générale qui donne une solution à partir d'elle-même.
  3. Vérifier que cette règle générale rapproche du cas particulier.
Example: a function to compute the sum of the first numbers to n.
Une fonction qui calcule la somme des premiers entiers jusqu'à n :
som(n) = 0 + 1 + 2 + 3 + ... + (n-1) + n
At first we find a number n, with its result
Cherchons un n avec son résultat
som(0) = 0
Then we find a general formula:
Nous trouvons d'abord une formulation récursive de cette suite :
som(n)   = 0 + 1 + 2 + 3 + ... + (n-1) + n
som(n-1) = 0 + 1 + 2 + 3 + ... + (n-1)
Therefore
som(n) = som (n-1) + n
The general term is closer to the individual than the previous one (n-1 is closer to 0 than n, the convergence is proved as n is a natural).
We have now a general case and a singular case, the general case tends forward to the singular one.

Il y a bien un cas particulier et une règle générale. La règle générale rapproche du cas particulier.
int som (int n) {
   if ( n < 1 ) {
      return 0;
   }
   else {
      return n + som (n-1);
   }
}

Vous devez écrire :

  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 récursive 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 et récursive
  14. Reste de la Division entière
  15. Plus grand diviseur commun de deux entiers
  16. Plus petit multiple commun de deux entiers
  17. Pour trouver l'entier x supérieur ou égale à la racine carrée d'un nombre a, il suffit de passer en revue tous les entiers jusqu'à avoir dépassé la racine.
    Faites la fonction C correspondante.
  18. Vous venez de trouver un nombre x supérieur ou égal à la racine carrée d'un autre nombre a. Vous savez donc que x et x-1 encadrent la racine. Faire une fonction qui renvoie celle de ces deux valeurs qui est la plus proche de la racine.

 

  • Of course you'll need also the main function to test all these functions.
  • Avec, bien sûr, une fonction main qui appelle et affiche les résultats des précédentes.
  • Note that you're not allowed to use not already presented functions or tools.
  • Attention, ce qui n'a pas encore été vu ne doit pas être utilisé.
  • Tout programme non testé est réputé faux.
  • If you didn't try it, it didn't work.
  • Si vous voulez d'autres exercices, il suffit de demander...

     

  • You should know about Fibonacci sequence: 1, 1, 2, 3, 5, 8, 13, 21...
    A formulation can be given as:

    La suite de Fibonacci est connue pour sa forte progression. Les premières valeurs sont calculées par :

       f(0) = 1
       f(1) = 1
       f(n) = f(n-1) + f(n-2)
    

    Just write the program and test it.

    Vous pouvez maintenant tester cette suite célèbre.

    Il faut la programmer et essayer différentes valeurs. On doit obtenir :

    1 1 2 3 5 8 13 21 34 55 89 144

        I.E) Convergence

    You always must verify the convergence of a recursive formula.
    La question de la convergence d'une formule récursive doit toujours être posée et résolue avant la programmation. Elle repose sur la méthode vue ci-dessis :
    1. Find a boundary value.
    2. In the general term,
    3. verify that the argument of the call is closer to the boundary value than the initial term. If it's in discrete maths, then the convergence is met.
    1. vérifier l'existence d'une borne, c'est-à-dire d'une situation de fin,
    2. dans la formule récursive, vérifier que le nouvel appel est plus près de la fin que la formule précédente
    3. vérifier que ce rapprochement est discret (si on avance de 1 en 1 vers 0, à partir d'une valeur entière, on va, certainement y arriver).
    Example Fibonacci.
    Two boundaries are given, f(0) and f(1).
    In the general term, to compute f(n) one needs to compute f(n-1) and f(n-2). These values are closer to 0 and 1 than n. n, n-1, n-2 are integers therefore it converges.

    Exemple, pour Fibonacci, il y a deux valeurs de fin, f(0) et f(1).
    Dans la formule récursive, à partir d'un certain n, (on cherche à calculer f(n)), on doit calculer f(n-1) et f(n-2) donc le paramètre est plus près de 0 ou 1 que le n initial. Comme ces valeurs sont discrètes, on arrive forcément à l'une des bornes.

     

        I.F) Tail-recursive
    Récursivité terminale

    A function is tail recursive is the recursive call is the last thing to be evaluated by the function.

    On parle de récursivité terminale lorsque l'appel récursif est la dernière action de la fonction, c'est-à-dire lorsque le résultat obtenu par cet appel est le résultat de la fonction appelante.
    Exemple :
    som (int n) {
      if (n == 0) {
         return 0;
      }
      else {
         return n + som (n-1);
      }
    }

    This function is clearly not tail-recursive as when som(n-1) will be known, an addition will be computed.
    n'est pas récursif terminal : après l'obtention du résultat de som(n-1) il faut encore faire une addition avec ce résultat. Par contre,
    int somrec (int n) {
      return somrec_aux (n,0);
    }
    int somrec_aux (int n, int s) {
      if (n <= 0) {
        return s;
      }
      else {
        return somrec_aux (n-1, s+n);
      }
    }

    est récursif terminal. Il faut, le plus souvent, transmettre non seulement le paramètre, mais aussi un accumulateur (ici s), à chaque appel de fonction.

    To obtain a tail-recursive function, one has to add an accumulator argument which store the computation and tends to the solution.
    Voici un exemple de fonction main pour tester somrec :
    main () {
      printf("som(%d)==\t%d\n",4,somrec(4));
      printf("som(%d)==\t%d\n",5,somrec(5));
      printf("som(%d)==\t%d\n",6,somrec(6));
    }

    We'll try now with the multiplcation.
    Essayons avec autre chose. Par exemple la multiplication par additions successives. La formule globale est :

    m(a,0) = 0
    m(a,b) = b + m(a-1,b)
    This expression is an addition so the neutral element is 0. The accumulator starts then at 0.
    L'opération principale est ici une addition. Son élément neutre est 0. L'accumulateur commencera à 0.
    The general term is :
    Si on veut faire, au fur et à mesure, ces additions, il faut, à chaque étape, ajouter b.
    M(a,b,som) = M(a-1,b,som+b)
    One can see that the third argument starts with 0 than 0+b, then 0+b+b and so on.
    Dans ce cas, petit à petit, on va se diriger vers a valant 0 et le troisième argument valant b+b+b+...+b (en tout, a(initial) fois). Comme ce troisième argument reçoit des valeurs en les ajoutant, il convient de lui donner une valeur initiale nulle.

    int mulrecter (int a, int b) {
      return mulrecter_aux (a, b, 0);
    }
    int mulrecter_aux (int a, int b, int som) {
      if (a == 0) {
        return som;
      }
      else {
        return mulrecter_aux (a-1, b, som + b);
      }
    }

    Exercices
    You have to write every recursive function done earlier in a tail recursive form. The Fibonacci sequence has to be done also as tail recursive.
    Reprendre les fonctions précédentes (somme, produit, puissance, Fibonacci...) et les programmer en utilisant la récusivité terminale.


    Dernière mise à jour le 22/1/2023 10h00