💻 Langage C - S5

Année: 2022-2023 (Semestre 5)
Crédits: 3 ECTS
Type: Programmation Système


PART A: PRÉSENTATION GÉNÉRALE

Objectifs du cours

Le cours de Langage C fournit une formation complète à la programmation système en C, langage fondamental pour le développement de systèmes embarqués, systèmes d'exploitation et applications nécessitant des performances optimales. Le cours couvre les concepts fondamentaux (pointeurs, tableaux, structures) ainsi que les aspects avancés (allocation dynamique, manipulation de bits, structures de données complexes).

Compétences visées

  • Maîtriser la syntaxe C et les types de données
  • Comprendre les pointeurs et l'arithmétique des pointeurs
  • Gérer la mémoire dynamique (malloc, free)
  • Manipuler les structures de données (listes chaînées, arbres)
  • Réaliser des opérations bit à bit pour le bas niveau
  • Créer des programmes modulaires avec fichiers multiples
  • Déboguer et optimiser du code C

Organisation

  • Volume horaire: 48h (CM: 24h, TD/TP: 24h)
  • Évaluation: Examens écrits (60%) + TPs et projets (40%)
  • Semestre: 5 (2022-2023)
  • Prérequis: Algorithmique de base, notions de programmation

PART B: EXPÉRIENCE, CONTEXTE ET FONCTION

Contenu pédagogique

1. Fondamentaux du C

Types de données et opérateurs:

Le C propose des types primitifs de tailles fixes:

  • char: 1 octet (8 bits)
  • int: 4 octets sur systèmes 32/64 bits
  • float: 4 octets (simple précision)
  • double: 8 octets (double précision)

Modificateurs: signed, unsigned, short, long

Exemple de déclarations:

int nombre = 42;
unsigned int positif = 100;
char lettre = 'A';
float pi = 3.14f;

Opérateurs bit à bit:

Essentiels pour la manipulation bas niveau:

  • & (AND), | (OR), ^ (XOR), ~ (NOT)
  • << (décalage gauche), >> (décalage droite)

Application TD1: Compter les bits à 1 dans un entier:

int bitcount(int n) {
    int count = 0;
    while (n) {
        count += n & 1;  // Teste le bit de poids faible
        n >>= 1;         // Décale d'un bit à droite
    }
    return count;
}

Pour 0xF0000F00, résultat: 8 bits à 1.

Structures de contrôle:

Boucles et conditionnelles standard:

// Tri à bulles (TD1)
for (int j = 0; j < TAILLE-1; j++) {
    for (int i = 0; i < TAILLE-j-1; i++) {
        if (tab[i+1] < tab[i]) {
            int temp = tab[i];
            tab[i] = tab[i+1];
            tab[i+1] = temp;
        }
    }
}

2. Pointeurs et Gestion Mémoire

Les pointeurs:

Concept fondamental du C: variable contenant une adresse mémoire.

Déclaration et utilisation:

int x = 10;
int *ptr = &x;  // ptr pointe vers x
*ptr = 20;      // Modifie x via le pointeur

Arithmétique des pointeurs:

int tab[5] = {1, 2, 3, 4, 5};
int *p = tab;  // Pointe vers tab[0]
p++;           // Pointe vers tab[1]
*p = 100;      // tab[1] = 100

Permutation par pointeurs (TD2):

int Permute(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
    return 0;
}

Allocation dynamique:

Fonctions essentielles:

  • malloc(size): alloue size octets
  • calloc(n, size): alloue et initialise à 0
  • free(ptr): libère la mémoire

Exemple TD2:

char* chaine = calloc(10, sizeof(char));
int* tab = calloc(10, sizeof(int));

// Utilisation...

free(chaine);
free(tab);

Risques:

  • Fuite mémoire si oubli de free
  • Double free (libérer deux fois)
  • Accès après free (use-after-free)
  • Dépassement de buffer

3. Structures et Types Composés

Définition de structures (TD3):

