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

Winter and Spring 2024




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

    II.E) Compilation

Ch III) C Addresses

Ch IV) C more than that

 

 

    II.D) Data types
Structure de Données

    II.D.1) Variables

A variable is a triple : (name,type,location)(nom,type,lieu).
One needs to draw a variable with its box, where the value will be written.

Il convient donc de dessiner une variable avec sa "boite" associée.
The variable declarations have to be all in one place at the beginning of the function.
Les déclarations doivent être groupées en début de fonction. C'est même la première chose à faire lorsqu'on commence une fonction.

While lots of programmers don't apply that rule, lots of programmers spend more time than necessary on debugging.
Si cette règle n'est pas appliquée, ne vous étonnez pas de passer plus de temps en debugging que les autres...


Hereafter is an example given in class:
Voici l'exemple donné en cours
#include <stdio.h>

void etalors (int * pa, int *pb) {
  *pa = *pa + *pb;
  *pb = *pa - *pb;
  *pa = *pa - *pb;
}

int main () {
  int x, y;
  x = 5;
  y = 8;
  printf("Avant \t x : %d\t y %d\n", x, y);
  etalors(&x, &y);
  printf("Apres \t x : %d\t y %d\n", x, y);
}
    II.D.2) Enum
    Enumération
Just to build a limited set of values, of any kind.
#include <stdio.h>

enum sema {lundi, mardi, mercredi, jeudi, vendredi, samedi, dimanche};
enum week {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday};

void affiche_day (enum week d) {
  switch(d) {
  case Sunday:
    printf("Sunday ");
    break;
  case Monday:
    printf("Monday ");
    break;
  case Tuesday:
    printf("Tuesday ");
    break;
  case Wednesday:
    printf("Wednesday ");
    break;
  case Thursday:
    printf("Thursday ");
    break;
  case Friday:
    printf("Friday ");
    break;
  case Saturday:
    printf("Saturday ");
    break;
  }
}
void affiche_dday (enum week d) {
  switch((int) d) {
  case 0:
    printf("Sunday ");
    break;
  case 1:
    printf("Monday ");
    break;
  default:
    printf("otherday ");
    break;
  }
}
void affiche_jour (enum sema j) {
  switch(j) {
  case lundi:
    printf("lundi ");
    break;
  case mardi:
    printf("mardi ");
    break;
  case mercredi:
    printf("mercredi ");
    break;
  case jeudi:
    printf("jeudi ");
    break;
  case vendredi:
    printf("vendredi ");
    break;
  case samedi:
    printf("samedi ");
    break;
  case dimanche:
    printf("dimanche ");
    break;
  }
}

int main () {
  enum sema jour;
  enum week day;

  for (jour = lundi; jour <= dimanche; jour++) {
    affiche_jour(jour);
    day = (enum week) jour + 1;
    affiche_day(day);
    affiche_dday(day);
    printf("\n");
  }
  jour = vendredi;
    printf("\n\n\n");
    affiche_jour(jour++);
    printf("\n");
    affiche_jour(jour++);
    printf("\n");
    affiche_jour(jour++);
    printf("\n");
    affiche_jour(jour++);
    printf("\n");
    affiche_jour(jour++);
    printf("\n");
    affiche_jour(jour++);
    printf("\n");
    affiche_jour(jour++);
    printf("\n");
}
/*
Blanc14.local: a.out
lundi Monday Monday 
mardi Tuesday otherday 
mercredi Wednesday otherday 
jeudi Thursday otherday 
vendredi Friday otherday 
samedi Saturday otherday 
dimanche otherday 



vendredi 
samedi 
dimanche 




*/

You'll correct it, right?
Il va falloir agir, lundi n'est pas sunday !

#include <stdio.h>

enum boole {vrai, faux};

enum boole non (enum boole v) {
  switch (v) {
  case vrai : return faux;
  case faux : return vrai;
  }
}
enum boole et (enum boole v, enum boole w) {
  if (v == faux)
    return faux;
  if (w == faux)
    return faux;
  return vrai;
}
enum boole ou (enum boole v, enum boole w) {
  if (v == vrai)
    return vrai;
  if (w == vrai)
    return vrai;
  return faux;
}
void afficheb (enum boole v) {
  if (v == vrai)
    printf("vrai");
  else
    printf("faux");
  printf("    ");
}
    
