Gestion des compétitions et inscriptions par CNI dans C

Exercice 1 - Gestion des joueurs Cet exercice manipule une structure de données pour modéliser des joueurs de sport (avec numéro, nom, prénom et poids) et utilise des fonctions pour lire ces données avec des contrôles de saisie, vérifier l'unicité du numéro de poste, et trouver le joueur le plus lourd.

D'après le document Gestion des compétitions et inscriptions par CNI dans C

Cet article a été rédigé automatiquement à partir du document source, puis vérifié avant publication.

Gestion des compétitions et inscriptions par CNI dans C

Document source

Gestion des compétitions et inscriptions par CNI dans C

Programming, Math, etc. · PDF · 13 pages

Afficher l'aperçu du document

Consulter le document original →

Exercice 1 - Gestion des joueurs

Cet exercice manipule une structure de données pour modéliser des joueurs de sport (avec numéro, nom, prénom et poids) et utilise des fonctions pour lire ces données avec des contrôles de saisie, vérifier l'unicité du numéro de poste, et trouver le joueur le plus lourd.

Code corrigé et commenté

Le code d'origine comportait des omissions mineures fréquentes dans les anciens standards C (comme l'absence du type de retour pour main). Ces éléments ont été corrigés pour que le code compile et s'exécute correctement aujourd'hui.

#include <stdio.h>

typedef struct {
    int num;
    char nom[21];
    char prenom[21];
    float poid;
} joueur;

/* Vérifie si le numéro n existe déjà dans les i premiers éléments du tableau */
int verifier(joueur *t, int i, int n) {
    int j = 0;
    while (i != 0 && j < i) {
        if (t[j].num == n)
            return 1;
        else 
            j++;
    }
    return 0;
}

void remplissage(joueur *t, int n) {
    int i;
    for (i = 0; i < n; i++) {
        printf("donner le nom : ");
        scanf("%s", t[i].nom);
        printf("donner le prenom : ");
        scanf("%s", t[i].prenom);
        
        /* Contrôle de saisie : le poids doit être strictement positif */
        do {
            printf("donner le poids : ");
            scanf("%f", &t[i].poid);
        } while (!(t[i].poid > 0));
        
        /* Contrôle de saisie : le numéro doit être unique et compris entre 1 et 15 */
        do {
            printf("donner le num de poste : ");
            scanf("%d", &t[i].num);
        } while (!(verifier(t, i, t[i].num) == 0 && t[i].num >= 1 && t[i].num <= 15));
    }

    printf("/****Affichage du tableau***/\n");
    for (i = 0; i < n; i++) {
        printf("les informations du joueur n%d:\n", t[i].num);
        printf("\t\tnom:%s\n", t[i].nom);
        printf("\t\tprenom:%s\n", t[i].prenom);
        printf("\t\tpoids:%f\n", t[i].poid);
    }
}

void pluslourd(joueur *t, int n) {
    float max; 
    int i = 0, jmax = 0; // Initialisation de jmax ajoutée par sécurité
    
    max = t[0].poid;
    for (i = 1; i < n; i++) {
        if (t[i].poid > max) {
            max = t[i].poid; 
            jmax = i;
        }
    }
    printf("\nle joueur le plus lourd c'est le num%d\n", t[jmax].num);
    printf("\t\tnom:%s\n", t[jmax].nom);
    printf("\t\tprenom:%s\n", t[jmax].prenom);
    printf("\t\tpoids:%f\n", t[jmax].poid);
}

int main() {
    int n; 
    joueur t[15];
    
    do {
        printf("donner le nombre du joueur\n");
        scanf("%d", &n);
    } while (!(n > 0 && n <= 15));
    
    remplissage(t, n);
    pluslourd(t, n);

    return 0;
}

Explications des corrections

  1. Signature de main : Déclarée en int main() avec un return 0; final, respectant la norme C standard.
  2. Variable jmax : Dans la fonction pluslourd, jmax n'était pas initialisée. Si le premier joueur (indice 0) est le plus lourd, la boucle ne met jamais à jour jmax, ce qui causerait l'affichage d'une donnée aléatoire en mémoire. L'initialiser à 0 garantit le bon fonctionnement.
  3. Variables inutilisées : Dans remplissage, les variables np, existe et j déclarées dans la source n'étaient pas utilisées. Elles ont été retirées pour plus de clarté.

