Jean-Jacques BOURDIN

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


Programmation Impérative
Imperative Programming

Spring 2025


Tous les exercices

Overview

Ch I) Let's try!

Ch II) Easy C

    II.A) Variables, Expressions, Types, Instructions

    II.A) Operators

    II.B) Control Flow

    II.C) Data Structures

    II.D) 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

    Votre premier partiel.

 

 

 

 


Ch III) Adresses C


    III.A) Principles / Principes, Rappels

A variable is a set of three things: a name, a type and a location.
It is in this location that one can find the value of the variable. The address is known by the operator &.

Une variable est un triplet < nom, type, emplacement>. C'est à cet emplacement que, selon le type, on trouve la valeur. On peut connaître l'emplacement, l'adresse, de la variable "a" en utilisant l'opérateur & :
void voirou1 () {
  int i, j;
  printf("i est en %u, j est en %u\n", (int)&i, (int)&j);
}

One may also set this adress into a new variable, a "pointer". The content of such a variable is available, and the content of the pointed variable can be found with the unary operator *.
On peut aussi mettre cette adresse dans une variable spéciale qui contient des adresses, un pointeur. On peut aussi savoir ce qu'il y a à une certaine adresse avec l'opérateur unaire *.
void voirou () {
  int *pi, *pj;
  int i, j;

  printf("i est en %d, j est en %u\n",(int) &i,(int) &j);
  pi = & i;
  pj = & j;
  i  = 7;
  j  = 9;
  printf("En %u il y a %d\n", (int) pi, * pi);
  printf("En %u il y a %d\n", (int) &j, j);  
}

On peut se servir des adresses pour modifier le contenu d'une variable extérieure.
void iv (int * pa, int * pb) {
   * pa = * pa + * pb;
   * pb = * pa - * pb;
   * pa = * pa - * pb;
}
int main () {
   int a, v;
   a = 5;
   v = 8;
   voirou1();
   voirou();
   printf("a = %d\t v = %d\n",a,v);
   iv (&a, &v);
   printf("a = %d\t v = %d\n",a,v);
}
/* dhcp13.ai.univ-paris8.fr: a.out
a = 5	 v = 8
a = 8	 v = 5
*/

Ici, les variables et leurs adresses :
      nom  adresse contenus
main   a   400     5    puis 13        puis 8
main   v   404     8            puis 5
iv     pa  408     400    
iv     pb  416     404
Amusant, non ?
/* une autre version */
#include <stdio.h>

void nrut (int * px, int * py) {
  * px = * px + * py;
  * py = * px - * py;
  * px = * px - * py;
}
void lookatit (int n) {
  int x, y;
  int * px, * py; /* adresses de int */

  x  = n; 
  y  = 3; 
  px  = & x; 
  py  = & y;
  printf("adresses de x %p et y %p\n",px, py);
  printf("Avant : valeurs de x %d et y %d\n",x, y);
  nrut(px,py);
  printf("Avant : valeurs de x %d et y %d\n",x, y);
}
int main () {
  lookatit(5);
}
/*
adresses de x 0x7ff7b32b7768 et y 0x7ff7b32b7764
Avant : valeurs de x 5 et y 3
Apres : valeurs de x 3 et y 5
*/
Voici un autre exemple, que vous reconnaîtrez aisément :
/* Fait par JJ B en 2010 */

typedef int * pint;