int main () {
  enum boole a, b, c, d, e, f;
  printf(" a\t  b\t  c\t et\t ou\t b+1\n");
  f = 0;
  for (a = vrai; a <= faux; a = a + 1) {
    c = non (a);
    for (b = vrai; b <= faux; b = b + 1) {
      d = et (a, b);
      e = ou (a, b);
      f = f + 1;
      printf("%2d\t %2d\t %2d\t %2d\t %2d\t %2d\t \n",a, b, c, d, e, f);
    }
  }
  f = 0;
  printf("\n a\t  b\t  c\t et\t ou\t b+1\n");
  for (a = vrai; a <= faux; a = a + 1) {
    c = non (a);
    for (b = vrai; b <= faux; b = b + 1) {
      d = et (a, b);
      e = ou (a, b);
      f = f + 1;
      afficheb(a);
      afficheb(b);
      afficheb(c);
      afficheb(d);
      afficheb(e);
      afficheb(f);
      printf("\n");
    }
  }
  printf(" Taille de cet enum : %d\n", (int) sizeof(enum boole));
}

As you can see, the enum valeur is just a number, therefore that will not improve your program.
Vous pouvez remarquer que les enums ne sont que des nombres, dès lors ce n'est pas ainsi que vous pourrez accélérer vos programmes.

    II.D.3) Vectors
    Vecteurs