struct Etudiant {
    char nom[50];
    int naissance;
    int notes[10];
    int nb_notes;
};

Utilisation:

struct Etudiant cedric;
strcpy(cedric.nom, "Chanfreau");
cedric.naissance = 2000;
cedric.notes[0] = 15;

Pointeurs vers structures:

struct Etudiant *ptr = &cedric;
ptr->naissance = 2001;  // Équivalent à (*ptr).naissance
Illustration des pointeurs en C

Figure : Concept des pointeurs - Un pointeur stocke l'adresse mémoire d'une variable

Copie de structures:

Attention aux pointeurs dans les structures:

struct S1 {
    int a;
    char* ch;  // Pointeur
};

struct S1 v1, v2;
v1.ch = calloc(10, sizeof(char));
strcpy(v1.ch, "Test");

v2 = v1;  // Copie superficielle: v2.ch pointe vers la même zone!

Solution: copie profonde manuelle ou allocation séparée.

4. Structures de Données Dynamiques

Listes chaînées (TP principal):

Structure d'un élément:

struct element {
    struct Coureur* coureur;
    struct element* suiv;
};

struct liste {
    struct element* premier;
    struct element* dernier;
    struct element* courant;
};

Initialisation:

int init_liste(struct liste* liste) {
    liste->premier = NULL;
    liste->dernier = NULL;
    return 0;
}

Ajout en queue (file):

int ajout_file(struct liste* der, struct Coureur* coureur) {
    if (der->dernier == NULL) {
        // Liste vide
        der->dernier = malloc(sizeof(struct element));
        der->dernier->coureur = coureur;
        der->premier = der->dernier;
        der->dernier->suiv = NULL;
    } else {
        // Ajout en fin
        der->dernier->suiv = malloc(sizeof(struct element));
        der->dernier = der->dernier->suiv;
        der->dernier->coureur = coureur;
        der->dernier->suiv = NULL;
    }
    return 0;
}

Parcours de liste:

int Aller_Debut(struct liste* liste) {
    liste->courant = liste->premier;
    return 0;
}

int Avancer(struct liste* liste) {
    liste->courant = liste->courant->suiv;
    return 0;
}

int Fin(struct liste liste) {
    return (liste.courant == NULL);
}

Comptage d'éléments:

int nbElement(struct liste liste) {
    int count = 0;
    while (!Fin(liste)) {
        Avancer(&liste);
        count++;
    }
    return count;
}

5. Fichiers et Arguments

Arguments de ligne de commande (TD2):

int main(int argc, char* argv[]) {
    printf("Nombre d'arguments: %d\n", argc);
    if (argc == 3) {
        printf("Programme: %s\n", argv[0]);
        printf("Arg1: %s\n", argv[1]);
        printf("Arg2: %s\n", argv[2]);
    }
    return 0;
}

Exécution: ./programme arg1 arg2

Manipulation de fichiers:

Ouverture et lecture:

FILE* fichier = fopen("data.txt", "r");
if (fichier == NULL) {
    perror("Erreur ouverture");
    return -1;
}

char buffer[256];
while (fgets(buffer, 256, fichier) != NULL) {
    printf("%s", buffer);
}

fclose(fichier);

Modes d'ouverture: "r" (lecture), "w" (écriture), "a" (ajout), "rb" (binaire)

6. Programmation Modulaire

Projet TP: Structure modulaire

Fichier coureur.h:

#ifndef _COUREUR_H
#define _COUREUR_H

struct Coureur {
    char* nom;
    char* prenom;
    int num_dossard;
    char* nom_equipe;
    int temps_etapes;
};

struct Coureur* Creer_Coureur(char nom[], char prenom[],
                               int dossard, char equipe[], int temps);
int Ajouter_Temps(struct Coureur* coureur, int temps_jour);
int Afficher_Coureur(struct Coureur* coureur);

#endif

Guards d'inclusion: #ifndef, #define, #endif évitent les inclusions multiples.

Compilation modulaire:

gcc -Wall -c coureur.c -o coureur.o
gcc -Wall -c liste.c -o liste.o
gcc -Wall -c test_coureur.c -o test_coureur.o
gcc coureur.o liste.o test_coureur.o -o programme

PART C: ASPECTS TECHNIQUES

Exercices de TD

TD1: Manipulation de tableaux et bits

Objectifs:

  • Tri à bulles d'un tableau
  • Multiplication sans opérateur *
  • Opérations bit à bit (masquage, comptage)

TD2: Pointeurs et allocation dynamique

Exercices:

  • Fonction Permute avec pointeurs
  • Allocation dynamique avec calloc
  • Arguments de ligne de commande

TD3: Structures et copie

Problématiques:

  • Structures avec pointeurs vs tableaux
  • Copie superficielle vs profonde
  • Gestion mémoire dans structures

TD4-TD5: Fichiers et structures avancées

Applications pratiques de manipulation de données.

Travaux Pratiques

TP: Gestion de liste de coureurs

Application complète avec:

  • Structure Coureur avec allocation dynamique de chaînes
  • Liste chaînée pour gérer plusieurs coureurs
  • Opérations: création, ajout, parcours, suppression
  • Affichage et calcul de statistiques

Fonctionnalités implémentées:

  • Création de coureurs avec malloc pour les strings
  • Ajout en file (FIFO)
  • Parcours avec pointeur courant
  • Suppression d'élément à position donnée
  • Comptage d'éléments
  • Libération mémoire complète

TP_bis: Extensions

Versions avancées avec:

  • Tri de listes
  • Recherche par critères
  • Fusion de listes
  • Optimisations mémoire

Outils de Développement

GCC (GNU Compiler Collection):

Compilation de base:

gcc -Wall -o programme source.c

Options utiles:

  • -Wall: affiche tous les warnings
  • -g: ajoute symboles de debug
  • -O2: optimisation niveau 2
  • -std=c99: standard C99

GDB (GNU Debugger):

gcc -g -o programme source.c
gdb ./programme

Commandes GDB:

  • break main: point d'arrêt
  • run: exécution
  • next: ligne suivante
  • print var: afficher variable
  • backtrace: pile d'appels

Valgrind (détection fuites mémoire):

valgrind --leak-check=full ./programme

Détecte:

  • Fuites mémoire (malloc sans free)
  • Accès mémoire invalides
  • Utilisation de mémoire non initialisée

Bonnes Pratiques

Gestion mémoire:

  • Toujours libérer ce qui est alloué
  • Vérifier le retour de malloc
  • Mettre les pointeurs à NULL après free

Code sûr:

char* str = malloc(100);
if (str == NULL) {
    fprintf(stderr, "Erreur allocation\n");
    return -1;
}

// Utilisation...

free(str);
str = NULL;  // Évite double free

Organisation code:

  • Fichiers .h pour déclarations
  • Fichiers .c pour implémentations
  • Guards d'inclusion systématiques
  • Commentaires pour fonctions complexes

PART D: ANALYSE ET RÉFLEXION

Compétences acquises

Techniques:

  • Maîtrise des pointeurs et gestion mémoire
  • Implémentation de structures de données complexes
  • Débogage avec GDB et Valgrind
  • Compilation modulaire et organisation projet
  • Manipulation bit à bit pour le bas niveau

Méthodologiques:

  • Rigueur dans la gestion mémoire
  • Tests systématiques des allocations
  • Documentation et organisation du code
  • Résolution méthodique des bugs

Auto-évaluation

Points forts:

  • Compréhension solide des pointeurs
  • Capacité à créer structures de données dynamiques
  • Bonne pratique de la compilation modulaire
  • Maîtrise des outils (GCC, GDB)

Défis:

  • Complexité initiale des pointeurs de pointeurs
  • Gestion rigoureuse de la mémoire (fuites)
  • Debugging de segmentation faults
  • Compréhension fine des copies de structures

Applications pratiques