void fct (int nb, int rg, pint a, pint b) {
  if (nb > rg) {
    *a = *a + *b;
    *b = *a - *b;
    fct (nb, rg + 1, a, b);
  }
}
main () {
  int i, n, a, b;

  n = 10;
  for (i = 0; i <= n; i++) {
    a = 1;
    b = 1;
    fct (i, 0, &a, &b);
    printf("%d => %d\n", i, b);
  }
}

 

 

    III.B) Arrays and pointers / Vecteurs et Tableaux

  1. Retour
    What is an array? Nothing else than a pointer.
    Qu'est-ce qu'un tableau ? Un pointeur ! On peut parcourir un tableau, case à case, par un pointeur :
    /* Fait par JJ B */
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct vecteur {
      int nbe;
      float tab [100];
    } vecteur_t;
    
    typedef float * pfloat;
    
    float somv (vecteur_t v) {
      int i;
      float som;
      pfloat p;
      p = v.tab;
      som = 0;
      for (i = 0; i < v.nbe; i++) {
        som = som + *p;
        p ++;
      }
      return som;
    }
    
    On suppose que le vecteur a été défini par ailleurs. Voici une illustration du fonctionnement de cette fonction :
    vecteur_t remplir (int nb) {
    float x, eps;
      vecteur_t vec;
      int i;
    
      vec.nbe = 0;
      if (nb >= 100)
    	return vec;
      vec.nbe = nb;
      x = 1.5;
      eps = 0.173;
      for (i = 0; i < nb; i = i + 1) {
    	vec.tab [i] = x;
    	x = x + eps;
    	if (x > 2.0)
    	  eps = 0.01 - eps;
    	if (x < 0.5)
    	  eps = 0.015 - eps;
      }
    }
    void voirvec (vecteur_t v) {
      int i;
      if (v.nbe  >= 100)
    	return;
      for (i = 0; i < v.nbe; i = i + 1) {
    	printf("vec[%3d] == %f\n",i, v.tab [i]);
      }
    }
    
    void voirvec2 (vecteur_t v) {
      int i;
      float * pf;
      if (v.nbe  >= 100)
         return;
      pf = v.tab;	    
      for (i = 0; i < v.nbe; i = i + 1) {
    	printf("vec[%3d] == %f\n",i, *pf);
            pf++;
      }
    }
    

    Il vous reste à reprendre quelques exercices faits avec des vecteurs, mais cette fois, en utilisant les pointeurs.

    Exemple de convertisseur

    En-tête
    #include<stdio.h>
    #include<stdlib.h>
    #include<assert.h>
    #define MAXB 30
    #define MAXD 30
    
    typedef unsigned char uchar;
    typedef struct binaire {
      int nbent;
      int nbfrac; /* nombre de chiffres entiers et post virgule */
      //  uchar ent [MAXB];
      //  uchar frac [MAXB];
      uchar *ent;
      uchar *frac;
    } binaire_t;
    typedef struct decimal {
      int nbent;
      int nbfrac; /* nombre de chiffres entiers et post virgule */
      uchar *ent;
      uchar *frac;
    } decimal_t;
    
    Fonction main :
    int main () {
      binaire_t b;
      decimal_t d;
      float deci, bina;
    
    
      deci = 134.125;
      d = nb2dec(deci);
      printf("Pour %f le code est :\n", deci);
      aff_dec(d);
      bina = 110011.11001;
      b = nb2bin(bina);
      printf("Pour %f le code est :\n", bina);
      aff_bin(b);
    }
        
    Transformer un nombre pour le mettre dans la structure :
    
    decimal_t nb2dec (double xx) { /* prend un nombre et le met dans les cases*/
      decimal_t dd;
      int i, nbc, chiffre, nbchif, nbfrac, p10;
      float frac;
      int partieent;
    
      partieent = (int) xx;
      frac = xx - partieent;
      /* combien de chiffres */
      nbchif = 0;
      i = 1;
      while (i <= partieent) {
        i *= 10;
        nbchif++;
      }
      p10 = 10;
      dd.nbent = nbchif;
      dd.ent = malloc(nbchif * sizeof(uchar));
      assert(dd.ent);
      
      for (i=0; i < nbchif; i++) {
        dd.ent[i] = (uchar) (partieent % 10);
        //    printf("partiee %d val %d\n", partieent, dd.ent[i]);
        partieent /= 10;
    
      }
      dd.nbfrac = 10;
      nbfrac = 10; /* 10 chiffres max*/
      dd.frac = malloc(nbfrac * sizeof(uchar));
      assert(dd.ent);
      for (i = 0; i < nbfrac; i++) {
        frac *= 10;
        chiffre = (int) frac;
        frac -= chiffre;
        dd.frac[i] = (uchar) chiffre;
      }
      return dd;
    }
    

    La suite

    void aff_bin (binaire_t bb) {
      int i;
      uchar *ptr;
      
      printf(" voici votre binaire\n");
      ptr = bb.ent + bb.nbent - 1;
      for (i= 0; i < bb.nbent; i++) {
        printf("%2u ", (unsigned int) *ptr--);
      }
      printf(" . ");
      ptr = bb.frac;
      for (i = 0; i < bb.nbfrac; i++) {
        printf("%2u ", (unsigned int) *ptr++);
      }
      printf("\n");
    }
    void aff_dec (decimal_t bb) {
      int i;
      uchar *ptr;
    
      //  printf("nb chiffres %d . %d\n", bb.nbent, bb.nbfrac);
      ptr = bb.ent + bb.nbent - 1;
      for (i = 0; i < bb.nbent ; i++) {
        printf("%2u ", (unsigned int) *ptr--);
      }
      printf(" . ");
      ptr = bb.frac;
      for (i = 0; i < bb.nbfrac; i++) {
        printf("%2u ", (unsigned int) *ptr++);
      }
      printf("\n");
    }
    
    		  
    et maintenant un exemple de convertisseur ;
    
    decimal_t bin2dec(binaire_t bb) {
      int p2, i,j;
      double res, neg;
      
      printf("conversion du binaire au décimal\n");
      aff_bin(bb);
      p2 = 1;
      res = 0.0;
      //  bzero(tmp, (size_t) MAXD, (size_t) 1);
      for (i = 0; i < bb.nbent; i++) {
        res += p2 * bb.ent[i];
        p2 *= 2;
        //    printf("i %d res %f\n", i, res);
      }
      neg = 1.0/ 2.0;
      for (i = 0; i < bb.nbfrac; i++) {
        res += neg * bb.frac[i];
        neg /= 2.0;
      }
      printf("et en float %f\n", res);
      return nb2dec(res);
    }
    
    

Dernière mise à jour le 10/2/2025 18h00