Formation Langage C
Apprenez le langage C, le fondement de nombreux langages de programmation modernes
Introduction au Langage C
Le langage C est un langage de programmation procédural de bas niveau, créé par Dennis Ritchie aux Bell Labs en 1972. C est le fondement de nombreux langages modernes (C++, Java, C#, Python, etc.) et reste largement utilisé pour la programmation système, les systèmes embarqués, et les applications nécessitant des performances élevées.
⚙️ Qu'est-ce que le langage C ?
Le langage C est un langage de programmation compilé et procédural. C est un langage de bas niveau qui donne un contrôle direct sur la mémoire et les ressources système. C'est un langage puissant mais qui nécessite une compréhension approfondie de la gestion mémoire et des pointeurs.
💡 Pourquoi le langage C est si important ?
- Fondement des langages modernes - C est à la base de nombreux langages (C++, Java, C#, Python, JavaScript). Comprendre C aide à mieux maîtriser ces langages
- Performance maximale - C offre un contrôle direct sur la mémoire et les ressources système, permettant des applications très rapides
- Programmation système - Utilisé pour développer les systèmes d'exploitation (Linux, Windows), les drivers, les compilateurs
- Systèmes embarqués - Idéal pour la programmation de microcontrôleurs, IoT, systèmes temps réel
- Standard et portable - Code C peut être compilé sur presque toutes les plateformes (Windows, Linux, macOS, embarqué)
- Contrôle total - Gestion manuelle de la mémoire et des pointeurs donne un contrôle précis sur les performances
🚀 Pourquoi apprendre le langage C ?
Le langage C est essentiel pour comprendre les fondements de la programmation :
- ✅ Comprendre l'informatique - C vous apprend comment fonctionnent vraiment les ordinateurs, la mémoire, les pointeurs
- ✅ Performance - Applications nécessitant des performances maximales (jeux vidéo, systèmes temps réel, embarqué)
- ✅ Programmation système - Développement de systèmes d'exploitation, drivers, compilateurs, outils système
- ✅ Base solide - Comprendre C facilite l'apprentissage de C++, Java, et autres langages dérivés
- ✅ Industrie - Très utilisé dans l'embarqué, l'automobile, l'aéronautique, les systèmes critiques
- ✅ Contrôle précis - Gestion manuelle de la mémoire permet d'optimiser chaque octet
- ✅ Standard ANSI - Langage standardisé, portable sur toutes les plateformes
📋 Prérequis pour apprendre C
Pour apprendre C efficacement, il est recommandé d'avoir :
- ✅ Informatique de base - Savoir utiliser un ordinateur, créer et éditer des fichiers
- ✅ Logique de programmation - Comprendre les concepts de base (variables, conditions, boucles) est très utile
- ✅ Patience - C nécessite plus d'attention aux détails que les langages de haut niveau
💡 Note importante : Pour compiler du code C, vous avez besoin d'un compilateur comme GCC (GNU Compiler Collection) qui est disponible gratuitement. Sur Linux, GCC est souvent préinstallé. Sur Windows, vous pouvez installer MinGW ou utiliser Visual Studio. Sur macOS, installez Xcode Command Line Tools. Vous pouvez aussi utiliser des IDE comme Code::Blocks, Dev-C++, ou Visual Studio Code avec l'extension C/C++.
🎯 Cas d'usage du langage C
Le langage C est utilisé dans de nombreux domaines critiques :
- Systèmes d'exploitation - Linux, Windows (en partie), macOS utilisent C pour leurs noyaux
- Programmation système - Drivers, compilateurs, interpréteurs, outils système
- Systèmes embarqués - Microcontrôleurs, IoT, systèmes temps réel, automobile, aéronautique
- Jeux vidéo - Moteurs de jeux nécessitant des performances maximales
- Réseaux - Protocoles réseau, serveurs haute performance
- Calcul scientifique - Applications nécessitant des calculs intensifs
- Bases de données - Moteurs de bases de données (MySQL, PostgreSQL utilisent C)
- Serveurs web - Serveurs web haute performance (nginx, Apache)
📝 Syntaxe de base
Le langage C est un langage de programmation procédural et compilé. C utilise des accolades {} pour définir les blocs de code et nécessite un point-virgule ; à la fin de chaque instruction.
// Premier programme C
#include
int main() {
printf("Bonjour, monde !\n");
return 0;
}
// Variables
int age = 25;
char nom[] = "NiangProgrammeur";
// Affichage formaté
printf("Je m'appelle %s et j'ai %d ans\n", nom, age);
// Opérations simples
int resultat = 10 + 5;
printf("10 + 5 = %d\n", resultat);
}
💡 Points importants sur la syntaxe C :
- C utilise des accolades
{}pour définir les blocs de code - Les commentaires utilisent
//pour une ligne ou/* */pour plusieurs lignes - Point-virgule obligatoire
;à la fin de chaque instruction - Les chaînes de caractères utilisent des guillemets doubles
"et sont des tableaux de caractères - Les fonctions doivent être déclarées avant leur utilisation (ou via des headers)
- Le point d'entrée est la fonction
main()qui retourne unint
🔍 Exemple détaillé de syntaxe
Voici un exemple complet montrant plusieurs aspects de la syntaxe C :
#include
// Définition d'une fonction
int calculer_moyenne(int nombres[], int taille) {
if (taille == 0) {
return 0;
}
int somme = 0;
for (int i = 0; i < taille; i++) {
somme += nombres[i];
}
return somme / taille;
}
// Fonction principale
int main() {
int notes[] = {15, 18, 12, 20, 16};
int moyenne = calculer_moyenne(notes, 5);
printf("La moyenne est : %d\n", moyenne);
return 0;
}
🔤 Variables
En C, les variables doivent être déclarées avec un type avant d'être utilisées. C est un langage à typage statique, ce qui signifie que le type d'une variable est déterminé au moment de la compilation et ne peut pas changer.
#include
int main() {
// Déclaration de variables
int age = 30; // Entier
float prix = 19.99f; // Nombre décimal (simple précision)
double decimal = 3.14159; // Nombre décimal (double précision)
char lettre = 'A'; // Caractère unique
char nom[] = "C"; // Chaîne de caractères (tableau)
// Affichage avec printf
printf("Age: %d\n", age);
printf("Prix: %.2f\n", prix);
printf("Decimal: %lf\n", decimal);
printf("Lettre: %c\n", lettre);
printf("Nom: %s\n", nom);
// Déclaration puis assignation
int nombre;
nombre = 10;
printf("Nombre: %d\n", nombre);
// Constantes avec #define
#define PI 3.14159
#define MAX_SIZE 100
// Constantes avec const
const int TAILLE = 50;
const char* MESSAGE = "Bonjour";
// Noms de variables valides
int age_utilisateur = 25;
char nom_utilisateur[] = "Bassirou";
float _prive = 3.14; // Possible mais non recommandé
return 0;
}
📌 Règles pour les noms de variables :
- Doivent commencer par une lettre ou un underscore
_ - Peuvent contenir des lettres, chiffres et underscores
- Ne peuvent pas contenir d'espaces ou de caractères spéciaux
- Sont sensibles à la casse (
age≠Age) - Ne peuvent pas être des mots-clés C (
if,for,int, etc.) - Convention : utilisez
snake_caseoucamelCasepour les variables
📊 Types de données
C a plusieurs types de données de base (primitifs). Voici les principaux types disponibles en C :
#include
#include // Pour le type bool
int main() {
// Types entiers
char c = 'A'; // 1 octet (-128 à 127 ou 0 à 255)
short s = 100; // 2 octets (-32768 à 32767)
int i = 1000; // 4 octets (généralement)
long l = 100000L; // 4 ou 8 octets
long long ll = 1000000LL; // 8 octets
// Types entiers non signés
unsigned char uc = 200;
unsigned int ui = 5000;
unsigned long ul = 100000UL;
// Types décimaux
float f = 3.14f; // 4 octets (simple précision)
double d = 3.14159; // 8 octets (double précision)
long double ld = 3.141592653589793L; // 10 ou 16 octets
// Type booléen (C99+)
bool est_vrai = true;
bool est_faux = false;
// Chaînes de caractères (tableaux de char)
char chaine[] = "Hello"; // Tableau de caractères
char* pointeur = "World"; // Pointeur vers une chaîne
// Affichage avec printf
printf("char: %c\n", c);
printf("int: %d\n", i);
printf("float: %.2f\n", f);
printf("double: %lf\n", d);
printf("bool: %d\n", est_vrai);
printf("chaine: %s\n", chaine);
// Taille des types (en octets)
printf("Taille de int: %zu octets\n", sizeof(int));
printf("Taille de float: %zu octets\n", sizeof(float));
printf("Taille de double: %zu octets\n", sizeof(double));
return 0;
}
📚 Types de données C :
- char - Caractère (1 octet)
- int - Entier (généralement 4 octets)
- float - Nombre décimal simple précision (4 octets)
- double - Nombre décimal double précision (8 octets)
- void - Type vide (pour fonctions sans retour)
- bool - Booléen (C99+, nécessite stdbool.h)
- short, long, long long - Variantes d'entiers
- unsigned - Modificateur pour entiers non signés
🔢 Opérateurs
C supporte les opérateurs arithmétiques, de comparaison, logiques, d'assignation et de pointeurs :
#include
#include // Pour pow()
int main() {
int a = 10, b = 3;
// Opérateurs arithmétiques
printf("%d + %d = %d\n", a, b, a + b); // Addition: 13
printf("%d - %d = %d\n", a, b, a - b); // Soustraction: 7
printf("%d * %d = %d\n", a, b, a * b); // Multiplication: 30
printf("%d / %d = %d\n", a, b, a / b); // Division entière: 3
printf("%d %% %d = %d\n", a, b, a % b); // Modulo (reste): 1
// Division avec float
float resultat = (float)a / b;
printf("%d / %d = %.2f\n", a, b, resultat); // Division: 3.33
// Puissance (nécessite math.h)
double puissance = pow(a, b);
printf("%d^%d = %.0f\n", a, b, puissance); // Puissance: 1000
// Opérateurs de comparaison
printf("%d > %d = %d\n", a, b, a > b); // 1 (true)
printf("%d < %d = %d\n", a, b, a < b); // 0 (false)
printf("%d >= %d = %d\n", a, b, a >= b); // 1 (true)
printf("%d <= %d = %d\n", a, b, a <= b); // 0 (false)
printf("%d == %d = %d\n", a, b, a == b); // 0 (false)
printf("%d != %d = %d\n", a, b, a != b); // 1 (true)
// Opérateurs logiques
int x = 1, y = 0; // 1 = true, 0 = false
printf("%d && %d = %d\n", x, y, x && y); // ET logique: 0
printf("%d || %d = %d\n", x, y, x || y); // OU logique: 1
printf("!%d = %d\n", x, !x); // NON logique: 0
// Opérateurs d'assignation
int c = 5;
c += 3; // Équivalent à c = c + 3 (c devient 8)
c -= 2; // Équivalent à c = c - 2 (c devient 6)
c *= 2; // Équivalent à c = c * 2 (c devient 12)
c /= 3; // Équivalent à c = c / 3 (c devient 4)
c %= 3; // Équivalent à c = c % 3 (c devient 1)
// Opérateurs d'incrémentation/décrémentation
int i = 5;
printf("i = %d\n", i++); // Post-incrémentation: affiche 5, puis i = 6
printf("i = %d\n", ++i); // Pré-incrémentation: i = 7, puis affiche 7
return 0;
}
🔀 Structures conditionnelles
Le langage C utilise if, else if et else pour les conditions. Les blocs de code sont délimités par des accolades {}.
# Structure if simple
age = 20
if age >= 18:
print("Vous êtes majeur")
else:
print("Vous êtes mineur")
# Structure if/elif/else
age = 15
if age >= 18:
print("Vous êtes majeur")
print("Vous pouvez voter")
elif age >= 13:
print("Vous êtes adolescent")
elif age >= 6:
print("Vous êtes enfant")
else:
print("Vous êtes un bébé")
# Conditions multiples
note = 85
if note >= 90:
mention = "Excellent"
elif note >= 80:
mention = "Très bien"
elif note >= 70:
mention = "Bien"
elif note >= 60:
mention = "Assez bien"
else:
mention = "Insuffisant"
print(f"Votre mention : {mention}")
# Opérateur ternaire (expression conditionnelle)
age = 20
statut = "Majeur" if age >= 18 else "Mineur"
print(statut)
# Conditions avec and/or
age = 25
permis = True
if age >= 18 and permis:
print("Vous pouvez conduire")
else:
print("Vous ne pouvez pas conduire")
🔄 Boucles
Le langage C propose trois types de boucles : for (pour itérer un nombre défini de fois), while (pour répéter tant qu'une condition est vraie) et do-while (exécute au moins une fois) :
# Boucle for avec range()
for i in range(5):
print(i) # Affiche 0, 1, 2, 3, 4
# range() avec début et fin
for i in range(1, 6):
print(i) # Affiche 1, 2, 3, 4, 5
# range() avec pas
for i in range(0, 10, 2):
print(i) # Affiche 0, 2, 4, 6, 8
# Boucle for avec liste
fruits = ["pomme", "banane", "orange"]
for fruit in fruits:
print(f"J'aime les {fruit}")
# Boucle for avec index (enumerate)
fruits = ["pomme", "banane", "orange"]
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# Boucle while
compteur = 0
while compteur < 5:
print(compteur)
compteur += 1
# Boucle while avec break
compteur = 0
while True:
print(compteur)
compteur += 1
if compteur >= 5:
break # Sortir de la boucle
# continue (passer à l'itération suivante)
for i in range(10):
if i % 2 == 0: # Si i est pair
continue # Passer au suivant
print(i) # Affiche seulement les impairs: 1, 3, 5, 7, 9
# Boucle for avec else
for i in range(5):
print(i)
else:
print("Boucle terminée") # Exécuté si la boucle se termine normalement
⚙️ Fonctions
Les fonctions permettent de réutiliser du code. En C, on définit une fonction avec son type de retour, son nom et ses paramètres. Les fonctions peuvent prendre des paramètres et retourner des valeurs avec return.
# Fonction simple (sans paramètres)
def dire_bonjour():
print("Bonjour !")
dire_bonjour() # Appel de la fonction
# Fonction avec paramètres
def saluer(nom):
return f"Bonjour, {nom} !"
message = saluer("Python")
print(message) # "Bonjour, Python !"
# Fonction avec plusieurs paramètres
def additionner(a, b):
return a + b
resultat = additionner(5, 3)
print(resultat) # 8
# Fonction avec paramètres par défaut
def saluer_personne(nom, message="Bonjour"):
return f"{message}, {nom} !"
print(saluer_personne("Bassirou")) # "Bonjour, Bassirou !"
print(saluer_personne("Bassirou", "Salut")) # "Salut, Bassirou !"
# Fonction avec arguments nommés
def creer_personne(nom, age, ville="Dakar"):
return f"{nom}, {age} ans, habite à {ville}"
print(creer_personne("Bassirou", 25))
print(creer_personne(age=25, nom="Bassirou", ville="Thiès"))
# Fonction avec *args (arguments variables)
def additionner_nombres(*args):
return sum(args)
print(additionner_nombres(1, 2, 3, 4, 5)) # 15
# Fonction avec **kwargs (arguments nommés variables)
def afficher_info(**kwargs):
for cle, valeur in kwargs.items():
print(f"{cle}: {valeur}")
afficher_info(nom="Bassirou", age=25, ville="Dakar")
# Fonction lambda (fonction anonyme)
carre = lambda x: x ** 2
print(carre(5)) # 25
# Utilisation de lambda avec map()
nombres = [1, 2, 3, 4, 5]
carres = list(map(lambda x: x ** 2, nombres))
print(carres) # [1, 4, 9, 16, 25]
📍 Pointeurs
Les pointeurs sont l'une des fonctionnalités les plus puissantes et importantes du langage C. Un pointeur est une variable qui stocke l'adresse mémoire d'une autre variable.
#include
int main() {
int nombre = 42;
int* ptr = &nombre; // ptr pointe vers nombre
printf("Valeur de nombre: %d\n", nombre); // 42
printf("Adresse de nombre: %p\n", &nombre); // Adresse mémoire
printf("Valeur de ptr: %p\n", ptr); // Même adresse
printf("Valeur pointée par ptr: %d\n", *ptr); // 42 (déréférencement)
// Modifier via le pointeur
*ptr = 100;
printf("Nouvelle valeur de nombre: %d\n", nombre); // 100
// Pointeur NULL
int* ptr_null = NULL;
if (ptr_null == NULL) {
printf("Pointeur NULL\n");
}
// Pointeurs et tableaux
int tableau[] = {1, 2, 3, 4, 5};
int* ptr_tableau = tableau; // tableau est déjà un pointeur
printf("Premier élément: %d\n", *ptr_tableau); // 1
printf("Deuxième élément: %d\n", *(ptr_tableau + 1)); // 2
printf("Troisième élément: %d\n", ptr_tableau[2]); // 3
return 0;
}
📋 Tableaux
Les tableaux en C sont des collections d'éléments du même type stockés en mémoire de manière contiguë. La taille d'un tableau est fixe et doit être connue à la compilation.
#include
int main() {
// Déclaration et initialisation
int nombres[5] = {1, 2, 3, 4, 5};
int tableau[10]; // Tableau non initialisé
// Accès aux éléments (index commence à 0)
printf("Premier élément: %d\n", nombres[0]); // 1
printf("Dernier élément: %d\n", nombres[4]); // 5
// Modification
nombres[1] = 10;
printf("nombres[1] = %d\n", nombres[1]); // 10
// Parcourir un tableau
for (int i = 0; i < 5; i++) {
printf("nombres[%d] = %d\n", i, nombres[i]);
}
// Tableaux multidimensionnels
int matrice[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", matrice[i][j]);
}
printf("\n");
}
// Tableaux de caractères (chaînes)
char chaine[] = "Bonjour";
char nom[20] = "C";
printf("Chaine: %s\n", chaine);
printf("Nom: %s\n", nom);
return 0;
}
🏗️ Structures (struct)
Les structures permettent de regrouper plusieurs variables de types différents sous un seul nom. C'est l'équivalent des "objets" dans d'autres langages, mais sans méthodes.
#include
#include
// Définition d'une structure
struct Personne {
char nom[50];
int age;
float taille;
};
int main() {
// Création d'une variable de type Personne
struct Personne p1;
strcpy(p1.nom, "Bassirou");
p1.age = 25;
p1.taille = 1.75;
printf("Nom: %s\n", p1.nom);
printf("Age: %d\n", p1.age);
printf("Taille: %.2f\n", p1.taille);
// Initialisation lors de la déclaration
struct Personne p2 = {"Aminata", 30, 1.65};
printf("\nNom: %s, Age: %d\n", p2.nom, p2.age);
// Tableau de structures
struct Personne personnes[3] = {
{"Bassirou", 25, 1.75},
{"Aminata", 30, 1.65},
{"Ibrahima", 28, 1.80}
};
for (int i = 0; i < 3; i++) {
printf("%s a %d ans\n", personnes[i].nom, personnes[i].age);
}
// Pointeurs vers structures
struct Personne* ptr = &p1;
printf("\nNom via pointeur: %s\n", ptr->nom); // Opérateur ->
printf("Age via pointeur: %d\n", (*ptr).age); // Ou (*ptr).age
return 0;
}
💾 Gestion de la mémoire
En C, vous devez gérer manuellement la mémoire. Les fonctions malloc(), calloc(), realloc() et free() permettent d'allouer et libérer de la mémoire dynamiquement.
#include
#include // Pour malloc, calloc, realloc, free
int main() {
// Allocation dynamique avec malloc
int* ptr = (int*)malloc(5 * sizeof(int)); // Tableau de 5 entiers
if (ptr == NULL) {
printf("Erreur d'allocation mémoire\n");
return 1;
}
// Utilisation de la mémoire allouée
for (int i = 0; i < 5; i++) {
ptr[i] = i * 10;
}
for (int i = 0; i < 5; i++) {
printf("ptr[%d] = %d\n", i, ptr[i]);
}
// Libération de la mémoire
free(ptr);
ptr = NULL; // Bonne pratique : mettre le pointeur à NULL
// Allocation avec calloc (initialise à zéro)
int* ptr2 = (int*)calloc(5, sizeof(int));
printf("\nTableau initialisé à zéro:\n");
for (int i = 0; i < 5; i++) {
printf("ptr2[%d] = %d\n", i, ptr2[i]);
}
// Réallocation avec realloc
ptr2 = (int*)realloc(ptr2, 10 * sizeof(int)); // Agrandir à 10 éléments
printf("\nAprès réallocation:\n");
for (int i = 5; i < 10; i++) {
ptr2[i] = i * 10;
}
for (int i = 0; i < 10; i++) {
printf("ptr2[%d] = %d\n", i, ptr2[i]);
}
free(ptr2);
// Allocation pour une chaîne de caractères
char* chaine = (char*)malloc(50 * sizeof(char));
if (chaine != NULL) {
strcpy(chaine, "Bonjour C !");
printf("\nChaine: %s\n", chaine);
free(chaine);
}
return 0;
}
💡 Note importante : En C, vous devez toujours libérer la mémoire allouée avec free() pour éviter les fuites mémoire. N'oubliez jamais de vérifier si l'allocation a réussi (pointeur != NULL) avant d'utiliser la mémoire !
📁 Manipulation de fichiers
En C, la manipulation de fichiers se fait avec les fonctions de la bibliothèque standard : fopen(), fclose(), fprintf(), fscanf(), fread(), fwrite(), etc.
#include
int main() {
FILE* fichier;
// Écrire dans un fichier (mode "w" = write)
fichier = fopen("fichier.txt", "w");
if (fichier == NULL) {
printf("Erreur lors de l'ouverture du fichier\n");
return 1;
}
fprintf(fichier, "Bonjour C !\n");
fprintf(fichier, "Ceci est la deuxième ligne\n");
fclose(fichier);
// Lire un fichier (mode "r" = read)
fichier = fopen("fichier.txt", "r");
if (fichier == NULL) {
printf("Erreur lors de l'ouverture du fichier\n");
return 1;
}
char ligne[100];
while (fgets(ligne, sizeof(ligne), fichier) != NULL) {
printf("%s", ligne);
}
fclose(fichier);
// Ajouter à un fichier (mode "a" = append)
fichier = fopen("fichier.txt", "a");
if (fichier != NULL) {
fprintf(fichier, "Nouvelle ligne ajoutée\n");
fclose(fichier);
}
// Modes de fichier
// "r" - Lecture (le fichier doit exister)
// "w" - Écriture (crée ou écrase le fichier)
// "a" - Ajout (ajoute à la fin, crée si n'existe pas)
// "r+" - Lecture et écriture
// "w+" - Lecture et écriture (crée ou écrase)
// "a+" - Lecture et ajout
return 0;
}
💡 Bonne pratique : Toujours fermer les fichiers avec fclose() après utilisation pour libérer les ressources. Vérifiez toujours que fopen() retourne un pointeur non-NULL avant d'utiliser le fichier. Cela évite les fuites de ressources et les erreurs d'accès !
🎓 Prochaines étapes
Félicitations ! Vous avez maintenant une solide base en langage C.
✅ Ce que vous avez appris :
- Syntaxe C et variables
- Types de données (int, float, double, char, void)
- Opérateurs (arithmétiques, comparaison, logiques, pointeurs)
- Structures conditionnelles (if, else if, else, switch)
- Boucles (for, while, do-while)
- Fonctions (définition, paramètres, return, prototypes)
- Pointeurs et références
- Tableaux et chaînes de caractères
- Structures (struct) et unions
- Gestion de la mémoire (malloc, calloc, realloc, free)
- Manipulation de fichiers (fopen, fclose, fprintf, fscanf, fread, fwrite)
🚀 Pour aller plus loin :
- C++ - Langage orienté objet basé sur C
- Programmation système - Développement de drivers, outils système
- Bibliothèques C - Utilisation de bibliothèques externes (GTK, SDL, etc.)
- Réseaux - Programmation réseau avec sockets
- Algorithmes avancés - Structures de données complexes, algorithmes optimisés
- Systèmes embarqués - Programmation de microcontrôleurs, IoT