Le C est utilisé dans:

  • Systèmes embarqués: microcontrôleurs (Arduino, STM32)
  • Systèmes d'exploitation: Linux kernel, drivers
  • Temps réel: applications critiques
  • Performances: calcul scientifique, traitement signal
  • Réseaux: protocoles, serveurs
  • Bases de données: PostgreSQL, SQLite

Connexions avec autres cours

  • Microcontrôleurs (S6): programmation STM32 en C
  • Systèmes d'exploitation (S6): appels système en C
  • Temps Réel (S8): FreeRTOS programmé en C
  • Réseaux (S6): sockets et protocoles en C
  • Architecture (S5): compréhension assembleur depuis C

Perspectives

Évolution du langage:

  • C11, C17, C23: standards modernes
  • Outils statiques: Clang, sanitizers
  • Intégration IDE: VS Code, CLion

Alternatives modernes:

  • Rust: sécurité mémoire garantie
  • C++: orienté objet avec compatibilité C
  • Zig: modernisation du C

Mais le C reste incontournable pour:

  • Systèmes embarqués contraints
  • Interfaces hardware
  • Performance maximale
  • Legacy code (Linux, UNIX)

Recommandations

  1. Pratiquer régulièrement: coder chaque jour
  2. Lire du code: projets open source (Git, SQLite)
  3. Utiliser Valgrind: systématiquement
  4. Tester rigoureusement: cas limites, gestion erreurs
  5. Documenter: fonctions et algorithmes complexes

Ressources:

  • K&R: "The C Programming Language" (référence)
  • Beej's Guide: tutoriels réseau et sockets
  • Linux kernel source: exemples réels
  • Stack Overflow: résolution problèmes

En conclusion, le C reste le langage fondamental pour comprendre le fonctionnement bas niveau des ordinateurs et programmer efficacement les systèmes embarqués. La rigueur acquise en C est bénéfique pour tous les autres langages.


📚 Documents de Cours

Voici les supports de cours en PDF pour approfondir les différents aspects de la programmation C :

🎯 Les Pointeurs

Cours complet sur les pointeurs, l'arithmétique des pointeurs, et la manipulation de la mémoire en C.

📥 Télécharger le PDF

🏗️ Structures et Types Composés

Définition et utilisation des structures, unions, énumérations et types définis par l'utilisateur.

📥 Télécharger le PDF

💾 Gestion de la Mémoire

Allocation dynamique, gestion du heap, détection de fuites mémoire et bonnes pratiques.

📥 Télécharger le PDF

⚙️ Compilation et Linking

Processus de compilation, préprocesseur, linkage, bibliothèques statiques et dynamiques.

📥 Télécharger le PDF

📁 Entrées/Sorties et Fichiers

Manipulation de fichiers en C, flux standard, fonctions de lecture/écriture et gestion d'erreurs.

📥 Télécharger le PDF

🏃 TP: Gestion de Coureurs

Travail pratique complet sur les listes chaînées avec gestion dynamique de structures de coureurs.

📥 Télécharger le PDF

💻 C Language - S5

Year: 2022-2023 (Semester 5)
Credits: 3 ECTS
Type: Systems Programming


PART A: GENERAL OVERVIEW

Course Objectives

The C Language course provides comprehensive training in systems programming with C, a fundamental language for developing embedded systems, operating systems, and applications requiring optimal performance. The course covers fundamental concepts (pointers, arrays, structures) as well as advanced topics (dynamic memory allocation, bit manipulation, complex data structures).

Target Skills

  • Master C syntax and data types
  • Understand pointers and pointer arithmetic
  • Manage dynamic memory (malloc, free)
  • Manipulate data structures (linked lists, trees)
  • Perform bitwise operations for low-level programming
  • Create modular programs with multiple files
  • Debug and optimize C code

Organization

  • Course hours: 48h (Lectures: 24h, Tutorials/Labs: 24h)
  • Assessment: Written exams (60%) + Labs and projects (40%)
  • Semester: 5 (2022-2023)
  • Prerequisites: Basic algorithms, programming fundamentals

