EXAMEN LANGAGE C ( PROGRAMMATION C ) TEST  07 /XX 2023

EXAMEN + CORRIGE EN LANGAGE C

Examinateur : Mr Joël Yk

Exercice 01 : Les Chaines de Caractères et Tableaux (5pts)

  1. Comment déclare-t-on et initialise-t-on une chaîne de caractères en C ? Illustrez par un exemple.
  2. Comment concatène-t-on une chaîne de caractères et un caractère en C ? Illustrez par un exemple.
  3. Comment déclare-t-on et initialise-t-on un tableau à deux dimensions en C ? Illustrez par un exemple.

Exercice 02 : Programme en C (3pts)

écrire un programme c qui calcule le plus grand commun diviseur (PGCD) entre deux nombres a et b en utilisant l'algorithme d'Euclide

Problème :  12pts

Dans la ville de Dschang une startup nommée Genius souhaite réaliser programme qui doit permettre de gérer la base de données des élèves du lycée Bilingue de Dschang. Les informations à stocker pour chaque élève sont :

  • son nom (une chaîne de caractères de 30 caractères)
  • son prénom (une chaîne de caractères de 30 caractères)
  • son âge (un entier)
  • sa classe (une chaîne de caractères de 10 caractères)

Le programme doit offrir les fonctionnalités suivantes :

1) Écrire une fonction saisir_eleve qui permet de saisir les informations d'un élève (nom, prénom, âge, classe) à partir du clavier et de les enregistrer dans une structure Eleve.

Prototype de la fonction :

void saisir_eleve(Eleve *e);

2)

Écrire une fonction ajouter_eleve qui prend en paramètre un tableau d'élèves tab, ainsi que sa taille n, et qui ajoute un nouvel élève à la fin de ce tableau. La fonction devra également gérer l'agrandissement du tableau si nécessaire (par exemple en utilisant la fonction realloc).

Prototype de la fonction :

void ajouter_eleve(Eleve **tab, int *n);

3)

Écrire une fonction supprimer_eleve qui permet de supprimer un élève du tableau tab en fonction de son nom et de son prénom. La fonction doit retourner un code d'erreur si l'élève n'a pas été trouvé dans le tableau.

Prototype de la fonction :

int supprimer_eleve(Eleve *tab, int n, char *nom, char *prenom);

4)

Écrire une fonction tri_insertion qui trie le tableau d'élèves tab selon le nom et le prénom des élèves, en utilisant l'algorithme de tri par insertion.

Prototype de la fonction :

void tri_selection(Eleve *tab, int n);

5)

Écrire une procédure afficher_classe qui affiche à l'écran tous les élèves d'une classe donnée (passée en paramètre).

Prototype de la procédure :

void afficher_classe(Eleve *tab, int n, char *classe);

6)

Écrire une fonction sauvegarder_eleves qui prend en paramètre un tableau d'élèves tab et sa taille n, et qui sauvegarde les informations de tous les élèves dans un fichier texte. Chaque élève doit être sauvegardé sur une ligne séparée, avec les informations séparées par des points-virgules.

Prototype de la fonction :

void sauvegarder_eleves(Eleve *tab, int n, char *nom_fichier);

 

Correction :

Exercice 01 :

  1. Pour déclarer et initialiser une chaîne de caractères en C, il faut utiliser une chaîne de caractères entre guillemets et affecter le résultat à un pointeur de type char. Par exemple :

    char *chaine = "Bonjour";

  2. Pour concaténer une chaîne de caractères et un caractère en C, on peut utiliser la fonction strncat de la bibliothèque string.h. Cette fonction permet de concaténer un nombre donné de caractères à la fin d'une chaîne de caractères.

    Voici un exemple d'utilisation de la fonction strncat pour concaténer un caractère à une chaîne de caractères :

    #include <string.h>
    #include <stdio.h>

    int main(void) {
        char chaine[10] = "Bonjour";
        strncat(chaine, "!", 1);
        printf("Chaîne concaténée : %s\n", chaine); // Affiche "Bonjour!"
        return 0;
    }

  3.  

    Pour déclarer un tableau à deux dimensions en C, il faut préciser le type de données des éléments du tableau, ainsi que les dimensions du tableau. Par exemple, pour déclarer un tableau à deux dimensions de 3 lignes et 4 colonnes de nombres entiers, on peut utiliser la syntaxe suivante :

     

    int tab[3][4];

    Pour initialiser le tableau, on peut utiliser la syntaxe suivante :

    int tab[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };

    Il est également possible de ne pas préciser toutes les valeurs du tableau et de laisser le compilateur initialiser les valeurs restantes avec 0 :

    int tab[3][4] = { {1, 2}, {5, 6, 7} };

    Le tableau tab sera alors initialisé comme suit :

    1 2 0 0
    5 6 7 0
    0 0 0 0

