SELC - Langage C : Travaux pratiques

Bertrand Dupouy


SOMMAIRE

  1. Présentation
  2. TP1 :introduction et E/S
  3. TP2 : du fichier à la liste chaînéee
  4. TP3 : recherche, insertion, tri
  5. TP4 : interface de commande
  6. TP5 :
  7. TP6 :


1. Présentation

Quelques documentations : Voici ce que l'on se propose de faire dans cette suite de TP sur le langage C :

  1. (TP 1) lire un fichier contenant des informations sur les élèves du groupe (nom, prénom, etc) et les ranger dans un tableau. Ces fichiers se trouvent là:
  2. (TP 2) puis créer, à partir de ce tableau, une liste chainée dont chaque élément représente un élève,
  3. (TP 3) donner des fonctions de base pour gérer cette liste : la trier, y insérer un élément, chercher si elle contient un élément,
  4. écrire une interface simple qui permette d'utiliser ces commandes de recherche et d'insertion et aussi d'envoyer un message à un élève
Le premier TP permet de se familiariser avec le langage C en essayant quelques unes de ses fonctions d'entrées-sorties.

2. TP1 : introduction et E/S

Il existe de très nombreuses fonctions pour faire des entrées-sorties en langage C, dans ce premier TP nous verrons : L'exemple utilisé sera réutilisable pour les exercices suivants.

2.1 Quelques différences entre C et Java