PART B: EXPERIENCE, CONTEXT AND FUNCTION

Course Content

1. C Fundamentals

Data Types and Operators:

C provides fixed-size primitive types:

  • char: 1 byte (8 bits)
  • int: 4 bytes on 32/64-bit systems
  • float: 4 bytes (single precision)
  • double: 8 bytes (double precision)

Modifiers: signed, unsigned, short, long

Declaration examples:

int nombre = 42;
unsigned int positif = 100;
char lettre = 'A';
float pi = 3.14f;

Bitwise Operators:

Essential for low-level manipulation:

  • & (AND), | (OR), ^ (XOR), ~ (NOT)
  • << (left shift), >> (right shift)

TD1 Application: Count the number of 1-bits in an integer:

int bitcount(int n) {
    int count = 0;
    while (n) {
        count += n & 1;  // Test the least significant bit
        n >>= 1;         // Shift one bit to the right
    }
    return count;
}

For 0xF0000F00, result: 8 bits set to 1.

Control Structures:

Standard loops and conditionals:

// Bubble sort (TD1)
for (int j = 0; j < TAILLE-1; j++) {
    for (int i = 0; i < TAILLE-j-1; i++) {
        if (tab[i+1] < tab[i]) {
            int temp = tab[i];
            tab[i] = tab[i+1];
            tab[i+1] = temp;
        }
    }
}

2. Pointers and Memory Management

Pointers:

A fundamental concept in C: a variable that holds a memory address.

Declaration and usage:

int x = 10;
int *ptr = &x;  // ptr points to x
*ptr = 20;      // Modifies x through the pointer

Pointer Arithmetic:

int tab[5] = {1, 2, 3, 4, 5};
int *p = tab;  // Points to tab[0]
p++;           // Points to tab[1]
*p = 100;      // tab[1] = 100

Swap via Pointers (TD2):

int Permute(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
    return 0;
}

Dynamic Allocation:

Essential functions:

  • malloc(size): allocates size bytes
  • calloc(n, size): allocates and initializes to 0
  • free(ptr): frees the memory

TD2 example:

char* chaine = calloc(10, sizeof(char));
int* tab = calloc(10, sizeof(int));

// Usage...

free(chaine);
free(tab);

Risks:

  • Memory leak if free is forgotten
  • Double free (freeing twice)
  • Access after free (use-after-free)
  • Buffer overflow

3. Structures and Composite Types

Structure Definition (TD3):

struct Etudiant {
    char nom[50];
    int naissance;
    int notes[10];
    int nb_notes;
};

Usage:

struct Etudiant cedric;
strcpy(cedric.nom, "Chanfreau");
cedric.naissance = 2000;
cedric.notes[0] = 15;

Pointers to Structures:

struct Etudiant *ptr = &cedric;
ptr->naissance = 2001;  // Equivalent to (*ptr).naissance
Illustration of pointers in C

Figure: Pointer concept - A pointer stores the memory address of a variable

Structure Copying:

Beware of pointers inside structures:

struct S1 {
    int a;
    char* ch;  // Pointer
};

struct S1 v1, v2;
v1.ch = calloc(10, sizeof(char));
strcpy(v1.ch, "Test");

v2 = v1;  // Shallow copy: v2.ch points to the same memory!

Solution: manual deep copy or separate allocation.

4. Dynamic Data Structures

Linked Lists (Main Lab Project):

Element structure:

struct element {
    struct Coureur* coureur;
    struct element* suiv;
};

struct liste {
    struct element* premier;
    struct element* dernier;
    struct element* courant;
};

Initialization:

int init_liste(struct liste* liste) {
    liste->premier = NULL;
    liste->dernier = NULL;
    return 0;
}

Enqueue (Queue Insertion):