Exercice 02 :

#include <stdio.h>

int main(void) {
    int a, b;
    printf("Entrez deux nombres : ");
    scanf("%d %d", &a, &b);

    printf("Calcul du PGCD de %d et %d :\n", a, b);

    // Algorithme d'Euclide
    while (b != 0) {
        int r = a % b;
        printf("%d = %d * %d + %d\n", a, a / b, b, r);
        a = b;
        b = r;
    }

    printf("Le PGCD de %d et %d est %d.\n", a, b, a);

    return 0;
}

L'algorithme d'Euclide consiste à diviser récursivement les deux nombres en entrée par leur reste de la division entière jusqu'à ce que le reste soit égal à 0. Le dernier diviseur non nul est alors le PGCD des deux nombres.

Par exemple, pour calculer le PGCD de 1071 et 462 :

1071 = 2 * 462 + 147
462 = 3 * 147 + 13
147 = 11 * 13 + 4
13 = 3 * 4 + 1
4 = 4 * 1 + 0

 

Probleme :

1)

#include <stdio.h>
#include <string.h>

typedef struct {
    char nom[30];
    char prenom[30];
    int age;
    char classe[10];
} Eleve;

void saisir_eleve(Eleve *e) {
    printf("Entrez le nom de l'élève : ");
    scanf("%s", e->nom);
    printf("Entrez le prénom de l'élève : ");
    scanf("%s", e->prenom);
    printf("Entrez l'âge de l'élève : ");
    scanf("%d", &e->age);
    printf("Entrez la classe de l'élève : ");
    scanf("%s", e->classe);
}

Il est important de noter que cette fonction ne gère pas les erreurs de saisie (par exemple si l'utilisateur entre un âge qui n'est pas un entier). Il pourrait être intéressant de rajouter des vérifications pour éviter les erreurs de saisie.

2)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char nom[30];
    char prenom[30];
    int age;
    char classe[10];
} Eleve;

void ajouter_eleve(Eleve **tab, int *n) {
    Eleve e;
    printf("Entrez les informations de l'élève à ajouter :\n");
    saisir_eleve(&e); // On utilise la fonction précédemment écrite pour saisir les informations de l'élève

    // On vérifie si le tableau est plein
    if (*n % 10 == 0) {
        // Si le tableau est plein, on le réalloue en lui ajoutant 10 éléments supplémentaires
        *tab = realloc(*tab, (*n + 10) * sizeof(Eleve));
    }

    // On ajoute l'élève à la fin du tableau
    (*tab)[*n] = e;
    (*n)++;
}

 

3)

#include <stdio.h>
#include <string.h>

typedef struct {
    char nom[30];
    char prenom[30];
    int age;
    char classe[10];
} Eleve;

int supprimer_eleve(Eleve *tab, int n, char *nom, char *prenom) {
    // On parcourt le tableau à la recherche de l'élève à supprimer
    for (int i = 0; i < n; i++) {
        if (strcmp(tab[i].nom, nom) == 0 && strcmp(tab[i].prenom, prenom) == 0) {
            // Si on a trouvé l'élève, on décale tous les élèves qui suivent d'une position vers la gauche
            for (int j = i; j < n - 1; j++) {
                tab[j] = tab[j+1];
            }
            // On décrémente la taille du tableau
            n--;
            return 0; // On retourne 0 pour indiquer que l'élève a été trouvé et supprimé
        }
    }

    // Si on arrive ici, c'est que l'élève n'a pas été trouvé
    return 1; // On retourne 1 pour indiquer que l'élève n'a pas été trouvé
}

4)

#include <stdio.h>
#include <string.h>

typedef struct {
    char nom[30];
    char prenom[30];
    int age;
    char classe[10];
} Eleve;

void tri_selection(Eleve *tab, int n) {
    // On parcourt le tableau de la première à l'avant-dernière position
    for (int i = 0; i < n - 1; i++) {
        // On cherche l'élève le plus petit entre i et la fin du tableau
        int min = i;
        for (int j = i + 1; j < n; j++) {
            if (strcmp(tab[j].nom, tab[min].nom) < 0 ||
                (strcmp(tab[j].nom, tab[min].nom) == 0 &&
                 strcmp(tab[j].prenom, tab[min].prenom) < 0)) {
                min = j;
            }
        }
        // On échange les éléments un à un
        char tmp_nom[30];
        strcpy(tmp_nom, tab[i].nom);
        strcpy(tab[i].nom, tab[min].nom);
        strcpy(tab[min].nom, tmp_nom);

        char tmp_prenom[30];
        strcpy(tmp_prenom, tab[i].prenom);
        strcpy(tab[i].prenom, tab[min].prenom);
        strcpy(tab[min].prenom, tmp_prenom);

        int tmp_age = tab[i].age;
        tab[i].age = tab[min].age;
        tab[min].age = tmp_age;

        char tmp_classe[10];
        strcpy(tmp_classe, tab[i].classe);
        strcpy(tab[i].classe, tab[min].classe);
        strcpy(tab[min].classe, tmp_classe);
    }
}

