C
Langage de programmation structuré, mais de bas niveau, permettant de manipuler dynamiquement les espaces mémoire avec des pointeurs, offrant des types primitifs, et très performant grâce à une implémentation de ses compilateurs près du matériel.
Historique
En 1969, dans les laboratoires Bell, Ken Thompson entreprend le développement d'un système d'exploitation qui deviendra le très célèbre UNIX.
Écrit en assembleur, le système d'exploitation devient difficile à maintenir et à faire évoluer. Thompson connaît le langage BCPL, de Martin Richards, utilisé pour écrire des outils système, mais celui-ci est trop lourd, alors il en tire une version réduite, le langage B. Ce dernier, sans types et raisonnant en mots machine, ne convient pas pour la réécriture du système UNIX. En 1971, Dennis Ritchie entreprend de faire évoluer le langage B pour créer le langage C.

AT&T, société mère des laboratoires Bell, oeuvre dans le domaine des systèmes téléphoniques et, à l'époque, un accord antitrust lui interdit de commercialiser autre chose. Ainsi, en 1975, le système d'exploitation UNIX complet, incluant son code source réécrit en langage C, est distribué dans les universités à un coût nominal.
C'est ainsi que le langage C devient l'un des plus utilisés dans le domaine des technologies de l'information.
Source
Le code source d'un programme en langage C est contenu dans des fichiers texte ayant, habituellement, .c comme extension.
Squelette
// Inclusions.
// Déclarations.
int main() {
// Code source de la fonction principale.
return 0; // Code de retour du programme.
}
Compilation
Le programme cl.exe est un compilateur pour les langages C et C++ sur le système d'exploitation Windows :
cl /c main.c
L'argument /c (compile) permet de générer le code assembleur, pour ensuite être traduit en langage machine.
Liaison
Le programme link.exe est un lieur pour le système d'exploitation Windows :
link main.obj
Commentaires
Tout ce qui suit les caractères // sur une ligne est ignoré lors de la compilation :
// Commentaire sur une ligne.
Tout ce qui est encadré des balises /* et */ est aussi ignoré lors de la compilation :
/* Commentaire
entre
balises. */
Blocs
Un bloc de code est initié par une accolade ouvrante et terminé par une accolade fermante :
{ // Début du bloc de code.
// Contenu du bloc de code.
} // Fin du bloc de code.
Types
Le langage C offre quelques types primitifs :
| Type | Langage C | Taille | Littéral |
|---|---|---|---|
| Entier | char | 1 octet | 127 ou '~' |
| short | 2 octets | 32767 | |
| int | 4 octets | 2147483647 | |
| long | 8 octets | 9223372036854775807 | |
| Réel | float | 4 octets | 3.141592f |
| double | 8 octets | 3.14159265358979 |
Il est possible de préciser, pour les types entiers, que les valeurs ne peuvent être que positives ou nulles, permettant de représenter de plus grandes valeurs :
| Langage C | Taille | Littéral |
|---|---|---|
| unsigned char | 1 octet | 255 |
| unsigned short | 2 octets | 65535 |
| unsigned int | 4 octets | 4294967295U |
| unsigned long | 8 octets | 18446744073709551615U |
Il est à noter que sur les plateformes Windows, ce sont les types long long et unsigned long long qui ont une taille de 8 octets.
Définitions de type
L'identificateur de certains types n'est parfois pas assez révélateur au niveau du type de donnée et de sa taille. Il est possible de créer des alias de ces types :
typedef char byte;
Certains types sont définis par la biblothèque standard du langage tel size_t qui représente la de n'importe quel objet selon l'architecture utilisée.
Variables
Une variable représente un espace, en mémoire centrale, permettant de stocker et de consulter une donnée selon un type.
Identificateur
Plutôt que d'utiliser les adresses de la mémoire centrale pour accéder aux données, il est possible de nommer les variables à l'aide d'un identificateur. Toutefois, certaines contraintes doivent être respectées lors de la composition des identificateurs :
- Doivent débuter par une lettre non accentuée.
- Ne doivent contenir que des lettres non accentuées, des chiffres et des caractères
_. - Doivent être différents des mots-clés du langage C.
Déclaration
La déclaration d'une variable commence par son type, suivi d'un identificateur, et se termine par le caractère ;. La variable peut aussi être initialisée par une valeur. Il est possible de déclarer plusieurs variables de même type en les séparant par le caractère , :
Tableau
Pour déclarer un tableau, il suffit d'ajouter, entre crochets après l'identificateur, le nombre d'éléments désirés :
short entiers[5];
Le nombre d'éléments doit être constant et les indices de tableaux débutent toujours à 0.
Un tableau ne peut être initialisé qu'au moment de sa déclaration :
short entiers[] = { 7, 42, 69, 404, 666 };
Le nombre d'éléments ne peut être omis que si une liste d'initialisation est fournie; il est alors déduit du nombre de valeurs. Si la taille est précisée et que la liste est incomplète, les éléments restants seront initialisés à 0.
Préprocesseur
Les directives du préprocesseur sont toutes précédées du caractère # et sont traitées avant la compilation.
Définitions
Agit comme un « rechercher-remplacer » :
#define TPS 0.05
#define TVQ 0.09975
Chaque occurrence de TPS sera remplacée par 0.05 et celles de TVQ par 0.09975 avant la compilation.
Inclusions
Agit comme un « copier-coller » :
#include <fichier.h>
Le code de fichier.h sera copié et collé à l'endroit du #include.
Comme exemple, pour utiliser des variables booléennes en langage C, il faut définir le type bool, et définir les constantes false et true. Ces définitions ont plutôt été placées dans un fichier d'en-tête stdbool.h, permettant de seulement l'inclure dans des projets.
Opérateurs
Le langage C offre les opérateurs suivants :
| Priorité | Opérateur | Description | Associativité |
|---|---|---|---|
| 1 | () | Appel de fonction | |
| [] | Indexation | ||
| . | Membre de structure | ||
| -> | Membre via pointeur | ||
| -- | Décrémentation postfixée | ||
| ++ | Incrémentation postfixée | ||
| 2 | (type) | Transtypage | |
| sizeof | Taille en octets | ||
| * | Indirection | ||
| & | Adresse de | ||
| ~ | Négation bit à bit | ||
| ! | Négation logique | ||
| - | Négation arithmétique | ||
| -- | Décrémentation préfixée | ||
| ++ | Incrémentation préfixée | ||
| 3 | * | Multiplication | |
| / | Division | ||
| % | Modulo | ||
| 4 | + | Addition | |
| - | Soustraction | ||
| 5 | << | Décalage de bits à gauche | |
| >> | Décalage de bits à droite | ||
| 6 | < | Plus petit | |
| <= | Plus petit ou égal | ||
| > | Plus grand | ||
| >= | Plus grand ou égal | ||
| 7 | == | Égalité | |
| != | Inégalité | ||
| 8 | & | Et bit à bit | |
| 9 | ^ | Ou exclusif bit à bit | |
| 10 | | | Ou bit à bit | |
| 11 | && | Et logique | |
| 12 | || | Ou logique | |
| 13 | ?: | Opérateur conditionnel | |
| 14 | = | Affectation | |
| += | Addition et affectation | ||
| -= | Soustraction et affectation | ||
| *= | Multiplication et affectation | ||
| /= | Division et affectation | ||
| %= | Modulo et affectation | ||
| <<= | Décalage à gauche et affectation | ||
| >>= | Décalage à droite et affectation | ||
| &= | Et bit à bit et affectation | ||
| ^= | Ou exclusif bit à bit et affectation | ||
| |= | Ou bit à bit et affectation | ||
| 15 | , | Séquence |
Les deux derniers opérateurs de priorité 1 et les opérateurs de priorité 2 sont unaires.
Structures conditionnelles
Le langage C offre deux principales structures conditionnelles : l'une selon une condition, l'autre selon une valeur.
Si
Le mot-clé if suivi d'une condition, entre parenthèses, permet d'introduire cette structure. Les instructions exécutées si cette condition est vraie sont placées entre accolades :
if (note >= 60) {
printf("Reussite\n");
}
Le mot-clé else permet d'introduire une branche pour exécuter des instructions, placées entre accolades, seulement si la condition est fausse :
if (note >= 60) {
printf("Reussite\n");
}
else {
printf("Echec\n");
}
Dans le cas où une branche ne contient qu'une seule instruction, les accolades sont facultatives :

