💻 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

Organisation


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:

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:

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:

Exemple TD2:

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

// Utilisation...

free(chaine);
free(tab);

Risques:

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:

TD2: Pointeurs et allocation dynamique

Exercices:

TD3: Structures et copie

Problématiques:

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:

Fonctionnalités implémentées:

TP_bis: Extensions

Versions avancées avec:

Outils de Développement

GCC (GNU Compiler Collection):

Compilation de base:

gcc -Wall -o programme source.c

Options utiles:

GDB (GNU Debugger):

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

Commandes GDB:

Valgrind (détection fuites mémoire):

valgrind --leak-check=full ./programme

Détecte:

Bonnes Pratiques

Gestion mémoire:

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:


PART D: ANALYSE ET RÉFLEXION

Compétences acquises

Techniques:

Méthodologiques:

Auto-évaluation

Points forts:

Défis:

Applications pratiques

Le C est utilisé dans:

Connexions avec autres cours

Perspectives

Évolution du langage:

Alternatives modernes:

Mais le C reste incontournable pour:

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:

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.


Environnement de développement

Outils utilisés:

Organisation mémoire

Layout mémoire:

Processus de compilation

  1. Préprocessing: Traitement des directives #
  2. Compilation: Traduction en assembleur
  3. Assembly: Génération du code machine
  4. Linking: Édition de liens
  5. Exécutable: Fichier final

Structures de données implémentées

Bonnes pratiques enseignées

Concepts de programmation système


PART D: COMPÉTENCES ACQUISES, AUTO-ÉVALUATION, AVIS

Compétences développées

Compétences techniques:

Compétences transversales:

Auto-évaluation

Points forts:

Défis rencontrés:

Apports pour le parcours

Ce cours a été fondamental pour:

Applications pratiques

Les compétences acquises sont directement utilisées dans:

Projets marquants

Gestion de structures de données:

Manipulation de fichiers:

Programmation système:

Ressources et documentation

Évolution des compétences

Recommandation: Le langage C est fondamental en ingénierie électronique et informatique embarquée. Ce cours établit des bases solides pour tous les cours de systèmes embarqués, microcontrôleurs et systèmes d’exploitation à venir. La pratique régulière et la lecture de code source sont essentielles pour consolider ces compétences.


📚 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


← Back to My Courses 2022-2023