int ajout_file(struct liste* der, struct Coureur* coureur) {
    if (der->dernier == NULL) {
        // Empty list
        der->dernier = malloc(sizeof(struct element));
        der->dernier->coureur = coureur;
        der->premier = der->dernier;
        der->dernier->suiv = NULL;
    } else {
        // Append at end
        der->dernier->suiv = malloc(sizeof(struct element));
        der->dernier = der->dernier->suiv;
        der->dernier->coureur = coureur;
        der->dernier->suiv = NULL;
    }
    return 0;
}

List Traversal:

int Aller_Debut(struct liste* liste) {
    liste->courant = liste->premier;
    return 0;
}

int Avancer(struct liste* liste) {
    liste->courant = liste->courant->suiv;
    return 0;
}

int Fin(struct liste liste) {
    return (liste.courant == NULL);
}

Element Counting:

int nbElement(struct liste liste) {
    int count = 0;
    while (!Fin(liste)) {
        Avancer(&liste);
        count++;
    }
    return count;
}

5. Files and Arguments

Command-Line Arguments (TD2):

int main(int argc, char* argv[]) {
    printf("Number of arguments: %d\n", argc);
    if (argc == 3) {
        printf("Program: %s\n", argv[0]);
        printf("Arg1: %s\n", argv[1]);
        printf("Arg2: %s\n", argv[2]);
    }
    return 0;
}

Execution: ./programme arg1 arg2

File Manipulation:

Opening and reading:

FILE* fichier = fopen("data.txt", "r");
if (fichier == NULL) {
    perror("Open error");
    return -1;
}

char buffer[256];
while (fgets(buffer, 256, fichier) != NULL) {
    printf("%s", buffer);
}

fclose(fichier);

Open modes: "r" (read), "w" (write), "a" (append), "rb" (binary)

6. Modular Programming

Lab Project: Modular Structure

File coureur.h:

#ifndef _COUREUR_H
#define _COUREUR_H

struct Coureur {
    char* nom;
    char* prenom;
    int num_dossard;
    char* nom_equipe;
    int temps_etapes;
};

struct Coureur* Creer_Coureur(char nom[], char prenom[],
                               int dossard, char equipe[], int temps);
int Ajouter_Temps(struct Coureur* coureur, int temps_jour);
int Afficher_Coureur(struct Coureur* coureur);

#endif

Include Guards: #ifndef, #define, #endif prevent multiple inclusions.

Modular Compilation:

gcc -Wall -c coureur.c -o coureur.o
gcc -Wall -c liste.c -o liste.o
gcc -Wall -c test_coureur.c -o test_coureur.o
gcc coureur.o liste.o test_coureur.o -o programme

PART C: TECHNICAL ASPECTS

Tutorial Exercises

TD1: Array and Bit Manipulation

Objectives:

  • Bubble sort on an array
  • Multiplication without the * operator
  • Bitwise operations (masking, counting)

TD2: Pointers and Dynamic Allocation

Exercises:

  • Swap function using pointers
  • Dynamic allocation with calloc
  • Command-line arguments

TD3: Structures and Copying

Key issues:

  • Structures with pointers vs arrays
  • Shallow copy vs deep copy
  • Memory management within structures

TD4-TD5: Files and Advanced Structures

Practical data manipulation applications.

Lab Work

Lab: Runner List Management

Complete application with:

  • Coureur (Runner) structure with dynamic string allocation
  • Linked list to manage multiple runners
  • Operations: creation, insertion, traversal, deletion
  • Display and statistics computation

Implemented Features:

  • Runner creation with malloc for strings
  • Queue insertion (FIFO)
  • Traversal with current pointer
  • Element deletion at a given position
  • Element counting
  • Full memory deallocation

Lab Extension

Advanced versions with:

  • List sorting
  • Criteria-based search
  • List merging
  • Memory optimizations

Development Tools

GCC (GNU Compiler Collection):

Basic compilation:

gcc -Wall -o programme source.c

Useful options:

  • -Wall: display all warnings
  • -g: add debug symbols
  • -O2: optimization level 2
  • -std=c99: C99 standard

GDB (GNU Debugger):

gcc -g -o programme source.c
gdb ./programme