Cas
Le mot-clé switch suivi d'une valeur entière, entre parenthèses, permet d'introduire cette structure. Les cas, introduits par le mot-clé case suivi d'une valeur constante entière unique et du caractère :, sont placés entre accolades. Un cas par défaut peut être introduit par le mot-clé default suivi du caractère :.
switch (position) {
case 1:
printf("Medaille d'or\n");
break;
case 2:
printf("Medaille d'argent\n");
break;
case 3:
printf("Medaille de bronze\n");
break;
default:
printf("Aucune medaille\n");
break;
}
L'exécution des instructions continue, même dans les cas suivants, jusqu'à la rencontre de l'instruction break ou jusqu'à la fin de la structure :

Structures de répétition
Les boucles permettent d'exécuter un bloc d'instructions de façon répétée.
Tant que
Cette boucle itère tant que sa condition est vraie :
int compteur = 6;
while (--compteur)
printf("%i\n", compteur);
Le mot-clé while, suivi d'une condition entre parenthèses, introduit cette structure. Les instructions exécutées à chaque itération se trouvent entre accolades. Les accolades sont facultatives s'il n'y a qu'une instruction :
Pour
Cette boucle permet d'alléger la syntaxe et de déclarer les itérateurs localement :
for (long compteur = 5; compteur; --compteur)
printf("%i\n", compteur);
La syntaxe de cette structure comporte trois expressions, séparées par le caractère ; :
- Initialisation : exécutée qu'une seule fois, avant la boucle.
- Condition : évaluée avant chaque itération de la boucle.
- Post-itération : exécutée à la fin de chaque itération de la boucle.
Fonctions
Les fonctions permettent de subdiviser subdiviser un programme et éviter la répétition de code puisqu'elles sont réutilisables :
void fonction() {
// Instructions exécutées par la fonction
}
La définition d'une fonction commence par son type de retour, suivi d'un identificateur puis de la liste de paramètres entre parenthèses. Le corps de la fonction se trouve dans un bloc de code, entre accolades :

