Langage C : bases
Éléments du language
Caractères permis
- lettres de l’alphabet
- chiffres
- caractères spéciaux
- séparateurs de mots (permis mais ignorés par le compilateur)
Commentaires
Balise ouvrante : /*
#include <stdio.h>
/* début
du
programme */
int main() {
printf("Hello world\n");
exit();
}Balise par ligne : //
#include <stdio.h>
// début
// du
// programme
int main(){
printf("Hello world\n");
exit(0);
}Les mots réservés
| auto | double | int | struct |
|---|---|---|---|
| break | else | long | switch |
| case | enum | register | typedef |
| char | extern | return | union |
| const | float | short | unsigned |
| continue | for | signed | void |
| default | goto | sizeof | volatile |
| do | if | static | while |
Les types de base
Les types entiers
- sizeof(char)
<=sizeof(short)<=sizeof(int)<=sizeof(long) Où l’opérateur sizeof retourne la taille en bytes de son paramètre: type ou variable.
Les types réels
Le langage C (ANSI C) connaît 3 types réels : float, double et long double.
Le pseudo-type booléen
Pour des raisons de lisibilité du code, nous utiliserons dans ce cours le fichier d’en-tête stdbool.h de la bibliothèque standard C. Introduit avec la norme C99, ce fichier définit différentes macros, dont un type booléen bool et deux valeurs, true qui équivaut à 1 et false qui équivaut à 0.
Opérateurs
Les conversions de types
Conversions explicites par cast
Le cast (ou transtypage explicite) d’une expression permet de changer le type de la valeur renvoyée par l’évaluation de cette expression.
int a = 10;
float b = (float)a; // Conversion explicite d'un int en floatConversions implicites
Par ailleurs, C convertit automatiquement certaines expressions dans un type préférentiel, lors de leur évaluation
Les conversions unaires vont s’appliquer à un seul opérande, en respectant les règles énoncées dans le tableau suivant :
Les conversions binaires vont s’appliquer sur un des opérandes, en respectant la hiérarchie des types suivantes :
int < long < float < double < long doubleLes conversions d’affectation permettent à l’opérande de droite d’être converti pour rester compatible avec le type de l’opérande de gauche. En fonction de la priorité des opérateurs, nous rencontrons les conversions suivantes :
Déclaration et définition d’une variable
C distingue déclaration et définition de variables et de fonctions. Une déclaration indique simplement au compilateur l’existence d’un élément dont le nom et le type ont été spécifiés. Il n’y a pas de réservation de mémoire et l’élément ne peut pas encore être utilisé. Par contre lors d’une définition de variable ou de fonction, il y a physiquement réservation d’espace mémoire (pour y stocker une valeur ou pour donner le code de la fonction). Nous reviendrons plus tard sur cette distinction.
Une variable se déclare en spécifiant son type et l’identificateur qui la représente dans le programme, tandis que lorsqu’on définit une variable, il est possible de lui donner une valeur initiale. Par exemple :
int a; /* déclaration ou définition de la variable a de type int */Les déclarations et définitions multiples (plusieurs déclarations et définitions dans la même expression) sont permises.
int a, b, c = 5, d; /* définition des variables de type int a, b, c, d où seule c est initialisée */Rem : La valeur d’initialisation peut être le résultat d’une expression mais elle doit être connue lors de la compilation.
int taille = 3 * 4;Les constantes
En ANSI C, il existe deux techniques pour définir une constante : soit en utilisant une macro (via la directive de préprocesseur #define)
#define MAX 10Qui sera convertie en sa valeur lors de la pré-compilation,
soit en définissant une variable qualifiée de constante (via le mot réservé const):
const int MAX = 10;Notez que, par convention, l’identificateur d’une constante sera toujours composé de lettres majuscules.
Les instructions simples
-
Le C accepte l’usage de l’instruction nulle (ou instruction vide), marquée par le caractère ’;’, le terminateur d’instructions.
; /* instruction nulle */ -
Il permet également l’utilisation de l’instruction-expression, qui évalue l’expression pour ses effets de bord.
20 + 2*b; /* instruction sans effet de bord: évaluation puis oubli du résultat */Nous rencontrerons essentiellement trois cas d’utilisation :
-
Les affectations
a = b * c; -
Les pré ou post incrémentations et décrémentations
a++; a--; ++a; --a; -
Et les appels de fonction de type void ou dont la valeur de retour n’est pas exploitée
printf(...);
-
-
break : instruction qui permet de quitter une branche du switch ou de sortir d’une répétitive directement, sans réévaluer la condition.
-
continue : instruction utilisée uniquement dans les répétitives, elle permet de sauter la suite du corps de la répétitive et de passer directement à une nouvelle vérification de la condition; dans un for, elle permet l’exécution de l’adaptation.
Le bloc d’instructions
Lorsque plusieurs instructions doivent être traitées conjointement, elles sont regroupées en un bloc d’instructions encadrés par une paire d’accolades ' et '.
{
// instr1
// instr2
}Du point de vue de la syntaxe, un bloc se comporte comme une instruction unique et peut figurer en tout endroit où une instruction simple est permise. Il n’est pas suivi par le ’;’ car les accolades servent de délimiteurs.
Un bloc d’instructions peut débuter par la définition d’un certain nombres de variables, locales à ce bloc d’instructions (i.e. leur existence se termine à la fin du bloc).
{
// définition de variables
// liste d'instructions
}Si un identificateur redéfinit un variable déjà existante, la nouvelle variable occulte l’ancienne, définie dans un bloc englobant. Dans l’exemple suivant :
{
int i = 5;
{
int i = 7;
printf("i vaut %d\n", i++);
}
printf("i vaut %d\n", i);
}l’affichage donnera:
i vaut 7
i vaut 5Les répétitives
Il y a différents type de répétitives: le while, le for et le do … while. Toutes ces répétitives utilisent une condition de continuation, c-à -d que l’itération suivante est réalisée si la condition testée vaut VRAI. En d’autres mots, la boucle se termine lorsque la condition devient FAUX.
while
La condition est vérifiée avant d’entamer l’itération et donc si la condition est directement FAUX, l’instruction n’est pas exécutée.
while (cdt){
// instruction(s)
}for
Le for est une écriture condensée du while. Il est constitué de 3 parties : l’initialisation, la condition et l’adaptation.
{
for (int i = 0; i < 10; i++)
{
// variable i utilisable uniquement dans la boucle for
}
// variable i inexistante
}{
int i;
for (i = 0; i < 10; i++)
{
// variable i utilisable
}
// variable i utilisable
}
// variable i inexistanteLes alternatives
C connaît deux types de traitements conditionnels: les alternatives, qui permettent de réaliser ou pas un traitement en fonction d’une condition, et les switch, qui réalisent un traitement en fonction du contenu d’une variable dénombrable (entière).
if
if (cdt){
// instruction
}et les if…else
if (cdt) {
// instruction1
}
else {
// instruction 2
}switch
Le switch peut être considéré comme un branchement multiple en fonction d’une valeur entière. Dès que l’on est aiguillé vers une branche, le traitement se poursuit en séquence. Cela signifie que toutes les instructions qui suivent le case sont exécutées, jusqu’à la fin du bloc ou jusqu’à une instruction de rupture break qui permet de quitter la structure de contrôle.
switch (exp) {
case val1:
case val2:
... // instructions exécutées si exp = val1 ou val2
break;
case val3:
... // instructions executée si exp = val3
case val4:
... // instruction executée si exp = val4 ou val3
break;
default:
... // instruction executée si exp <> val1, val2, val3 et val 4
}switch (exp) {
case val1:
// instruction1
break;
case val2:
// instruction2
break;
case val3:
// instruction3
break;
default:
// instruction 4
}est l’equivalent d’un if imbriqué:
if (exp == val1){
// instruction1
} else if (exp == val2){
// instruction2
} else if (exp == val3){
// instruction3
} else {
// instruction 4
}