A vector is a set of values of the same type.
Un vecteur est un ensemble d'un certain nombre de valeurs du même type.

  1. Use
    Premiers usages
    Fill a vector with values
    Objectif placer dans un vecteur toutes les valeurs de la somme des n premiers entiers (pour tous les n).
    int somvec (int n) {
      int t [100];
      int i;
      t [0] = 0;
      if (n > 99) {
        return -1;
      }
      for (i=1; i <= n; i++) {
        t[i] = t[i-1] + i;
      }
      return t[n];
    }
    int main () {
      int v, res;
      v = 5;
      res = somvec(v);
      printf("som(%d)=%d\n",v,res);
      v = 6;
      res = somvec(v);
      printf("som(%d)=%d\n",v,res);
      v = 7;
      res = somvec(v);
      printf("som(%d)=%d\n",v,res);
    }
    


    Second example:
    Fill a vector with variable values
    Second exemple :
    Remplir un vecteur avec des valeurs quelconques.
    #include<stdio.h>
    
    void remplir (float vec [100], int nb) {
      float x, eps;
      int i;
      if (nb >= 100)
    	return;
      x = 1.5;
      eps = 0.173;
      for (i = 0; i < nb; i = i + 1) {
    	vec [i] = x;
    	x = x + eps;
    	if (x > 2.0)
    	  eps = 0.01 - eps;
    	if (x < 0.5)
    	  eps = 0.015 - eps;
      }
    }
    void voirvec (float vec [100], int nb) {
      int i;
      if (nb >= 100)
    	return;
      for (i = 0; i < nb; i = i + 1) {
    	printf("vec[%3d] == %f\n",i, vec [i]);
      }
    }
    int main () {
      int n;
      float vec [100];
      n = 20;
      remplir(vec, n);
      voirvec(vec, n);
    }
    
    The results are:
    Donne ceci :
    vec[  0] == 1.500000
    vec[  1] == 1.673000
    vec[  2] == 1.846000
    vec[  3] == 2.019000
    vec[  4] == 1.856000
    vec[  5] == 1.693000
    vec[  6] == 1.530000
    vec[  7] == 1.367000
    vec[  8] == 1.204000
    vec[  9] == 1.041000
    vec[ 10] == 0.878000
    vec[ 11] == 0.715000
    vec[ 12] == 0.552000
    vec[ 13] == 0.389000
    vec[ 14] == 0.567000
    vec[ 15] == 0.745000
    vec[ 16] == 0.923000
    vec[ 17] == 1.101000
    vec[ 18] == 1.279000
    vec[ 19] == 1.457000
    

    Another function, with integers this time.

    Autre fonction de remplissage d‘un vecteur, d‘entiers cette fois.

    Nouvelle version, à peine améliorée, du 5 février 2024.

    void remplirv (int nb, int vec[100]) {
        int crt, pre, new, i;
        crt = 13;
        pre = 21;
        vec[0]=pre;
        vec[1]=crt;
        for (i=2; i <= nb; i = 1 + i) {
           new = (crt + pre) % 23; // reste de la division
           vec[i] = new;
           pre = crt;
           crt = new;
        }
    }
    
  2. Liste d‘exercices à faire :

    Refaire tous les exercices itératifs en remplissant un vecteur au fur et à mesure et en utilisant les valeurs déjà dans le vecteur pour calculer les nouvelles, sur l‘exemple de somvec ci-dessus.

    Puis coninuez en remplissant le vecteur avec la fonction remplirv ci-dessus et faites :

    1. Faire une fonction qui renvoie le nombre d‘éléments nuls du vecteur.
    2. Faire une fonction qui renvoie le nombre d‘éléments du vecteur égaux à un certain x.
    3. Faire une fonction qui renvoie la première valeur du vecteur qui soit le carré d‘un entier ou -1 sinon.
    4. Faire une fonction qui renvoie la somme des valeurs du vecteur.
    5. Faire une fonction qui renvoie la somme des valeurs du vecteur inférieures à x.
    6. Faire une fonction qui affiche les valeurs du vecteur dans l‘ordre inverse.
    7. Faire une fonction qui renvoie la plus grande valeur du vecteur.
    8. Faire une fonction qui renvoie la plus petite valeur du vecteur.
    9. Faire une fonction qui renvoie la seconde plus petite valeur du vecteur.
    10. Faire une fonction qui renvoie la moyenne des valeurs du vecteur.
    11. Faire une fonction qui renvoie la médiane des valeurs du vecteur.
    12. Faire une fonction qui renvoie l‘écart-type du vecteur.
    13. Faire une fonction qui replace les valeurs du vecteur dans l‘ordre inverse.
    14. Fabriquez un autre vecteur dans lequel vous mettrez en premier l‘élément le plus grand élément du vecteur initial, puis en second le second plus grand, puis le troisième et ainsi de suite, le dernier élément du second vecteur sera le plus petit du vecteur de départ. Affichez le vecteur ainsi rangé.

      vecteur initial : [8, 13, 21, 11, 9, 20, 6, 3, 9, 12]
      Vecteur final : [21, 20, 13, 12, 11, 9, 9, 8, 6, 3]

    15. Faire une fonction qui insère une valeur dans un vecteur rangé en ordre décroissant.
      insere([1,2,6,9,10],5,8) donne un vecteur de 6 éléments : [1,2,6,7,8,9,10].
    16. Faire une fonction qui trie le vecteur dans l‘ordre décroissant grâce à la fonction ci-dessus.
    17. Faire une fonction qui trie le vecteur dans l‘ordre décroissant grâce à la fonction quicksort.

     

  3. With letters
    Avec des textes
    Let‘s replace lower case letters with upper case letters in a text.
    Et si nous nous amusions à remplacer les minuscules par des majuscules dans un texte ?

    /* jjb    */
    
    void replaceminparmaj (int nbc, char txt [1000]) {
      int i, diff;
    
      if (nbc > 999) {
        printf("\n\ntrop de texte\n\n");
        return;
      }
      for (i = 0; i < nbc; i++) {
        diff = txt[i] - ‘a‘;
        if (diff >= 0) {
          if (diff < 26) {
            txt[i] = (char) (‘A‘ + diff);
          }
        }
      }
    }
    void affitxt (int nbc, char t [1000]) {
      int i;
      for (i= 0; i < nbc; i++) {
        printf("%c",t[i]);
      }
      printf("\n");
    }
    void remplirtxt (int nbc, char t [1000]) {
      int i;
      for (i=0; i < 50; i++) {
        t[i] = (char) 'a' + (i % 26);
      }
      for (i=50; i < 60; i++) {
        t[i] = ' ';
      }
      for (i=60; i < 110; i++) {
        t[i] = (char) 'A' + (i % 26);
      }
      for (i=110; i < nbc; i++) {
        t[i] = ' ';
      }
    }
    /* on peut utiliser ce remplissage aussi */
    
    int remplirchaine(char ch [1000]) {
      ch [0] = 'J';
      ch [1] = 'e';
      ch [2] = ' ';
      ch [3] = 'F';
      ch [4] = 'a';
      ch [5] = 'i';
      ch [6] = 's';
      ch [7] = ' ';
      ch [8] = 'S';
      ch [9] = 'o';
      ch [10] = 'u';
      ch [11] = 'v';
      ch [12] = 'e';
      ch [13] = 'n';
      ch [14] = 't';
      ch [15] = ' ';
      ch [16] = '\0';
      return 16;
    }
    int main () {
      int nbc;
      char t [1000];
      nbc = 120;
      remplirtxt(nbc,t);
      affitxt(nbc, t);
      replaceminparmaj(nbc, t);
      affitxt(nbc, t);
      nbc = remplirchaine(t);
      affitxt(nbc, t);
      replaceminparmaj(nbc, t);
      affitxt(nbc, t);
    }
    }
    

    Just try it.

    Il ne reste plus qu'à essayer :

    neige: gcc ex16.c
    neige: a.out
    abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx          IJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF          
    ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWX          IJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF
    Je Fais Souvent 
    JE FAIS SOUVENT 
    

    As one might see, you always associate the number of elements of a vector to the vector itself when it is passed as argument.
    Remarquez bien que quand on veut transmettre un vecteur comme argument il est très important de transmettre aussi le nombre d‘éléments utilisés de ce vecteur.

  4. Soit un vecteur de caractères. Un mot est défini par des caractères et est séparé des autres mots par un ou des signes de ponctuation (virgule, point, espace...). Compter le nombre de mots d‘un vecteur de caractères. Pour ceci vous pouvez utilisez la fonction de remplissage ci-dessous.
    void remplirc (int nbc, char vc [1000]) {
      int i, j, k;
      char c;
      c = 'a';
      j = 3;
      k = 1;
      for (i = 0; i < nbc; i = i + 1) {
    	vc[i] = c ;
    	c = c + j;
    	if (c > 'z') {
    	  c = ' ';
    	}
    	else {
    	  if (c < 'a') {
    		c = 'a' + k;
    		k = k + 1;
    	  }
    	}
        if (k > 10) {
          k = 2;
        }
      }
    }
    void affichechars (int nbc, char vc [1000]) {
      int i;
      printf(" Les caracteres sont\n");
      for (i = 0; i < nbc; i = i + 1) {
    	printf ("%c",vc[i]);
      }
      printf("\n");
    }
    