Cette fonction utilise l'algorithme de tri par sélection pour trier le tableau tab selon le nom et le prénom des élèves. Le tri est effectué en place, c'est-à-dire que les éléments du tableau sont échangés entre eux sans être copiés dans un autre tableau.

Il est important de noter que cette fonction ne vérifie pas si le tableau est déjà trié avant de lancer l'algorithme. Il serait intéressant de vérifier cela pour éviter de trier inutilement le tableau.

5)

#include <stdio.h>
#include <string.h>

typedef struct {
    char nom[30];
    char prenom[30];
    int age;
    char classe[10];
} Eleve;

void afficher_classe(Eleve *tab, int n, char *classe) {
    // On parcourt le tableau d'élèves
    for (int i = 0; i < n; i++) {
        // Si l'élève appartient à la classe donnée, on l'affiche à l'écran
        if (strcmp(tab[i].classe, classe) == 0) {
            printf("%s %s (%d ans)\n", tab[i].prenom, tab[i].nom, tab[i].age);
        }
    }
}

Cette procédure parcourt le tableau d'élèves et affiche à l'écran les élèves qui appartiennent à la classe passée en paramètre. Elle utilise la fonction strcmp pour comparer les noms de classe des élèves avec la classe donnée. Si les noms sont identiques, l'élève appartient à la classe et il est affiché à l'écran.

Voici un exemple d'utilisation de la fonction afficher_classe sur un tableau d'élèves contenant quatre éléments :

#include <stdio.h>
#include <string.h>

typedef struct {
    char nom[30];
    char prenom[30];
    int age;
    char classe[10];
} Eleve;

int main(void) {
    // On déclare et initialise le tableau d'élèves
    Eleve tab[] = {
        {"Yankam", "Joel", 17, "2nde"},
        {"Joel", "Yk", 16, "1re"},
        {"Panda", "Codeur", 18, "1re"},
        {"Alice", "Bob", 16, "2nde"}
    };
    int n = 4;

    // On affiche les élèves de la classe 1re
    afficher_classe(tab, n, "1re");

    return 0;
}

Ce programme affiche à l'écran les élèves suivants :

Yk Joel (16 ans)
Codeur Panda (18 ans)

Il est important de noter que la fonction afficher_classe ne modifie pas le contenu du tableau tab, elle ne fait que l'afficher à l'écran. Si vous souhaitez trier le tableau avant de l'afficher, vous pouvez utiliser la fonction tri_selection ou tri_insertion que j'ai précédemment proposées.

6)

#include <stdio.h>
#include <string.h>

typedef struct {
    char nom[30];
    char prenom[30];
    int age;
    char classe[10];
} Eleve;

void sauvegarder_eleves(Eleve *tab, int n, char *nom_fichier) {
    // On ouvre le fichier en mode "écriture"
    FILE *fichier = fopen(nom_fichier, "w");
    if (fichier == NULL) {
        // Si le fichier n'a pas pu être ouvert, on affiche un message d'erreur et on quitte la fonction
        fprintf(stderr, "Erreur lors de l'ouverture du fichier %s\n", nom_fichier);
        return;
    }

    // On parcourt le tableau d'élèves
    for (int i = 0; i < n; i++) {
        // On écrit les informations de l'élève dans le fichier, séparées par des points-virgules
        fprintf(fichier, "%s;%s;%d;%s\n", tab[i].nom, tab[i].prenom, tab[i].age, tab[i].classe);
    }

    // On ferme le fichier
    fclose(fichier);
}

    // On ferme le fichier
    fclose(fichier);
}

La fonction fclose permet de fermer un fichier qui a été précédemment ouvert avec la fonction fopen. Cette étape est importante car elle permet de libérer les ressources utilisées par le fichier et de permettre à d'autres processus d'accéder au fichier si nécessaire.

Il est recommandé de fermer un fichier dès que vous avez fini de l'utiliser, afin d'éviter des fuites de mémoire ou des conflits d'accès au fichier.

Aucune note. Soyez le premier à attribuer une note !

Ajouter un commentaire

Anti-spam