Le mot-clé return permet de retourner une valeur et l'exécution de la fonction s'arrête dès cette instruction :
int min(int nbr1, int nbr2) {
if (nbr1 < nbr2)
return nbr1;
return nbr2;
}
Principale
La fonction principale main peut recevoir des arguments lors de son appel :
#include <stdio.h>
/// @brief Fonction principale.
/// @param argc Nombre d'arguments.
/// @param argv Arguments.
/// @return Code de retour.
int main(int argc, char* argv[]) {
for (int i = 0; i < argc; ++i)
printf("%s\n", argv[i]);
return 0;
}
Bibliothèque standard
Le langage C vient avec une bibliothèque standard proposant des fonctionnalités courantes.
Chaînes de caractères
Une chaîne de caractères n’est en réalité qu'une suite, un tableau, de caractères se terminant par la valeur \0 :
char chaine[26] = "Langages";
printf("%s\n", chaine);
Uniquement à la déclaration, les guillemets initialisent chaque case du tableau avec le caractère correspondant et ajoutent automatiquement le caractère \0 final.
Pour utiliser les fonctions de chaînes de caractères, le fichier d'en-tête doit être inclus :
#include <string.h>
Concaténer
La fonction strcat permet de concaténer une chaîne de caractères à une autre :
strcat(chaine, " de programmation");
printf("%s\n", chaine);
La chaîne de destination doit être suffisamment grande, incluant le caractère \0.
Taille
La fonction strlen retourne le nombre de caractères de la chaîne en argument :
printf("Taille : %z\n", strlen(chaine));
Copier
La fonction strcpy permet de copier une chaîne de caractères :
strcpy(chaine, "Programmation III");
printf("%s\n", chaine);
La chaîne de destination doit être suffisamment grande, incluant le caractère \0.
Comparer
La fonction strcmp permet de comparer les caractères de deux chaînes en arguments :
if (strcmp(chaine, "Reseau II"))
printf("Chaines differentes\n");
else
printf("Chaines identiques\n");
Le retour peut être l'un des trois suivants :
| Retour | Description |
|---|---|
| < 0 | Par ordre alphabétique, la première chaîne vient avant la deuxième. |
| == 0 | Les chaînes sont identiques. |
| > 0 | Par ordre alphabétique, la première chaîne vient après la deuxième. |
Affichage
Pour utiliser la fonction d'affichage, le fichier d'en-tête des entrées et sorties standards doit être inclus :
#include <stdio.h>
La fonction printf permet d'afficher une chaîne de caractères formatée dans le terminal :
printf("420-C35-JO : Langages de programmation\n");
Caractères spéciaux
Des séquences de caractères spéciaux peuvent être utilisées dans le format :
| Séquence | Description |
|---|---|
\n | Saut de ligne |
\t | Tabulation |
\\ | Caractère \ |
\" | Caractère " |
| ... | ... |
Balises de données
Une balise de donnée, dans le format, sera remplacée par une valeur de ce type :
| Balise | Description |
|---|---|
%i | Entier signé |
%u | Entier non signé |
%z | Type taille |
%X | Entier non signé sous forme hexadécimal |
%p | Adresse mémoire |
%f | Réel |
%e | Réel en notation scientifique |
%c | Caractère |
%s | Chaîne de caractères |
%% | Caractère % |
| ... | ... |
Les valeurs qui remplaceront les balises de données doivent être spécifiées, dans l'ordre, à la suite du format :
short entier = 404;
float reel = 3.14159;
printf("La variable entier vaut %i et reel vaut %f\n", entier, reel);
Gabarit
Il est possible de préciser le nombre minimum de caractères à afficher :
int entier = 123456;
printf("L'entier %10i est precede de 4 espaces.\n", entier);
printf("L'entier %010i est precede de 4 zeros.\n", entier);
Précision
Pour les réels, il est aussi possible de préciser le nombre de décimales :
float reel = 123.456789;
printf("Le reel %.2f est arrondi a 2 decimales.\n", reel);
Six décimales sont affichées par défaut pour les balises %f et %e.
Fichiers
La structure FILE permet de représenter un fichier :
FILE* fichier;
Ouverture
La fonction fopen permet d'ouvrir un fichier :
fichier = fopen("NomFichier.ext", mode);
Le mode d'ouverture peut être l'un des suivants :
| Mode | Description |
|---|---|
| "r" | Lecture (le fichier doit être existant) |
| "rb" | Lecture binaire (le fichier doit être existant) |
| "w" | Écriture (le fichier est créé ou écrasé si existant) |
| "wb" | Écriture binaire (le fichier est créé ou écrasé si existant) |
| "a" | Ajout (le fichier est ouvert à la fin ou créé si inexistant) |
| "ab" | Ajout binaire (le fichier est ouvert à la fin ou créé si inexistant) |
Validation
Pour valider si le fichier a été ouvert :
if (fichier)
// L'ouverture du fichier a réussi
else
// L'ouverture du fichier a échoué
Déplacement
La fonction fseek permet de se déplacer dans un fichier :
fseek(fichier, deplacement, origine);
Le déplacement est exprimé en nombre d'octets.
L'origine peut être l'une des suivantes :
| Origine | Description |
|---|---|
| SEEK_SET | Début du fichier |
| SEEK_CUR | Position actuelle |
| SEEK_END | Fin du fichier |
Position
La fonction ftell permet d'obtenir la position actuelle :
long position = ftell(fichier);
Lecture
La fonction fread permet de lire dans un fichier :
fread(destination, taille, compte, fichier);
Le compte correspond au nombre de données à lire et leur taille est exprimée en octets.
La lecture se fait à partir de la position actuelle dans le fichier, et cette position est modifiée selon le nombre et la taille des données lues.
Fermeture
La fonction fclose permet de fermer un fichier :
fclose(fichier);