GDB commands:

  • break main: set breakpoint
  • run: execute
  • next: next line
  • print var: display variable
  • backtrace: call stack

Valgrind (memory leak detection):

valgrind --leak-check=full ./programme

Detects:

  • Memory leaks (malloc without free)
  • Invalid memory accesses
  • Use of uninitialized memory

Best Practices

Memory Management:

  • Always free what is allocated
  • Check the return value of malloc
  • Set pointers to NULL after free

Safe Code:

char* str = malloc(100);
if (str == NULL) {
    fprintf(stderr, "Allocation error\n");
    return -1;
}

// Usage...

free(str);
str = NULL;  // Prevents double free

Code Organization:

  • .h files for declarations
  • .c files for implementations
  • Systematic include guards
  • Comments for complex functions

PART D: ANALYSIS AND REFLECTION

Acquired Skills

Technical:

  • Mastery of pointers and memory management
  • Implementation of complex data structures
  • Debugging with GDB and Valgrind
  • Modular compilation and project organization
  • Bitwise manipulation for low-level programming

Methodological:

  • Rigor in memory management
  • Systematic testing of allocations
  • Code documentation and organization
  • Methodical bug resolution

Self-Assessment

Strengths:

  • Solid understanding of pointers
  • Ability to create dynamic data structures
  • Good modular compilation practices
  • Proficiency with tools (GCC, GDB)

Challenges:

  • Initial complexity of pointer-to-pointer concepts
  • Rigorous memory management (leaks)
  • Debugging segmentation faults
  • Deep understanding of structure copying

Practical Applications

C is used in:

  • Embedded systems: microcontrollers (Arduino, STM32)
  • Operating systems: Linux kernel, drivers
  • Real-time: safety-critical applications
  • Performance: scientific computing, signal processing
  • Networking: protocols, servers
  • Databases: PostgreSQL, SQLite

Connections with Other Courses

  • Microcontrollers (S6): STM32 programming in C
  • Operating Systems (S6): system calls in C
  • Real-Time Systems (S8): FreeRTOS programmed in C
  • Networking (S6): sockets and protocols in C
  • Architecture (S5): understanding assembly from C

Outlook

Language Evolution:

  • C11, C17, C23: modern standards
  • Static analysis tools: Clang, sanitizers
  • IDE integration: VS Code, CLion

Modern Alternatives:

  • Rust: guaranteed memory safety
  • C++: object-oriented with C compatibility
  • Zig: modernization of C

But C remains essential for:

  • Resource-constrained embedded systems
  • Hardware interfaces
  • Maximum performance
  • Legacy code (Linux, UNIX)

Recommendations

  1. Practice regularly: code every day
  2. Read code: open source projects (Git, SQLite)
  3. Use Valgrind: systematically
  4. Test rigorously: edge cases, error handling
  5. Document: complex functions and algorithms

Resources:

  • K&R: "The C Programming Language" (reference)
  • Beej's Guide: networking and sockets tutorials
  • Linux kernel source: real-world examples
  • Stack Overflow: problem solving

In conclusion, C remains the fundamental language for understanding the low-level workings of computers and for efficiently programming embedded systems. The rigor acquired through C is beneficial for all other programming languages.


📚 Course Documents

Here are the course materials in PDF format to deepen your understanding of the various aspects of C programming:

🎯 Pointers

Complete course on pointers, pointer arithmetic, and memory manipulation in C.

📥 Download PDF

🏗️ Structures and Composite Types

Definition and use of structures, unions, enumerations and user-defined types.

📥 Download PDF

💾 Memory Management

Dynamic allocation, heap management, memory leak detection and best practices.

📥 Download PDF

⚙️ Compilation and Linking

Compilation process, preprocessor, linking, static and dynamic libraries.

📥 Download PDF

📁 Input/Output and Files

File manipulation in C, standard streams, read/write functions and error handling.

📥 Download PDF

🏃 Lab: Runner Management

Complete lab on linked lists with dynamic management of runner structures.

📥 Download PDF