2.2 Exercices

  1. Pour vous permettre de commencer, on donne un exemple complet ici
    Ce programme introduit les fonctions d'E/S; printf, scanf, fopen, fscanf sur une exemple de lecture de mots dans un fichier texte avec leur affichage à l'écran.
    Il montre également l'utilisation de #ifdef : pour avoir la version qui initialise les paramètres sur la ligne de commande, on utilise gcc ainsi :
    gcc -DARGS -Wall exo1.c -o exo1
    
  2. Exercice 1
    Exécuter ce programme pour lire le fichier contenant la liste des élèves ou tout autre fichier texte, le source du programme, par exemple.
  3. Exercice 2
    Reprendre le programme précédent et le modifier pour lire le fichier des élèves ligne par ligne et le ranger dans un tableau Eleve_t tab_eleves[100] dont chaque entrée est du type :
    typedef struct eleve {
    	char nom[30];
    	char prenom[20];
    	char login[20];
    	char photo[20];
    	int info;
    } Eleve_t;
    
    Déclaration du tableau :
    Eleve_t tab_eleves[100];
    
    Pour lire le fichier, on utilise encore, dans une boucle while, la fonction fscanf :
    
    ret_lec = fscanf(fichier, "%s %s %s %s %d", tab_eleves[ilig].nom,
                     tab_eleves[ilig].prenom, tab_eleves[ilig].login,
                     tab_eleves[ilig].photo, &tab_eleves[ilig].info);
    
    Cette fonction, qui renvoie un int, renvoie la valeur EOF quand elle atteint la fin du fichier.

    Après lecture du fichier, on visualisera à l'écran le contenu du tableau tab_eleves.

  4. Exercice 3
    On va maintenant effectuer dans une fonction la lecture et le rangement des données lues dans le tableau.
    Cette fonction lire_fichier qui prend en arguments le tableau et le nom du fichier va renvoyer le nombre de lignes lues dans le fichier.
    La signature (ou prototype) de cette fonction qui renvoie donc un int et prend en argument un tableau du type Eleve_t et une chaine de caractéres (un tableau de char) est :
    int lire_fichier(Eleve_t *tab, char * nom);
    
    Le programme aura la structure suivante :
    ...
    /********************   main   ********************/
    int main(int argc, char*argv[]) {
    	...
    	
    	printf ("nom du fichier ?\n");
    	scanf( "%s", nomfic);
    	
    	/****** appel a la fonction  *******/
    	ilig = lire_fichier(tab_eleves, nomfic);
    	
    	/****** visualisation du tableau a l ecran  *******/
    	/* A COMPLETER */
    	
    	return 1;
    }
    
    /********************   lire_fichier   ******************
     * lire le fichier ligne par ligne et le ranger dans le 
     * tableau dont chaque entree est du type Eleve_t 
     ********************************************************/
    int lire_fichier(Eleve_t *table, char * nomfic){
    	
    	/* A COMPLETER */
    
    	return ilig;		
    
Le corrige est .

2. TP2 : du fichier à la liste chaînée

Résumé de ce que l'on va faire :
  1. Lire le fichier contenant la liste des élèves et les ranger dans un tableau en reprenant le dernier exercice du TP1.
  2. Créer une liste chainée à partir des informations contenues dans ce tableau, (par insertion en début de liste, cest une pile).
    Chaque élément de la liste chaînée a le type suivant :
    typedef struct maillon{
          Eleve_t  eleve;
          struct maillon * suivant;
    } Maillon_t;
    
  3. Visualiser cette liste à l'écran (utiliser printf) et l'écrire dans un fichier (utiliser fprintf),
2.2 Exercices

Il faut écrire les fonctions de création de la liste à partir du tableau. Ces fonctions seront rangées dans un second fichier qu'on appelera gere-liste.c. Les prototypes correspondants seront rangés dans gere-liste.h. Les types utilisés (Eleve_t, Maillon_t) seront rangés dans tpselc_types.h
Voici la liste des fonctions à écrire :

Voici leurs signatures :
Maillon_t * nouveau_maillon(Eleve_t un_eleve);
Maillon_t * chainer(Maillon_t * debut, Maillon_t * maillon_a_chainer);
int         ecrire_fic_liste (Maillon_t * debut, char * nom_fichier);
void        ecrire_liste(Maillon_t * debut);

Comment faire :

3. TP3 : recherche, insertion, tri

3.2 Exercices

On va écrire quelques fonctions gérer cette liste : chercher si elle contient un élément, y insérer un élément, la trier.

On ne passera à l'écriture d'une fonction qu'après avoir testé la précédente.
On pourra faire ces tests comme dans la fonction main proposée ci-après dans le paragraphe "Comment faire" .

  1. chercher qui vérifie si un nom se trouve dans la liste et renvoie l'adresse de l'élément correspondant, ou NULL si aucun ne correspond (utiliser strcmp()).
  2. inserer qui insère un maillon dans la liste supposée triée et renvoie le début de la liste,
  3. trier qui trie la liste en la copiant dans une nouvelle liste. Le tri se fera sur le nom et de la façon suivante  :
  4. liberer qui rend la memoire occupee par une liste chainee. Cette fonction ne renvoie rien.

Voici leurs signatures :
Maillon_t * chercher (Maillon_t * debut, char *nom);
Maillon_t * inserer(Maillon_t * debut, Maillon_t * maillon_a_inserer);
Maillon_t * trier(Maillon_t * debut);
void liberer(Maillon_t *debut);

Comment faire :

4. TP4: interface de commande

On va maintenant écrire une interface qui présente un menu à l'utilisateur.
Ce menu va permettre d'envoyer des commandes au programme, ces commandes sont :
  1. chercher, (search) qui demande le nom d'un élève, appelle la fonction chercher et, si ce nom est dans la liste, affiche les inforamtions associées à ce nom,
  2. lister, (list) qui appelle la fonction ecrire_liste,
  3. (facultatif) envoyer, (send) qui demande le nom d'un élève, appelle la fonction chercher et crée dans /tmp un fichier contenant un message pour l'élève en question,
  4. fin, (stop) qui termine le programme.
La structure de données utilisée est :
 
typedef struct commande {
	char nom [80];
	char name[80];
	int fonc;
} Commande_t;
Elle sera initialisée comme suit :
 
Commande_t Comm []= {
		{"chercher", "search", 1}, 
		{"lister", "list", 2}, 
		{"envoyer", "send", 3},
		{"fin", "stop", 4}, 
	};
Le canevas du programme d'interrogation sera du type :
 
while (1)	{
	printf ("Commandes disponibles : Available commands :\n");
	for (Compteur=0; Compteur < NBRE_COMMANDES; Compteur++) 
		printf(" %s ", Comm[Compteur].nom);
	scanf ("%s",  Une_comm);
	/* Verifier si la commande est bien dans la liste */
	....
	/* si la commande existe appeler la fonction correspondante 
           en utilisant un switch */
	switch (Comm[Compteur].fonc) {
		case 1 :
		...
		...
		...
		case 4 : /* fin */
		return 1;
	}
	
Pour traiter la fonction facultative :
  1. Pour créer le fichier on utilisera la commande :
    /bin/echo bonjour > /tmp/FICHIER 
    où FICHIER sera le nom du fichier construit a partir du nom de l'eleve. Si celui-ci est NOM, ce nom sera "pour_NOM".
  2. pour exécuter cette commande, on construira la commande dans une chaine de caractères ma_commande et on appelera la fonction system(ma_commande),
Un corrigé est ici.

5. TP5 :

6. TP6 :