INF304 — TP1

Première partie : arguments de la ligne de commande et fichiers en C

Préambule

Les TP se font sous Linux, sur les machines du DLST avec une machine virtuelle Ubuntu. Pour le premier TP, suivre la procédure de connexion et de mise en place des fichiers de configuration sur cette page.

Utilisation de la machine virtuelle Ubuntu depuis les machines du DLST

  1. Ouvrez le client « Omnissa Horizon Client » Icône Omnissa Horizon Client
  2. Se connecter sur « ebureau » Icône ebureau.univ-grenoble-alpes.fr
  3. Entrer son login et mot de passe Agalan (fournis par l'UGA)
  4. Choisir la machine virtuelle « Ubuntu IM2AG » Icône Ubuntu IM2AG

Une fois la machine virtuelle lancée (depuis un environnement Linux/Ubuntu), lancez Visual Studio et ouvrez un répertoire (soit votre répertoire personnel, soit un répertoire créé pour l'UE, par exemple nommé « INF304 »).

Il est conseillé, pour tous les TPs, à partir de Visual Studio, d'ouvrir systématiquement un répertoire de travail (accès au gestionnaire de fichiers intégré), et un terminal (Terminal > New terminal) où vous pourrez taper les commandes indiquées.

Avant de commencer ce premier TP vous devez créer un répertoire de nom INF304 (mkdir INF304, ou répertoire créé à l'ouverture avec Visual Studio). Placez-vous alors dans ce répertoire (cd INF304), et copiez les fichiers nécessaires à ce premier TP :

cp -r /home/Public/304_INF_Public/TP1 .
N'oubliez pas le "." à la fin de cette commande !

Alternative : téléchargez l'achive contenant ces fichiers : TP1.zip et décompressez cette archive dans un répertoire de travail (le répertoire INF304 créé ci-dessus).

Vous pouvez alors vous placer dans le répertoire TP1 qui vient d'être créé (cd TP1), puis dans le sous-répertoire TP1a.

Arguments de la ligne de commande en C

L'accès aux arguments de la ligne de commande depuis un programme C se fait en utilisant les deux paramètres argc et argv de la procédure principale main :

Pour mieux comprendre le fonctionnement de ces fonctions :

  1. Lisez le code du programme essai_ligne_de_commande.c en utilisant un éditeur de texte (emacs, nedit ou gedit).
  2. Compilez ce programme avec la commande clang essai_ligne_de_commande.c -o essai_ligne_de_commande.
  3. Exécutez-le avec différentes séquences d'arguments, comme par exemple :
  4. ./essai_ligne_de_commande abc 42 defg
    ./essai_ligne_de_commande
    ./essai_ligne_de_commande abc
    

Exercice 1

Écrire un programme C de nom exercice1.c qui affiche un message d'erreur s'il ne reçoit pas exactement deux arguments sur sa ligne de commande, et qui affiche ces deux arguments dans le cas contraire. Compilez ce programme (clang exercice1.c -o exercice1) et testez-le.

Lecture et écriture de «fichiers texte» depuis un programme C

Référez-vous à la partie «Lecture et écriture de fichiers texte depuis un programme C» du Mémento C.

Exercice 2

Écrire un programme C de nom exercice2.c qui lit la première ligne d'un fichier et copie son contenu dans un autre fichier. Les noms des deux fichiers seront passés en argument de la ligne de commande, un message d'erreur sera affiché si la ligne de commande est incorrecte. Compilez ce programme et testez-le.

Exercice 3

Écrire un programme C de nom exercice3.c qui lit un fichier caractère par caractère et copie son contenu dans un autre fichier. Les noms des deux fichiers seront passés en argument de la ligne de commande, un message d'erreur sera affiché si la ligne de commande est incorrecte.

Compilez et testez ce programme.

Exercice 4

  1. Écrire un programme C de nom exercice4.c qui lit dans un fichier (dont le nom est fourni sur la ligne de commande) une date au format "jour mois année" (comme 18 octobre 1966) avec le jour sur la première ligne, le mois sur la deuxième ligne et l'année sur la troisième, et affiche un entier représentant la somme du jour et de l'année (comme 1984, somme de 18 et 1966).

    Exemple de fichier :

    18
    octobre
    1966
    

    Compilez et testez ce programme.

  2. Modifier le programme pour lire une date dans un fichier avec le jour, le mois et l'année sur la même ligne.

    Avant et après le nom du mois, il y a (au moins) un espace ou tabulation.

    Exemple de fichier :

    18 octobre 1966
    

Deuxième partie : Tests et débogage

Pour cette deuxième partie, placez-vous dans le répertoire INF304/TP1/TP1b.

Écriture de tests

Exercice 0

Prendre connaissance et comprendre le fonctionnement des différents modules du squelette de programme fourni.

Le but de cette deuxième partie est de tester soigneusement la procédure tri_insertion du paquetage tri.

Exercice 1

Écrire un jeu de tests (c'est-à-dire, plusieurs fichiers de tests !) pour tester la fonction de tri.

Compilez le programme exec_test_tri à l'aide de la commande make exec_test_tri (ou simplement make).

Testez le programme exec_test_tri sur le jeu de tests que vous avez créé. La fonction tri_insertion est-elle correcte ?

Débogage

Les outils de débogage permettent de suivre l'exécution d'un programme pas à pas, et d'avoir accès à chaque pas à l'état de la mémoire (zones allouées, valeur des variables et paramètres). Un des outils de débogage les plus largement utilisés est l'outil gdb. Cet outil — en ligne de commande — est souvent utilisé via une interface graphique : VScode par exemple permet d'utiliser gdb.

L'utilisation d'un outil de débogage nécessite de compiler le code source avec une option particulière (-g).

  1. compilez le programme exec_test_tri en tapant la commande make exec_test_tri
  2. notez la taille des fichiers .o en tapant la commande ls -l *.o
  3. modifiez la première ligne du fichier Makefile en ajoutant l'option -g : CC=clang -g
  4. recompilez le programme exec_test_tri en tapant les commande make clean, puis à nouveau make exec_test_tri
  5. notez à nouveau la taille des fichiers *.o
L'option -g ajoute des informations dans le code compilé du fichier .o permettant de faire la correspondance avec les instructions du code source.

Utilisation de gdb avec VScode

Si vous ne l'avez pas fait lors du premier TP, copiez les deux fichiers de configurations tasks.json et launch.json, depuis le répertoire /home/Public/304_INF_Public/.vscode, dans votre propre répertoire .vscode (cf « Mise en place des fichiers de configuration »).

Ouvrez le fichier source tri.c (Fichier/Ouvrir un fichier source), placez un point d'arrêt au début de la fonction tri_insertion : un point d'arrêt se place en cliquant sur la partie gauche de l'éditeur (à gauche des numéros de ligne). Un point d'arrêt placé est signalé par un point rouge : il s'agit d'un point du programme où l'exécution va être arrêtée lors du débogage.

Une fois le programme compilé avec l'option -g, et le point d'arrêt placé, ouvrez le programme principal exec_test_tri.c dans une fenêtre, puis lancez le débogueur (bouton , ou menu Exécuter/Démarrer le débogage). VScode vous demande d'entrer un argument au programme débogué (ici, ce sera le nom du fichier d'entrée contenant un tableau à trier).

Observez les valeurs de t, t->taille, i. Observez le fonctionnement des différentes commandes disponibles (barre d'outils , ou menu Exécuter) : «pas à pas principal», «pas à pas détaillé», «pas à pas sortant».

Exercice 2

Utilisez l'outil de débogage pour trouver et corriger les éventuelles erreurs de la fonction tri_insertion.

Automatisation des tests

Exercice 3

On souhaite automatiser l'exécution de ces tests. Compléter la procédure test_tri_insertion (dans le fichier test_tri.c) afin que cette procédure, pour chaque nom de fichier fourni comme argument de la liste de commande :

  1. lise le tableau contenu dans le fichier
  2. trie ce tableau à l'aide de la procédure tri_insertion
  3. écrive le tableau trié dans un nouveau fichier (dont le nom correspond par exemple au nom du fichier d'entrée, suffixé par .out).
NB: on peut recopier une chaîne de caractères dans une autre à l'aide de la fonction strcpy, et concaténer une chaîne à une autre à l'aide de la fonction strcat (déclarées dans le module string.h) :
    #include 

    void exemple_concatenation(char * nom) {
      char nouveau_nom[256];

      strcpy(nouveau_nom, nom);
      strcat(nouveau_nom, ".out");
      ...
    }
  

Exercice 4

Il peut être fastidieux de vérifier «à la main» (ou plutôt «aux yeux»...), pour chaque test, que le résultat de la procédure est correct.

Écrivez un oracle pour la procédure de tri, c'est-à-dire une procédure ou une fonction dont le rôle est de vérifier que le résultat rendu par la procédure testée correspond bien à sa spécification. Quelles sont les propriétés à vérifier pour une procédure de tri ?

Complétez la procédure test_tri_insertion, en utilisant cet oracle, afin d'afficher automatiquement quel(s) tests échouent.

Exercice 5

On souhaite maintenant vérifier que le jeu de tests écrit est pertinent. Modifiez l'algorithme afin d'y introduire une erreur (si possible assez subtile...). L'erreur introduite est-elle découverte par votre jeu de tests ?

Compte-rendu

À l'issue du TP, déposer sur la page moodle du cours :