We‘ll need typedef to help us understand.
Nous rajoutons ici la commande "typedef" qui permet de définir un nouveau type données à partir des types déjà connus.
typedef float tablef [100];
Et, au lieu d‘écrire partout float t [100] on écrira
tablef t.

 

    II.D.3) To dimensions tables
    Tableaux à deux dimensions
Un tableau à deux dimensions est simplement un vecteur de vecteurs.

exemple :
Example
tablef tab [100];
Est donc un vecteur de tablef, donc un vecteur de vecteurs de float.
typedef tablef table [100];
et table est un type de vecteur de vecteurs de float.
void voirt (table t, int taillex, int tailley) {
   int i, j;
   for (i = 0; i < taillex; i = i + 1) {
      for (j = 0; j < tailley; j = j + 1)
         printf("%5.2f ", t[x][y]);
      printf("\n");
   }
}

  • Tableaux à trois, quatre dimensions, ou plus
    Il suffit d‘étendre les connaissances pour imaginer la suite.
    /* exo sur les tableaux a trois dimensions */
    typedef float table3 [50] [50] [50];
    
    void remplirt (table3 t, int sx, int sy, int sz) {
      int x, y, sxy, z;
      float v, eps, add, pas;
    
      pas = 0.5;
      v = pas;
      add = 5.0;
      sxy = sx * sx + sy * sy;
      eps = 1.0 / (float) (sxy);
      for (x = 0; x < sx; x += 1) {
    	for (y =  0; y < x; y += 1) {
    	    for (z =  0; z < sz; z += 1) {
    	        t[x][y][z] = (float) (x * x - y * y + z + add) * eps;
            }
        }
        for (y =  x; y < sy; y += 1) {
            for (z =  0; z < sz; z += 1) {
               t[x][y][z] = (float) ( y * y - x * x + z + add) * eps;
            }
        }
        add += v;
        if (add > 10.0)
          v = - pas;
        if (add < 0.1)
          v = pas;
      }  
    }
    

  •  

        II.D.4) Structures
    A structure is a set of variables of possibly different types.
    Nous définissons des structures comme étant des assemblages d‘objets différents, contrairement au tableau qui est un assemblage d‘objets du même type.

    1. Definition
      Définition et exemple simple

      struct duo {
         int quot;
         int rest;
      } ;
      typedef struct duo duo;
      
      Just use it.
      Nous avons donc maintenant défini une structure composée de deux entiers, utile pour renvoyer le reste et le quotient d‘une division.
      duo division (int a, int b) {
        duo d;
        d.quot = 0;
        d.rest = 0;
        if (b == 0)
           return d;
        while (a >= b) {
           a = a - b;
           d.quot = d.quot + 1;
        }
        d.rest = a;
        return d;
      }
      
      int main () {
        duo res;
        int a, b;
        res = division(a,b);
        printf(" when dividing %d by %d, one gets a result", a, b);
        printf(" of %d with a reminder of %d\n", res.quot, res.rest);
      }
      

    2. Definition 2
      Définition 2

      All the type definitions are to be placed at the start of the file, in the "head" of the file.
      On place toujours la définition en tête de fichier

      Example:

      Nous mettons en place une structure de vecteur de nombres entiers.
      struct vecint {
        int nbele;
        int vec[100];
      };
      typedef struct vecint vecint_t;
      
      Il faut évidemment modifier la fonction qui remplit ce vecteur :
      vecint_t remplirv (int nb) {
          int crt, pre, new, i;
          vecint_t w;
          crt = 13;
          pre = 21;
          w.vec[0]=pre;
          w.vec[1]=crt;
          for (i=2; i <= nb; i = 1 + i) {
             new = (crt + pre) % 23; // reste de la division
             w.vec[i] = new;
             pre = crt;
             crt = new;
          }
          w.nbele = nb;
          return w;
      }
      
      		   

      Refaire quelques exercices de vecteurs d‘entiers avec cette structure.

      New example altitudes array:

      exemple tableau d‘altitudes:

      Vous trouverez ci-dessous une déclaration permettant de travailler sur des tableaux d‘altitudes, avec non seulement les valeurs, mais aussi les largeurs et hauteurs de la table.

      We‘ll work on altitude tables. Each cell contains the altitude at its coordinates.
      Nous allons travailler avec des tableaux d‘altitude. Sur une grande carte, carrée, nous donnons l‘altitude de chacune des cases, c‘est-à-dire l‘altitude moyenne pour toute la surface qu‘elle représente sur le terrain.
      Pour générer le tableau, il faut utiliser cette fonction en donnant comme paramètres, le tableau, le nombre de colonnes et le nombre de lignes :

      /* exo sur les altitudes JJ’2023 */
      typedef struct table_alt {
        int larg;
        int haut;
        float t[100][100];
      } table_alt_t;
      
         /* desormais table_alt_t est un type qui contient
         - deux valeurs de taille et
         - un vecteur float [100][100]*/
       
      Now the word "t_table_alt" is defined as a type of objects composed of two integers and a table of float numbers.
      Maintenant t_table_alt est un mot reservé dont la signification est : "objet composé de deux entiers et un tableau de flottants". On peut afficher un tel vecteur :
      void affiche (table_alt_t t) {
        int x, y, sx, sy;
        sx = t.larg;
        sy = t.haut;
        printf("Tailles max %d et %d\n", t.larg, t.haut);
        for (x = 0; x < sx; x = x + 1) {
          for (y = 0; y < sy; y = y + 1)
            printf("%5.2f\t", t.t[x][y]);
          printf("\n");
        }
      }
      
      table_alt_t remplirt (int sx, int sy) {
        int x, y, sxy;
        float v, eps, add, pas;
        table_alt_t tt;
      
        tt.larg = sx;
        tt.haut = sy;
        pas = 0.5;
        v = pas;
        add = 5.0;
        sxy = sx * sx + sy * sy;
        eps = 100.0 / (float) (sxy);
        for (x = 0; x < sx; x += 1) {
              for (y =  0; y < x; y += 1) {
                tt.t[x][y] = (float) (x * x - y * y + add) * eps;
              }
              for (y =  x; y < sy; y += 1) {
                tt.t[x][y] = (float) ( y * y - x * x + add) * eps;
              }
              /*
              for (y = 0; y < sy; y = y + 1)
                printf("%f \t", (*tt).t[x][y]);
              printf("\n");
              */
              add += v;
              if (add > 10.0)
                v = - pas;
              if (add < 0.1)
                v = pas;
        }
        return tt; /* ici on renvoie la structure */
      }
      

      Nous devons donc maintenant créer une fonction main pour s‘en servir.
      Note : le dénivelé entre deux points et la différence d‘altitude entre ces deux points.
      Un dénivelé positif est un dénivelé dont la valeur est positive (montée).
      Un dénivelé négatif est un dénivelé dont la valeur est négative (descente).
      Il vous reste à  :

      1. Trouver le point culminant (la valeur la plus grande) d‘une certaine ligne horizontale.
      2. Trouver le point culminant d‘une certaine colonne.
      3. Trouver le point culminant de toute la surface.
      4. Trouver le second point culminant de toute la surface.
      5. Calculer le dénivelé entre deux points donnés.
      6. Calculer la somme des dénivelés entre deux points d‘une ligne. Il faut donc que le numéro de la ligne soit fourni en argument.
      7. Calculer la somme des dénivelés entre deux points d‘une colonne. Il faut donc que le numéro de la colonne soit fourni en argument.
      8. Calculer la somme des dénivelés positifs entre deux points le long d‘une ligne.
      9. Calculer la somme des dénivelés négatifs entre deux points le long d‘une colonne.

    3. Square root
      Détour par la racine
      How to find the square root of a positive number x? It‘s the number, say y, that respects y * y == x.
      La racine carrée, y, d‘un nombre à virgule, x, est difficile à trouver. C‘est le nombre qui, multiplié par lui-même, donne x.

      x == y * y

      If x≥0 then 0≤ y <x+ 1.
      Commençons par cette constatation : si ce nombre, x, est positif ou nul alors la racine est comprise entre 0 et x+1, toujours.
      Let‘s call inf and sup these values (0 and x+1). Let‘s call med the average of them. it is easy to find if y is greater than med or not. If y>med then y belongs to ]med,sup], if not, y belongs to [inf, med]. One just has to set one of the two values inf or sup and carry on, and on, and on...
      When does it stop? When the value is close enough to the square root. Close enough is when the difference is smaller than a given value.

      Mais entre ces deux valeurs, inf et sup, il y en a beaucoup. Coupons par le milieu, mil. Comment savoir si la racine est plus grande ou plus petite que mil ? Et si elle est plus petite, ne pouvons-nous pas réduire l‘intervalle de recherche ? De même si elle est plus grande.
      Vous pouvez faire tourner longtemps cet algorithme, mais attention, vous n‘avez pas besoin d‘une infinité de chiffres, il faut donc vous arrêter quand la précision requise est acquise !

      Write this function square root.
      Faites une fonction qui calcule ainsi la racine carrée d‘un nombre positif à virgule.

       

    4. Complex numbers.

      As seen in class a structure for complex numbers can be:
      struct complex {
        float real;
        float imag;
      };
      typedef struct complex complex;
      
      
      A function to add two complex numbers is given by:
      struct complex mulc (struct complex a, struct complex b) {
        struct complex res;
        res.real = a.real + b.real;
        res.imag = b.imag + a.imag;
        return res;
      }
      
      The module of a complex number is square root of the sum of the square of the real and imag values.
      Faites une fonction qui calcule le module d‘un nombre complexe (la racine de la somme du carré des deux composants).
      Give a function that computes the module of a complexe number.

      Donnez une fonction qui permet de comparer en grandeur deux nombres complexes (on compare en fait leur module).

      If we add this definition to bring a vector of complex numbers:

      struct vecc {
        int nbe;
        complex tab [100];
      };
      typedef struct vecc vecc_t ;
      
      this is a function to create such a vector:
      Voici une nouvelle fonction pour remplir un tel vecteur :
      /* pour travailler les structures */
      
      vecc_t remplirc (int nbc) {
        int i;
        vecc_t t;
        float x, y;
        t.nbe = nbc;
        x = -4.0;
        y = nbc / 10.0 + 1.;
        for (i = 0; i < nbc; i++) {
      	t.tab[i].real = x;
      	t.tab[i].imag = y;
      	x = x + 0.35;
      	if (x > -3.7) {
      	  x -= 1.67;
      	}
      	y = y - 0.29;
      	if (y < 2.0) {
      	  y += 0.6;
      	}
        }
        return t;
      }
      void affic (vecc_t t) {
        int i;
        printf("Voici les %d nombres complexes\n", t.nbe);
        for (i= 0; i < t.nbe; i++) {
      	printf("(%6.3f,%6.3f) ", t.tab[i].real, t.tab[i].imag);
        }
        printf("\n");
      }
      int main () {
        vecc_t ta;
        int n;
      
        n = 10;
        ta = remplirc(n);
        affic (ta);
        ta.tab[2] = addc(ta.tab[0],ta.tab[1]);
        ta.tab[3] = multc(ta.tab[0],ta.tab[1]);
        affic (ta);
      }
      
      

      it seems easy to build the following functions: (Faites les fonctions suivantes)
      • La différence entre deux complexes.
      • Soit un x, la somme des complexes du vecteur dont le module est supérieur à x.
      • Le second plus grand nombre complexe (utilisation du module, de même que pour toute la suite),
      • le troisième plus petit,
      • le quatrième plus grand,
      • ranger tout ce tableau dans l‘ordre des modulos décroissants en utilisant l‘algorithme tri par insertion,
      • ranger tout ce tableau dans l‘ordre des modulos décroissants en utilisant l‘algorithme quicksort.

       

          II.D.5) Unions
      It’s not a structure, but looks like one.
      Nous devons traiter cette structure très spéciale.
      /* pour s amuser avec des unions */
      
      typedef unsigned short ushort;
      typedef unsigned long ulong;
      
      union etrange {
        ushort sh;
        ulong lg;
        char c;
      } ;
      typedef union etrange strange_t;
      
      void voir (strange_t s) {
        printf("short %d\t long %d\t char %d\t car %c \n", s.sh, s.lg, (int) s.c, s.c);
      }
      
      int main () {
        strange_t v;
      
        v.lg = 1024;
        voir (v);
        v.lg = 1024 * 1024;
        voir (v);
        for (v.lg = 1; v.lg < 128; v.lg++) 
      	voir (v);
      }
      /*
      short 1024	 long 1024	 char 0	 car  
      short 0	 long 1048576	 char 0	 car  
      short 1	 long 1	 char 1	 car  
      short 2	 long 2	 char 2	 car  
      short 3	 long 3	 char 3	 car  
      short 4	 long 4	 char 4	 car  
      short 5	 long 5	 char 5	 car  
      short 6	 long 6	 char 6	 car  
      short 7	 long 7	 char 7	 car  
      short 8	 long 8	 char 8	 car 
      short 9	 long 9	 char 9	 car 	 
      short 10	 long 10	 char 10	 car 
      short 127	 long 127	 char 127	 car  
      La suite, vous la verrez en faisant tourner le programme !
      */
      

     

     

     

     

     

  • Makefile
    Compilation séparée

    Nous allons maintenant créer plusieurs fichiers et les compiler séparément.
    Le premier fichier contient les prototypes des fonctions. Il s‘agit du fichier "fac.h":
    /* les prototypes des fonctions */
    
    int fac (int);
    int fac_acc (int, int);
    void affiche (int, int);
    

    Ensuite nous avons un fichier qui s‘occupe des entrées sorties, le fichier "io.c":
    #include "fac.h"
    
    void affiche (int a, int b) {
      printf("Vous avez donne \t%d\n",a);
      printf("Sa factorielle est \t%d\n",b);
    }

    Le fichier suivant contient la fonction du calcul de la factorielle, c‘est le fichier "fac.c":
    #include "fac.h"
    
    /* le calcul de la fonction factorielle */
    int fac (int n) {
       return fac_acc (n, 1);
    }
    int fac_acc (int n, int acc) {
      if (n < 2) {
         return acc;
      }
      else {
         return fac_acc (n-1, n*acc);
      }
    }

    Enfin, le fichier "main.c" contient le reste du code (ici la fonction main):
    #include "fac.h"
    
    main () {
      int n, f;
    
      n = 5;
      f = fact(n);
      affiche(n,f);
      n = 6;
      f = fact(n);
      affiche(n,f);
    }

    Il reste à les compiler séparément. Ceci se généralise grâce au fichier "Makefile":

    # Compilation generique par Bourdin
    
    CC=gcc
    
    fac:    io.o main.o fac.o fac.h
            $(CC) io.o main.o fac.o -o fac
    
    main.o:     main.c fac.h
    
    io.o:     io.c fac.h
    
    fac.o:     fac.c fac.h
    
    clean:
        @rm -f *.o
        @rm -f core
        @rm -f *~
    

    Attention, il faut remettre des "tabulations" à la main, sous emacs.

    Dans ce fichier on trouve trois sortes de lignes :


    Prenons la ligne 5:
    fac est nommé "cible".
    io.o main.o fac.o fac.h sont les dépendances.

    Sous shell, il ne reste plus qu‘à demander la compilation

    alpha5: make fac
    predecessor cycle (io.o)
            gcc -O -c io.c
    predecessor cycle (main.o)
            gcc -O -c main.c
    predecessor cycle (fac.o)
            gcc -O -c fac.c
            gcc io.o main.o fac.o -o fac
    ld: ERROR 33: Unresolved text symbol "fact" -- 1st referenced by main.o.
            Use linker option -v to see when and which objects, archives and dsos are loaded.  
    ld: INFO 152: Output file removed because of error.
    *** Error code 1 (bu21)
    

    Après correction (la fonction est nommée "fac" et pas "fact"!):
    alpha5: make fac
    predecessor cycle (io.o)
    predecessor cycle (main.o)
            gcc -O -c main.c
    predecessor cycle (fac.o)
            gcc io.o main.o fac.o -o fac
    alpha5: fac
    Vous avez donne         5
    Sa factorielle est      120
    Vous avez donne         6
    Sa factorielle est      720
    alpha5:

    On peut améliorer ce fichier de make, en utilisant des variables et des règles :
    # Meilleure compilation par Bourdin
    #
    # Attention, les tabulations doivent être refaites vous-mêmes, à la
    # main
    #
    
    OBJ=io.o main.o fac.o
    CC=gcc
    
    fac:    $(OBJ) fac.h
            $(CC) $(OBJ) -o fac
    
    %.o :   %.c
            $(CC)  -c $<
    
    clean:
        @rm -f *.o
        @rm -f core
        @rm -f *~
    

    Vous remarquerez que les fichiers qui finissent par ".o" sont obtenus par compilation avec l‘option "-c" c‘est l‘objet des lignes 14 et 15.

    Quelques variables par défaut


    Voici les fichiers pour mettre en place l‘algorithme de Newton, à télécharger.

    Vous pouvez regarder la page de mon collègue Bel Hadj pour comprendre mieux : sur les makefile .

  • À faire

    Dernière mise à jour le 12/2/2024 14h