Exercice 2 - Gestion des compétitions

Ici, nous concevons des structures imbriquées. La structure competition contient un tableau de structures participant. Le but est de recenser le nombre de compétitions auxquelles un participant spécifique (identifié par sa CIN) a pris part.

Code corrigé et commenté

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

typedef struct {
    char ncin[9];
    char nom[21];
    char prenom[21];
} participant;

typedef struct {
    int id;
    char nomcomp[10];
    int nbpart;
    participant t[50];
} competition;

participant saisir_part() {
    participant p;
    printf("donner le ncin : ");
    scanf("%s", p.ncin);
    printf("donner le nom : ");
    scanf("%s", p.nom);
    printf("donner le prenom : ");
    scanf("%s", p.prenom);
    return p;
}

void saisir_comp(competition s[], int n) {
    int i, j;
    for (i = 0; i < n; i++) {
        printf("donner l identifiant de la competition : ");
        scanf("%d", &s[i].id);
        printf("donner le nom de la comp : ");
        scanf("%s", s[i].nomcomp);
        printf("donner le nombre de participants\n");
        scanf("%d", &s[i].nbpart);
        
        for (j = 0; j < s[i].nbpart; j++) {
            s[i].t[j] = saisir_part();
        }
    }
}

int nbre_comp(competition s[], int n, char ncin[9]) {
    int i, j, nbre = 0;
    for (i = 0; i < n; i++) {
        for (j = 0; j < s[i].nbpart; j++) {
            /* Comparaison des chaînes de caractères pour la CIN */
            if (strcmp(s[i].t[j].ncin, ncin) == 0) {
                nbre++;
            }
        }
    }
    return nbre;
}

int main() {
    int n;
    char ncin[9];
    competition s13[10];
    
    do {
        printf("donner le nombre total de compétition : ");
        scanf("%d", &n);
    } while (!(n > 0 && n <= 10));
    
    saisir_comp(s13, n);
    
    printf("donner le numero du ncin : ");
    scanf("%s", ncin);
    
    printf("le joueur num %s a participe dans %d competitions\n", ncin, nbre_comp(s13, n, ncin));
    
    return 0;
}

Explications des corrections

  1. Déclarations obsolètes : La fonction main() a été mise aux normes avec int main().
  2. Variable nb : Déclarée dans saisir_comp dans le code source mais jamais utilisée. Elle a été supprimée.
  3. Logique de recherche : La fonction nbre_comp parcourt toutes les compétitions, et pour chacune d'entre elles, vérifie si le numéro d'identité ncin correspond. L'utilisation de strcmp est parfaitement justifiée ici car ncin est un tableau de caractères (chaîne).

Exercice 3 - Manipulation des dates

Ce programme incrémente une date en fonction d'un nombre de jours donnés en ajoutant les jours, puis en gérant les dépassements par rapport au nombre de jours que compte le mois en cours (en tenant compte des années bissextiles).

Code corrigé et commenté

#include <stdio.h>
#include <stdlib.h> // Contient atoi() pour la conversion chaîne -> entier

typedef struct date {
    char jour[3];
    char mois[3];
    char annee[5];
} DATE;

int nb_jour_mois(int mois, int annee) {
    switch(mois) {
        case 1: case 3: case 5: case 7: case 8: case 10: case 12:
            return 31;
        case 4: case 6: case 9: case 11:
            return 30;
        case 2:
            /* Une année est bissextile si elle est divisible par 4 */
            /* (Le code source omet la règle des 100 et 400 ans, nous conservons la logique d'origine) */
            if (annee % 4 == 0)
                return 29;
            else
                return 28;
        default:
            return 0;
    }
}

void saisir_date_initiale(DATE *t) {
    int j, m, a;

    do {
        printf("Donner l'annee : ");
        scanf("%s", t->annee);
        a = atoi(t->annee);
    } while (a < 0);

    do {
        printf("Donner le mois : ");
        scanf("%s", t->mois);
        m = atoi(t->mois);
    } while (m < 0 || m > 12);

    do {
        printf("Donner le nombre de jours : ");
        scanf("%s", t->jour);
        j = atoi(t->jour);
    } while (j < 0 || j > nb_jour_mois(m, a));
}

