Correction du CC d'INFO404_INFO de mai 2018

par Tom
le 20/12/2019
  1. Expliquer comment faire pour avoir un paramètre en entrée/sortie d’une fonction en C.

Il faut que le paramètre soit de type pointeur :

// multiplie par 2 le nombre passé en paramètre
int fonction(int* paramES)
{
    *paramES = 2 * *paramES;
}

  1. Expliquer la différence d’usage entre ces deux types de déclaration : char * machaine et char machaine[20]
  • char * machaine déclare une variable appelée machaine de type char* (pointeur vers caractère)
  • char machaine[20] déclare un tableau de char appelé machaine ayant une taille de 20

  1. Expliquer pourquoi ces lignes lignes de code vont provoquer une erreur à la compilation :
// struct doit être en minuscule
Struct personne {
 char nom[10];
 char prenom[20];
} // manque le point-virgule
int main()
{
 personne p; // manque le "struct" devant le nom du type
 strcpy(p.nom,"dupond");
 strcpy(p.prenom,"paul");
 printf("%s %s", p.nom, p.prenom);
}

Le code correct est :

struct personne {
 char nom[10];
 char prenom[20];
};
int main()
{
 struct personne p;
 strcpy(p.nom,"dupond");
 strcpy(p.prenom,"paul");
 printf("%s %s", p.nom, p.prenom);
}

Si on veut être pédant, on pourrait dire qu'il manque le return 0; dans main() mais ce n'est pas une erreur mais seulement un warning.


  1. Expliquer en quelques lignes, l’intérêt de la compilation séparée

Cela permet de modifier le code et l'implémentation des fonctions sans que ceux qui utilisent notre code (par le biais des headers) n'aient à changer quoi que ce soit.


  1. Les nombres de Pell (Pn) et de Pell-Lucas (Qn) sont définis par la récurrence linéaire suivante : [...] Écrire une seule fonction permettant de calculer l’une ou l’autre des suites et retournant la valeur au rang n dont le protype est définit comme suit :
    typedef enum {pell,pelllucas} typeSuite;
    long suitePell(int rang, typeSuite suite)

Correction :

typedef enum {pell,pelllucas} typeSuite;
long suitePell(int rang, typeSuite suite)
{
    if (suite == pell)
    {
        if (rang == 0) return 0;
        if (rang == 1) return 1;
    }
    else if (suite == pelllucas)
    {
        if (rang <= 1) return 2;
    }

    return 2 * suitePell(rang - 1, suite) + suitePell(rang - 2, suite);
}

  1. Écrire une fonction qui permette de trouver le nombre max d’occurrence > 1 dans un tableau d’entier positif trié ainsi que la valeur de cette occurrence (la taille du tableau est donnée par la constante MAX_TAB)
#define MAX_TAB 11

void fonc(int tab[MAX_TAB], int* maxOcc, int* maxVal)
{
    *maxOcc = 0;
    *maxVal = -1;

    int actOcc = 0;
    int actVal = -1;

    for (int i = 0; i <= MAX_TAB; i++)
    {
        if (i == MAX_TAB || tab[i] != actVal)
        {
            if (actOcc > 1 && actOcc > *maxOcc)
            {
                *maxOcc = actOcc;
                *maxVal = actVal;
            }

            actVal = tab[i];
            actOcc = 0;
        }

        actOcc++;
    }
}

int main()
{
    int T[MAX_TAB] = { 5, 6, 6, 6, 7, 8, 21, 21, 21, 25, 25 };
    int occ, val;

    fonc(T, &occ, &val);

    printf("occ=%d, val=%d\n", occ, val);

    return 0;
}

  1. Définir le type énuméré permettant de définir les mois d’une année standard puis définir les structures (date, temps, trace) et les nouveaux types permettant de gérer une trace d’accès (trace) et les traces d’accès bâtiments (tracebat)
typedef enum
{
    JAN = 1, FEV, MAR, AVR, MAI, JUN, JUL, AOU, SEP, OCT, NOV, DEC
} mois;

