Programmation C
Types élémentaires - Variables - Constantes - Pointeurs - Opérateurs
Cours Exercices Correction des exercices

Types élémentaires Variables Constantes Pointeurs Opérateurs

Types élémentaires

  • Types entiers
    • short : stockage sur au moins 2 octets
      • Sur 2 octets valeurs possibles de -32768 à 32767 (de -215 à 215-1)
    • int : stockage sur au moins 2 octets suivant le compilateur, généralement 4 octets
      • Sur 2 octets, valeurs possibles de -32768 à 32767 (de -215 à 215-1)
      • Sur 4 octets : valeurs possibles de -2147483648 à 2147483647 (de -231 à 231-1)
    • long : stockage sur au moins 4 octets suivant le compilateur
      • Sur 4 octets valeurs possibles de -2147483648 à 2147483647 (de -231 à 231-1)
      • Sur 8 octets de -9223372036854775808 à 9223372036854775807 (de -263 à 263-1)
    • long long : stockage sur au moins 8 octets suivant le compilateur
      • Sur 8 octets de -9223372036854775808 à 9223372036854775807 (de -263 à 263-1)
  • Types entiers non signés (valeurs positives seules possibles)
    • unsigned short : stockage sur au moins 2 octets
      • Sur 2 octets valeurs possibles de 0 à 65535 (de 0 à 216-1)
    • unsigned int : stockage sur au moins 2 octets suivant le compilateur, généralement 4 octets
      • Sur 2 octets, valeurs possibles de 0 à 65535 (de 0 à 216-1)
      • Sur 4 octets : valeurs possibles de 0 à 4294967295 (de 0 à 232-1)
    • unsigned long : stockage sur au moins 4 octets suivant le compilateur
      • Sur 4 octets valeurs possibles de 0 à 4294967295 (de 0 à 232-1)
      • Sur 8 octets valeurs possibles de 0 à 18446744073709551615 (de 0 à 264-1)
    • unsigned long long : stockage sur au moins 8 octets suivant le compilateur
      • Sur 8 octets valeurs possibles de 0 à 18446744073709551615 (de 0 à 264-1)
    • size_t : stockage sur 4 octets si compilation en 32 bits, sur 8 octets si compilation en 64 bits
      Utilisé pour représenter des "tailles" (nombre d'enregistrements d'un tableau, nombre d'octets...)
  • Types réels
    • float : stockage sur 4 octets
      • 7 chiffres de précision sur la mantisse, exposant de -38 à +38, valeurs positives ou négatives
    • double : stockage sur 8 octets
      • 16 chiffres de précision sur la mantisse, exposant de -308 à +308, valeurs positives ou négatives
    • long double : stockage sur au moins 8 octets (non nomalisé)
  • Type booléen
    • Pas de type booléen en C89
    • Assimilation de toute variable à un booléen
      • Vrai si différente de zéro
      • Faux si égale à zéro
    • Utilisation fréquente du type int pour les variables booléennes
    • Introduction du type bool et des constantes littérales true et false avec le C99 et son API stdbool
  • Type caractère
    • char : stockage sur au moins 1 octet, généralement 1 octet
      • Sur 1 octet valeurs décimales de -128 à 127 (de -27 à 27-1)
    • Stockage de la valeur ASCII du caractère
  • Type caractère non signé
    • unsigned char : stockage sur au moins 1 octet, généralement 1 octet
      • Sur 1 octet valeurs décimales de 0 à 255 (de 0 à 28-1)
    • Souvent utilisé pour coder les octets de mémoire
  • "Type" void
    • Type spécial utilisé pour indiquer "vide"
      • Non utilisable pour définir une variable car elle ne pourrait rien contenir
      • Possibilité de définir un pointeur qui ne pointe spécifiquement sur aucun type (voir plus loin)
      • Type retour pour les fonctions qui ne retournent rien (voir chapitre sur les fonctions)
      • Type de la liste de paramètres pour les fonctions qui ne prennent pas de paramètre (voir chapitre sur les fonctions)
      • ...

Variable

  • Support du stockage de l'information quand celle-ci est susceptible de varier au cours de l'exécution du programme
  • Caractérisée par le nom qui la désigne (respect des conventions du langage C pour le choix des noms de variable), le type de la valeur qu'elle contient et la valeur qu'elle contient
  • Typage immuable et obligatoire
  • Syntaxe de définition
    nonType nomVariable;
  • Exemples
    • int i;
    • double d;
    • long l = 1000;
    • char c = 'A';

Constante

  • Support du stockage de l'information quand celle-ci ne varie pas au cours de l'exécution du programme
  • Caractérisée par le nom qui la désigne (respect des conventions du langage C pour le choix des noms de constante -> intégralement en majuscules), le type de la valeur qu'elle contient et la valeur qu'elle contient
  • Typage immuable et obligatoire
  • Syntaxe de définition
    const nonType NOM_CONSTANTE = valeurConstante;
  • Exemples
    • const double PI = 3.14159;
    • const short S = 23;
  • Attention : Pas vraiment définition d'une constante, mais définition d'une variable dont la modification est impossible via l'opérateur = (opérateur interdit) et dont la zone mémoire de stockage est de plus interdite en écriture (pas de manipulation de mémoire possible)
  • Autres possibilités pour déclarer de "vraies" constantes
    • #define
    • enum
  • Exemple
  • #include <stdbool.h>

    void main(void) {
      // Valeur définie en utilisant une constante int donnée en notation binaire
      const unsigned char CUC = 0b0100110;
      bool b = true;
      char c;
      short s;
      int i;
      long l;
      long long ll;
      float f;
      double d;
      unsigned char uc;
      unsigned int ui;

      // Valeur affectée en utilisant une constante littérale caractère
      c = 'a';
      // Valeur affectée en utilisant la constante littérale false
      b = false;
      // Valeur affectée en utilisant une constante littérale int
      s = -10;
      // Valeur affectée en utilisant une constante littérale int
      i = 1;
      // Valeur affectée en utilisant une constante littérale long
      l = -1000000000L;
      // Valeur affectée en utilisant une constante littérale entière sur 64 bits
      ll = 4000000000000000000LL;
      // Valeur affectée en utilisant une constante littérale float
      f = -0.98e-10F;
      // Valeur affectée en utilisant une constante littérale double
      d = 0.56e284;
      // Valeur affectée en utilisant une constante littérale int
      uc = 150;
      // Valeur affectée en utilisant une constante int donnée en notation hexadécimale
      ui = 0xE5A845DC;
    }

    TypesElementaires.c - TypesElementaires.exe
    • Définitions d'une constante et de dix variables suivies d'une affectation avec une constante littérale sur chacune des 10 variables

Transtypage

  • Possibilité de conversion d'un type vers un autre type
  • Syntaxe
    (typeVersLequelConvertir) valeurAConvertir
    -> Conversion vers le type indiqué entre parenthèses de la première valeur trouvée après le type indiqué entre parenthèses
  • Exemples
    • (int) 3.82 : conversion de la valeur double 3.82 en un entier et obtention de la valeur 3
    • (int) -3.98 : conversion de la valeur double -3.98 en un entier et obtention de la valeur -3
    • (int) 3.72*10 : conversion de la valeur double 3.72 en un entier, multiplication par l'entier 10 et obtention de la valeur 30
    • (int) (3.72*10) : conversion de la valeur double obtenue en multipliant 3.72 par l'entier 10 en un entier et obtention de la valeur 37
    • (char) 110 : conversion de la valeur entière 110 vers le caractère de code ASCII 110 ('n')
  • Pas de transtypage explicite obligatoire pour la conversion vers des types plus précis
    Exemples : float vers double, int vers long, long vers double
  • Transtypage explicite possible d'à peu près n'importe quoi vers à peu près n'importe quoi
    Probablement trop permissif
  • Exemple
  • #include <stdio.h>

    void main(void) {
      printf("%d\n", (int)3.82);
      printf("%d\n", (int)-3.98);
      printf("%d\n", (int)3.72 * 10);
      printf("%d\n", (int)(3.72 * 10));
      printf("%c\n", (char)110);
    }

    Transtypage.c - Transtypage.exe
    • Implantation des cinq exemples de transtypage proposés ci-dessus
    3
    -3
    30
    37
    n

Pointeurs

  • Possibilité d'utiliser explicitement des variables de type adresse mémoire
  • Pas de type pointeur générique mais plutôt existence d'un type pointeur pour chacun des types élémentaires : pointeur sur int, pointeur sur unsigned char, pointeur sur void...
  • Quel que soit le type pointeur d'une variable, stockage de l'adresse sur 4 octets en 32 bits, sur 8 octets en 64 bits
  • Pointeurs généralement notés en hexadécimal.
    Exemples : 0xFEA456C3 en 32 bits, 0x78FF4376CD6290AB en 64 bits
  • Transtypage possible de n'importe quel type pointeur vers n'importe quel type pointeur
  • Syntaxe de définition d'une variable nommée nomVariable de type pointeur sur le type nomType
  • nomType* nomVariable;
    ou
    nomType * nomVariable;
    ou
    nomType *nomVariable;
  • Existence de l'opérateur & permettant d'obtenir l'adresse mémoire de n'importe quelle variable (ou constante) sous la forme d'un pointeur sur le type de la variable
    • Variable nomVariable du type nomType -> &nomVariable du type pointeur sur nomType
  • Existence de l'opérateur * permettant de désigner la valeur de la variable pointée par n'importe quel type de variable pointeur : un int pour pointeur de type int *, un unsigned char pour pointeur de type unsigned char *...
    • Variable nomVariable du type pointeur sur nomType -> *nomVariable du type nomType
  • ATTENTION : Sauf à vouloir planter l'exécution, impossibilité de stocker de l'information dans la zone mémoire pointée par une variable de type pointeur si cette zone mémoire
    • ne correspond pas à une "vraie" variable
    • n'a pas été correctement allouée dynamiquement à cette fin
  • Existence de la constante NULL généralement égale à l'adresse mémoire 0x00000000 en 32 bits, 0x0000000000000000 en 64 bits
    • Fréquemment utilisée pour affectation aux variables de type pointeur lorsqu'elles ne contiennent pas d'adresse valide (pas l'adresse mémoire d'une zone mémoire valide)
  • Pointeurs pour faire quoi ?
    • Gérer finement la mémoire
    • Gérer les tableaux et en particulier l'allocation dynamique de mémoire pour les tableaux
    • Passer des paramètres à des fonctions
    • ...
  • Exemples
  • #include <stdio.h>

    void main(void) {
      int val = 10;
      int* pVal = NULL;
      printf("%p\n%p\n\n", &val, pVal);
      pVal = &val;
      printf("%p\n%p\n\n", &val, pVal);
    }

    Pointeurs1.c - Pointeurs1.exe
    • Définitions pour une variable de type int initialisée à 10 et une variable de type pointeur sur int initialisée à NULL
    • Affichage de l'adresse de la variable int et de la valeur de la variable pointeur
      -> une adresse différente de NULL et l'adresse 0x0000000000000000
    • Affectation de la variable pointeur avec l'adresse de la variable int
    • Affichage de l'adresse de la variable int et de la valeur de la variable pointeur
      -> deux adresses identiques et différentes de NULL
    000000394610F9C0
    0000000000000000

    000000394610F9C0
    000000394610F9C0

    #include <stdio.h>

    void main(void) {
      int val = 10;
      int* pVal = &val;
      printf("%d %d\n", val, *pVal);
      *pVal = 100;
      printf("%d %d\n", val, *pVal);
      val = 200;
      printf("%d %d\n", val, *pVal);
    }

    Pointeurs2.c - Pointeurs2.exe
    • Définitions pour une variable de type int initialisée à 10 et une variable de type pointeur sur int initialisée avec l'adresse de la variable de type int
    • Affichage de la valeur de la variable int et de la valeur de la variable pointée par la variable pointeur
      -> 10 et 10
    • Affectation de la valeur de la variable pointée par la variable pointeur avec la valeur 100
    • Affichage de la valeur de la variable int et de la valeur de la variable pointée par la variable pointeur
      -> 100 et 100
    • Affectation de la variable int avec la valeur 200
    • Affichage de la valeur de la variable int et de la valeur de la variable pointée par la variable pointeur
      -> 200 et 200
    10 10
    100 100
    200 200

Opérateurs

  • Existence d'opérateurs associés aux différents types
    • = : opérateur d'affectation, résultat du type de la variable affectée et égal à la valeur affectée
    • Types entiers
      • Résultat booléen
        • == : test d'égalité
        • != : test de différence
        • > : test de supériorité
        • < : test d'infériorité
        • >= : test de supériorité ou égalité
        • <= : test d'infériorité ou égalité
      • Résultat entier
        • + : addition entière
        • - : soustraction entière
        • * : multiplication entière
        • / : division entière
        • % : reste de la division entière (modulo)
        • << : décalage de bit(s) vers la gauche (souvent utilisé pour multiplier par deux, quatre, huit... les entiers positifs)
        • >> : décalage de bit(s) vers la droite (souvent utilisé pour diviser par deux, quatre, huit... les entiers positifs)
        • & : et binaire (et bit à bit)
        • | : ou binaire (ou bit à bit)
        • ^ : ou exclusif (ou exclusif bit à bit)
        • ++ : incrément de 1
          • Si ++ placé avant la variable, incrément de 1 et obtention de la valeur incrémentée
          • Si ++ placé après la variable, obtention de la valeur initiale puis incrément de 1
        • -- : décrément de 1
          • Si -- placé avant la variable, décrément de 1 et obtention de la valeur décrémentée
          • Si -- placé après la variable, obtention de la valeur initiale puis décrément de 1
        • ...
      • ...
    • Types réels
      • Résultat booléen
        • == : test d'égalité
        • != : test de différence
        • > : test de supériorité
        • < : test d'infériorité
        • >= : test de supériorité ou égalité
        • <= : test d'infériorité ou égalité
      • Résultat réel
        • + : addition réelle
        • - : soustraction réelle
        • * : multiplication réelle
        • / : division réelle
        • ...
      • ...
    • Type "booléen"
      • == : test d'égalité
      • != : test de différence
      • && : et logique
      • || : ou logique
      • ! : non
    • Types caractères
      • Assimilables aux types entier
    • Types pointeurs
      • Traités dans le chapitre "Tableaux"
  • Opérateur sizeof
    • Appliqué à une constante ou une variable : nombre d'octets occupés par la constante ou la variable
    • Appliqué à un type : nombre d'octets occupés par une constante ou une variable définie de ce type
    • Obtention d'une valeur de type size_t (type entier non signé dont la précision varie selon l'architecture cible de compilation, 4 ou 8 octets)
    • Syntaxe
      sizeof(...)
      -> taille en octets de l'item donné entre parenthèses
  • Opérateurs opérateur=
    • Avec tous les opérateurs portant sur deux items, possibilité d'implanter la syntaxe var = var opérateur item en utilisant la syntaxe var opérateur= item
    • Exemples
      • a += 3;
      • c %= 5;
      • b ^= z;
  • Existence de règles définissant la possibilité de marier des variables ou des constantes de types différents au sein d'une même opération, et, si ce mariage est possible, ce qu'est le type du résultat et comment il est calculé
  • Existence de priorités entre opérateurs
  • A priorités égales, évaluation de gauche à droite
    Conseil : mettre des parenthèses pour éviter les risques d'écriture érronée
  • Exemples
  • #include <stdio.h>
    #include <stdbool.h>

    void main(void) {
      int a1 = 10;
      int a2;
      int a3;
      a3 = (a2 = a1 - 1) - 1;
      printf("%d %d %d\n", a1, a2, a3);
      printf("%d %d %d\n", a1 + a2, a1 * a2, a1 / a2);
      printf("%d %d\n", a1 << 2, a2 >> 2);
      printf("%d %d\n", a1 == a2, a1 != a2);
      printf("\n");
      double d1 = 1.1;
      double d2 = 2.1;
      printf("%lf %lf\n", d1, d2);
      printf("%lf %lf %lf %lf\n", d1 + d2, d1 - d2, d1 * d2, d1 / d2);
      printf("%d %d\n", d1 == d2, d1 < d2);
      printf("\n");
      char c = 'a';
      c += 10;
      printf("%c\n", c);
      printf("\n");
      bool b1 = true;
      bool b2 = false;
      printf("%d %d\n", b1, b2);
      printf("%d %d %d %d\n", true && truetrue && falsefalse && truefalse && false);
      printf("%d %d %d %d\n", true || truetrue || falsefalse || truefalse || false);
      printf("%d %d\n", !b1, !b2);
    }

    Operateurs1.c - Operateurs1.exe
    • Affectation en tant qu'opérateur
    • Addition, multiplication et division entre int
    • Décalage de bits sur des int
    • Tests d'égalité et de différence entre int
    • Addition, soustraction, multiplication et division entre double
    • Tests d'égalité et d'infériorité entre double
    • Addition d'un char et d'un int et report du résultat dans un char, travail sur les codes ASCII
    • Affichage des quatre combinaisons par et de deux booléens
    • Affichage des quatre combinaisons par ou de deux booléens
    • Affichage des deux négations de booléens
    10 9 8
    19 90 1
    40 2
    0 1

    1.100000 2.100000
    3.200000 -1.000000 2.310000 0.523810
    0 1

    k

    1 0
    1 0 0 0
    1 1 1 0
    0 1

    #include <stdio.h>
    #include <stdbool.h>

    void main(void) {
      int a1 = 55;
      int a2 = 10;
      double d1 = 1.1;
      double d2 = 2.1;
      char c = 'a';
      printf("%d %lf %lf\n", a1 / a2, a1 / a2, (double)a1 / a2);
      printf("%d %lf\n", d1 / d2, d1 / d2);
      printf("%c %d %lf\n", c + 1, c + 1, c + 1);
    }

    Operateurs2.c - Operateurs2.exe
    • Affichage de deux divisions entre int et d'une division entre un double et un int, mauvais format de printf pour la deuxième valeur
    • Affichage de deux divisions entre double, mauvais format de printf pour la première valeur
    • Affichage de trois additions entre char et int, mauvais format de printf pour la troisième valeur
    5 0.000000 5.500000
    818089009 0.523810
    b 98 0.000000

    #include <stdio.h>

    void main(void) {
      int a1 = 10;
      int b1 = a1++;
      printf("%d %d\n", a1, b1);
      int a2 = 10;
      int b2 = ++a2;
      printf("%d %d\n", a2, b2);
    }

    OperateursPlusPlusEtMoinsMoins.c - OperateursPlusPlusEtMoinsMoins.exe
    • Définition d'une variable a1 de type int initialisée à 10
    • Définition d'une variable b1 initialisée avec a1++ c'est à dire avec a1 auquel sera ajouté 1 après l'affectation
    • Affichage de a1 et de b1 -> affichage de 11 et 10
    • Définition d'une variable a2 de type int initialisée à 10
    • Définition d'une variable b2 initialisée avec ++a2 c'est à dire avec a2 après ajout de 1
    • Affichage de a2 et de b2 -> affichage de 11 et 11
    11 10
    11 11

    #include <stdio.h>
    #include <stdbool.h>

    void main(void) {
      int i;
      long l;
      long long ll;
      float f;
      double d;
      char c;
      bool b;
      void* p;
      printf("Variable int       : %zu\n", sizeof(i));
      printf("Variable long      : %zu\n", sizeof(l));
      printf("Variable long long : %zu\n", sizeof(ll));
      printf("Variable float     : %zu\n", sizeof(f));
      printf("Variable double    : %zu\n", sizeof(d));
      printf("Variable char      : %zu\n", sizeof(c));
      printf("Variable bool      : %zu\n", sizeof(b));
      printf("Variable void*     : %zu\n", sizeof(p));
      printf("\n");
      printf("Type int           : %zu\n", sizeof(int));
      printf("Type long          : %zu\n", sizeof(long));
      printf("Type long long     : %zu\n", sizeof(long long));
      printf("Type float         : %zu\n", sizeof(float));
      printf("Type double        : %zu\n", sizeof(double));
      printf("Type char          : %zu\n", sizeof(char));
      printf("Type bool          : %zu\n", sizeof(bool));
      printf("Type void*         : %zu\n", sizeof(void *));
    }

    OperateurSizeof.c - OperateurSizeof.exe
    • Définition de variables de différents types et affichage du nombre d'octets qu'elles occupent individuellement
    • Affichage du nombre d'octets correspondant à différents types
    Variable int       : 4
    Variable long      : 4
    Variable long long : 8
    Variable float     : 4
    Variable double    : 8
    Variable char      : 1
    Variable bool      : 1
    Variable void*     : 8

    Type int           : 4
    Type long          : 4
    Type long long     : 8
    Type float         : 4
    Type double        : 8
    Type char          : 1
    Type bool          : 1
    Type void*         : 8