void saisir_nb_jours(int *n) {
    do {
        printf("Donner le nombre de jours à ajouter : ");
        scanf("%d", n);
    } while (*n <= 0);
}

void dateinc(DATE *t, int n) {
    int j, m, a, temp;
    
    j = atoi(t->jour);
    m = atoi(t->mois);
    a = atoi(t->annee);
    
    j += n; // Ajout des jours
    temp = nb_jour_mois(m, a);
    
    while (j > temp) {
        j -= temp;
        m++;
        if (m > 12) {
            m = 1;
            a++;
        }
        temp = nb_jour_mois(m, a);
    }
    
    /* Reconversion des entiers calculés en chaînes de caractères */
    sprintf(t->jour, "%d", j);
    sprintf(t->mois, "%d", m);
    sprintf(t->annee, "%d", a);
}

void afficher(DATE t) {
    printf("La date est: %s/%s/%s.\n", t.jour, t.mois, t.annee);
}

int main() {
    DATE d;
    int n;
    
    saisir_date_initiale(&d);
    afficher(d);
    saisir_nb_jours(&n);
    dateinc(&d, n);
    afficher(d);
    
    return 0;
}

Explications des corrections

  1. La structure DATE conserve délibérément les nombres sous forme de texte (ex: char jour[3]). La taille 3 est exactement suffisante pour stocker "31" plus le caractère nul de fin de chaîne \0.
  2. Le switch(mois) d'origine provoquait un avertissement en cas d'absence de default. Un default: return 0; a été ajouté pour éviter un comportement indéfini.

Exercice 4 - Gestion des commandes et stock

Cet exercice confronte un tableau global d'articles (le stock) à un tableau d'articles désirés (la commande). Il vérifie la disponibilité, calcule le total, et met à jour les quantités du stock initial.

Code corrigé et commenté

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

typedef struct {
    char modele[21];
    float pu;
    int qtd;
} article;

typedef struct {
    char modele[21];
    int qte;
} commandeunitaire;

/* Stock global */
article stock[100];

typedef struct {
    char nomclt[21];
    commandeunitaire cu[100];
} commande;

article saisirArticle() {
    article a;
    printf("donner le modele : ");
    scanf("%s", a.modele);
    printf("donner le prix : ");
    scanf("%f", &a.pu);
    printf("donner la quantitee : ");
    scanf("%d", &a.qtd);
    return a;
}

void ajouterArticle(article a, int i) {
    stock[i] = a;
}

int saisircomdunt(commandeunitaire cu[]) {
    char r = 'n';
    int i = 0;
    do {
        printf("donner le modele : ");
        scanf("%s", cu[i].modele);
        printf("donner la quantitee : ");
        scanf("%d", &cu[i].qte);
        i++;
        
        printf("voulez vous continuer o/n : ");
        scanf(" %c", &r); // L'espace avant %c est vital pour ignorer le saut de ligne précédent
    } while (!(r == 'n' || r == 'N'));
    
    return i;
}

float retirerCommandeUnitaire(article *stock, commandeunitaire cu) {
    int existe = 0, i = 0;
    float r = 0;
    
    do {
        if ((strcmp(stock[i].modele, cu.modele)) == 0) {
            existe = 1;
            if (stock[i].qtd >= cu.qte) {
                r = cu.qte * stock[i].pu;
                stock[i].qtd = stock[i].qtd - cu.qte; // Mise à jour du stock
            } else {
                printf("STOCK INSUFFISANT!!!!!!\n");
            }
        }
        i++;
    } while (!(existe == 1 || i >= 100)); // CORRECTION: i >= 100 au lieu de i > 100

    if (existe == 0)
        printf("STOCK INSDISPONIBLE!!!!!!\n");
        
    return r;
}