typedef struct
{
    unsigned char jour;
    mois mois;
    unsigned short annee;
} date;

typedef struct
{
    unsigned char heure;
    unsigned char minute;
    unsigned char seconde;
} temps;

typedef struct
{
    char badge[15];
    date date;
    temps temps;
} trace;

typedef struct
{
    trace traces[50];
    unsigned char nombre;
} tracebat;

  1. Écrire les fonctions suivantes :
    void ajouteTrace(trace t, tracebat * b)
    void afficheTrace(tracebat b)
    void videTrace(tracebat * b)

Corrigé :

void ajouteTrace(trace t, tracebat* b)
{
    b->traces[b->nombre++] = t;
}

void afficheTrace(tracebat b)
{
    trace* t = b.traces;
    for (unsigned char i = 0; i < b.nombre; i++, t++)
    {
        printf("badge %.15s - %02d/%02d/%04d %02dh%02dm%02ds\n",
            t->badge, 
            t->date.jour, t->date.mois, t->date.annee,
            t->temps.heure, t->temps.minute, t->temps.seconde);
    }
}

void videTrace(tracebat* b)
{
    b->nombre = 0;
}

  1. Écrire le programme principal (main) permettant de tester l’ajout de deux traces (badge 123456 le 2 mars 2018 à 14:20:18 et badge 123456 le 2 mars 2018 à 14:45:18) , leur affichage et leur suppression
int main()
{
    tracebat tb;

    ajouteTrace((trace){ "123456", { 02, MAR, 2018}, { 14, 20, 18} }, &tb);
    ajouteTrace((trace){ "123456", { 02, MAR, 2018}, { 14, 45, 18} }, &tb);

    afficheTrace(tb);

    videTrace(&tb);

    return 0;
}

  1. Écrire une fonction (sans utiliser string.h) qui permet de concaténer deux chaînes dans la première et qui retourne la taille total de la nouvelle chaîne. On suppose que la fin de chaîne, passée en paramètre, est correctement formatée et que la taille de la première est suffisamment grande pour contenir la seconde
int concat(char dest[], char src[])
{
    int pos_dest = 0;

    // on cherche la fin de la chaîne destination
    while (dest[pos_dest] != '\0')
        pos_dest++;

    int pos_src = 0;

    // on copie la chaîne source
    while (src[pos_src] != '\0')
        dest[pos_dest++] = src[pos_src++];

    return pos_dest;
}

  1. Écrire les fonctions suivantes :
    int estVide(ListeCirculaire * liste) → retourne vrai si la liste est vide, faux sinon
    void afficheListe(ListeCirculaire * liste) → affiche la liste

Corrigé :

int estVide(ListeCirculaire* liste)
{
    return liste->nbelt == 0;
}

void afficheListe(ListeCirculaire* liste)
{
    Element* elem = liste->tete;

    for (int i = 0; i < liste->nbelt; i++, elem = elem->suiv)
    {
        printf("Élément %d : %d\n", i, elem->valeur);
    }
}

  1. On souhaite maintenant pourvoir insérer un élément (qui aura été précédemment alloué) en fin de liste
void insereEnFin(ListeCirculaire* liste, Element* elt)
{
    liste->tete->prev->suiv = elt;
    elt->prev = liste->tete->prev;
    liste->tete->prev = elt;
    elt->suiv = liste->tete;
}

  1. On souhaite maintenant pourvoir insérer un élément (qui aura été précédemment alloué) en tête de liste
void insereEnTete(ListeCirculaire* liste, Element* elt)
{
    insereEnFin(liste, elt);
    liste->tete = elt;
}

  1. En utilisant les fonctions précédentes (insereEnFin(), insereEnTete()) créer une fonction d’ajout permettant d’ajouter de façon triée une valeur dans la liste
void ajouteListe(ListeCirculaire* liste, int valeur)
{
    Element* elem = malloc(sizeof(Element));

    elem->valeur = valeur;

    Element* tete = liste->tete;

    while (liste->tete->valeur < elem->valeur)
        liste->tete = liste->tete->suiv;

    insereEnFin(liste, elem);
}

TODO