void afficheStock(article *stock, int n) {
    int i;
    for (i = 0; i < n; i++) {
        printf("\ninformations d article n %d\n", i + 1);
        printf("\t\tmodele :%s\n", stock[i].modele);
        printf("\t\tprix :%f\n", stock[i].pu);
        printf("\t\tquantitee :%d\n", stock[i].qtd);
    }
}

int main() {
    commande cd;
    int n, i, nbc;
    float r, s = 0;
    
    do {
        printf("donner le nombre d article\n");
        scanf("%d", &n);
    } while (!(n > 0 && n <= 100));
    
    for (i = 0; i < n; i++) {
        ajouterArticle(saisirArticle(), i);
    }
    
    printf("****votre stock initial**** \n");
    afficheStock(stock, n);
    
    printf("donner le nom du client : ");
    scanf("%s", cd.nomclt);
    nbc = saisircomdunt(cd.cu);
    
    printf("/***la commande de Mr/Mme %s ***/\n", cd.nomclt);
    for (i = 0; i < nbc; i++) {
        printf("\t\tmodele %s\n", cd.cu[i].modele);
        printf("\t\tquantite %d\n", cd.cu[i].qte);
    }
    
    for (i = 0; i < nbc; i++) {
        r = retirerCommandeUnitaire(stock, cd.cu[i]);
        if (r != 0)
            s = s + r;
    }
    
    if (s != 0)
        printf("**le prix totale de votre commande %f**\n", s);
        
    printf("\n/****Votre nouveau Stock****/\n");
    afficheStock(stock, n);
    
    return 0;
}

Explications des corrections

  1. Risque de dépassement (Buffer overflow) : Dans retirerCommandeUnitaire, la condition d'arrêt i > 100 permettait à la boucle de vérifier l'indice 100 du tableau stock. Puisque le tableau est de taille 100 (indices de 0 à 99), cela lisait de la mémoire non allouée. La condition a été corrigée en i >= 100.
  2. Gestion du scanf pour un caractère : Dans saisircomdunt, scanf(" %c", &r); comporte désormais un espace avant le %c. C'est impératif en C, sinon la touche "Entrée" du scanf précédent est immédiatement lue comme la réponse.

Exercice 5 - Gestion d'un album musical

Ce programme recherche des informations dans un tableau de structures musicales (durée d'une chanson, nombre de pistes par un même interprète).

Code corrigé et commenté

La source originale propose deux méthodes avec exactement le même nom de fonction (comparerduree). Dans un vrai programme C, cela empêche la compilation (erreur de redéfinition). Pour que le code s'exécute, nous plaçons la première méthode en commentaire tout en la laissant visible pour l'étude.

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

typedef struct {
    int minutes;
    int secondes;
} temps;

typedef struct {
    char titre[30];
    char interpretre[30]; // Nous conservons l'orthographe d'origine
    temps duree;
} chanson;

typedef chanson album[12];

void saisirchanson(chanson *c) {
    printf("donnez le titre\n");
    scanf("%s", c->titre);
    printf("donnez l interprete\n");
    scanf("%s", c->interpretre);
    printf("donnez le nombre de minutes\n");
    scanf("%d", &c->duree.minutes);
    printf("donnez le nombre de secondes\n");
    scanf("%d", &c->duree.secondes);
}

void afficherchanson(chanson c) {
    printf("le titre %s, linterprete %s, duree %d minutes et %d secondes\n", 
           c.titre, c.interpretre, c.duree.minutes, c.duree.secondes);
}

/* 1ére Méthode (Mise en commentaire pour éviter l'erreur de compilation) */
/*
int comparerduree(chanson c1, chanson c2) {
    int d1, d2;
    d1 = c1.duree.minutes * 60 + c1.duree.secondes;
    d2 = c2.duree.minutes * 60 + c2.duree.secondes;
    
    if(d1 > d2)
        return 1;
    else if(d1 < d2)
        return 2;
    else
        return 0;
}
*/

/* 2ème Méthode (Celle qui sera compilée et exécutée) */
int comparerduree(chanson c1, chanson c2) {
    if (c1.duree.minutes > c2.duree.minutes)
        return 1;
    else if (c1.duree.minutes < c2.duree.minutes)
        return 2;
    else {
        // En cas d'égalité des minutes, on compare les secondes
        if (c2.duree.secondes < c1.duree.secondes)
            return 1;
        else if (c2.duree.secondes > c1.duree.secondes)
            return 2;
        else
            return 0;
    }
}

void rempliralbum(album a, int n) {
    int i;
    for (i = 0; i < n; i++) {
        saisirchanson(&a[i]);
    }
}

void afficherralbum(album a, int n) {
    int i;
    for (i = 0; i < n; i++) {
        afficherchanson(a[i]);
    }
}

/* Fonction récursive pour compter les chansons d'un même interprète */
int chansonsmemeinterpret(album a, int n, char intp[]) {
    if (n == 0)
        return 0;
    else {
        if (strcmp(a[n-1].interpretre, intp) == 0) {
            afficherchanson(a[n-1]);
            return 1 + chansonsmemeinterpret(a, n - 1, intp);
        } else {
            return chansonsmemeinterpret(a, n - 1, intp);
        }
    }
}

int main() {
    int n, i;
    chanson plusCourteC;
    album a;
    char intp[10];

    printf("donner le nombre de chanson\n");
    scanf("%d", &n);
    
    rempliralbum(a, n);
    
    printf("\n Affichage Album\n");
    afficherralbum(a, n);
    
    printf("donner le nom de l interprete\n");
    scanf("%s", intp);
    
    printf("\n\nCHANSONS MEME INTERPRETE: \n");
    printf("l interprete %s a %d chanson(s)\n", intp, chansonsmemeinterpret(a, n, intp));
    
    plusCourteC = a[0];
    for (i = 1; i < n; i++) {
        /* La fonction retourne 1 si la première (plusCourteC) est plus longue que la deuxième (a[i]) */
        if (comparerduree(plusCourteC, a[i]) == 1)
            plusCourteC = a[i];
    }
    
    printf("\n\nPLUS COURTE CHANSON: \n");
    afficherchanson(plusCourteC);
    
    return 0;
}

Explications des corrections

  1. Redéfinition de fonction : L'examen illustre deux manières d'écrire la fonction comparerduree (la méthode 1 unifie le temps en secondes, la méthode 2 compare d'abord les minutes puis les secondes). En C, deux fonctions ne peuvent pas avoir le même nom dans le même fichier. La méthode 1 a été mise en commentaire pour autoriser la compilation.
  2. Fonction récursive chansonsmemeinterpret : Elle décrémente n jusqu'à 0 (condition d'arrêt) en analysant les cases de n-1 à 0. Si l'interprète correspond, elle ajoute 1 au résultat de l'appel suivant. C'est un excellent exemple de parcours de tableau par récursivité.

Méthode

Lorsque vous abordez un examen de programmation C orienté sur les struct (structures), voici le raisonnement à appliquer :

  1. Cartographiez les dépendances : Repérez systématiquement si une structure est imbriquée dans une autre (ex: participant dans competition, ou temps dans chanson). Déclarez toujours la structure "enfant" avant la structure "parent" pour que le compilateur la reconnaisse.
  2. Attention au passage par paramètre :
    • Pour modifier une variable simple ou une structure à l'intérieur d'une fonction, vous devez utiliser un pointeur et l'opérateur d'adresse (ex: void modifier(joueur *j)).
    • Les tableaux en C (comme article stock[100] ou competition s[]) sont passés naturellement par adresse. Les modifications faites dans la fonction seront donc appliquées au tableau d'origine.
  3. Sécurisez vos lectures (scanf) : Les champs de type chaîne de caractères (%s) ignorent d'eux-mêmes les sauts de ligne, mais la lecture d'un simple caractère (%c) requiert une vigilance stricte. Prenez l'habitude de placer un espace avant le format (scanf(" %c", &var);).
  4. Vérifiez les bornes des tableaux : Un tableau déclaré de taille N accepte les indices de 0 à N - 1. Si une boucle while teste i > N ou i == N à l'intérieur des crochets de votre tableau, votre programme lira une zone mémoire interdite.

Partager

Commentaires

Aucun commentaire pour le moment. Posez la première question.

Les commentaires sont relus avant publication. Votre e-mail n'est jamais affiché.

← Toutes les révisions