Le C en 20 heures


précédentsommairesuivant

XI. Structures et fichiers

XI-A. Les types synonymes

Cette nouvelle notion de type synonyme va nous servir d'ici peu. Voyons de quoi il s'agit.

Il est possible grâce au mot‐clé typedef de définir un synonyme pour un type déjà existant. Ainsi la définition suivante :
 
Sélectionnez
typedef int entier ;

définit un nouveau type appelé entier ayant les mêmes caractéristiques que le type prédéfini int. Une fois cette définition réalisée, nous pouvons utiliser ce nouveau type pour définir des variables et nous pouvons mélanger les variables de ce type avec des variables entières dans des expressions.
 
Sélectionnez
typedef int entier;
entier e1=23, e2=5, te[7]={1,2,3,4,5,6,7};
int i;
i = e1 + e2;
te[3] = i - 60;

XI-B. Structures

Une structure est un objet composé de plusieurs champs qui sert à représenter un objet réel ou un concept. Par exemple une voiture peut être représentée par les renseignements suivants : la marque, la couleur, l'année, etc.

Nous pouvons définir une structure ainsi :
Solution 1 :
 
Sélectionnez
struct nom_de_la_structure {
   /* Définition de la structure */
} nom_du_type;

Ceci fait, le nouveau type de données sera struct nom_du_type et nous pourrons déclarer une variable ainsi :
 
Sélectionnez
struct nom_du_type nom_variable;

Cependant, la répétition du mot‐clé struct est rapidement ennuyeuse. Nous préférerons donc souvent la syntaxe suivante.
Solution 2 :
 
Sélectionnez
typedef struct {
   /* Définition de la structure */
} nom_du_type;

Cette fois‐ci, le nouveau type de données s'appelle nom_du_type (nous avons créé la structure et en même temps nous avons défini un synonyme avec typedef).
Nous déclarerons une variable ainsi :
 
Sélectionnez
nom_du_type nom_variable;
En pratique, cela donne :
 
Sélectionnez
#define LONGUEUR 40
struct personne{
   char  nom [LONGUEUR];
   char  prenom [LONGUEUR];
   int   age;
};
struct personne p;
 
Sélectionnez
#define LONGUEUR 40
typedef struct {
   char  nom [LONGUEUR];
   char  prenom [LONGUEUR];
   int   age;
} personne;
personne p;

La seconde solution est plus simple et plus élégante à l'usage.
L'accès aux éléments d'une structure, que nous appelons aussi champ, se fait selon la syntaxe :
 
Sélectionnez
nom_de_variable.nom_du_champ
Par exemple :
 
Sélectionnez
#include <stdio.h> 
typedef struct {
   char  nom [40];
   char  prenom [20];
   int   age;
} personne;
int main () {
   personne p;
   printf("Veuillez entrer le nom de la personne:");
   scanf("%s",p.nom);
   printf("Veuillez entrer le prénom de la personne:");
   scanf("%s",p.prenom);
   printf("Veuillez entrer l'âge de la personne:");
   scanf("%d",&p.age);   /* ne pas oublier le & !!! */
   printf("Voici les caractéristiques de cette personne:\n");
   printf("nom=%s\n",p.nom);
   printf("prenom=%s\n",p.prenom);
   printf("age=%d\n",p.age);
   return 0;
}

XI-C. Bases sur les fichiers

Tout ce qui est enregistré sur votre disque dur ou presque est un fichier, et porte un nom.

Il est possible de créer, de lire ou d'écrire dans des fichiers. Notez que certains fichiers peuvent être protégés en lecture, en écriture ou les deux.

Voici un programme que nous allons détailler :

 
Sélectionnez
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. int main () { 
  4.     FILE *p_fichier; /* pointeur sur fichier*/ 
  5.     char nom_fichier[20], nom_personne[20]; 
  6.      int  i, nbr_enregistrements; 
  7.      /* 1ère étape : Création et remplissage du fichier */ 
  8.      printf("Quel est le nom du fichier à créer ? "); 
  9.      scanf("%s", nom_fichier); 
  10.  
  11.      /* w: write   r: read    a: append*/ 
  12.      p_fichier = fopen(nom_fichier, "w"); 
  13.      if (p_fichier == NULL) { 
  14.         printf("Erreur de création du fichier \n"); 
  15.         exit(-1);  // Abandonner le programme 
  16.      } 
  17.  
  18.      printf("Nombre de personnes à stocker ? : "); 
  19.      scanf("%d", &nbr_enregistrements); 
  20.  
  21.      for (i = 0; i<nbr_enregistrements; i++) { 
  22.         printf("Entrez le nom de la personne : "); 
  23.         scanf("%s", nom_personne); 
  24.         fprintf(p_fichier, "%s\n", nom_personne); 
  25.      } 
  26.      fclose(p_fichier); 
  27.  
  28.      /* 2ème étape : Lecture et affichage du fichier */ 
  29.      p_fichier = fopen(nom_fichier,"r"); /* read */ 
  30.      if (p_fichier == NULL) { 
  31.         printf("\aErreur d'ouverture sur le fichier \n"); 
  32.         exit(-2); // Abandonner le programme 
  33.      } 
  34.  
  35.      while (!feof(p_fichier)) { 
  36.         fscanf(p_fichier, "%s ", nom_personne); 
  37.         printf("Nom : %s\n", nom_personne); 
  38.      } 
  39.      fclose(p_fichier); 
  40.  
  41.      return 0; 
  42. } 

Explications :

  • Ligne 4 : une variable p_fichier est créée ; elle va pointer sur un type FILE. Sans entrer dans les détails, le type FILE est un type structure (vu au paragraphe précédent) qui permet de décrire un fichier.
  • Ligne 9 : l'utilisateur va saisir une chaîne au clavier. Cette dernière sera stockée dans la variable nom_fichier. Supposons pour fixer les idées que l'utilisateur tape au clavier familles.txt. Le fichier qui sera par la suite créé portera ce nom.
  • ligne 12 : fopen va créer une sorte de lien entre le fichier du disque dur qui s'intitule familles.txt et la variable p_fichier. Ainsi dans la suite, vous allez faire des opérations sur la variable p_fichier et toutes ces opérations seront répercutées au niveau du fichier familles.txt. Dans ce cas précis, les 3 opérations suivantes peuvent être réalisées :
    • p_fichier=fopen(nom_fichier, "w"); : si le fichier familles.txt existe déjà, il est purement et simplement écrasé puis réinitialisé à vide. S'il n'existe pas encore, le fichier est crée, pour l'instant il est vide.
    • p_fichier=fopen(nom_fichier, "r"); : si le fichier familles.txt existe déjà, il est simplement ouvert en lecture (read). L'ordinateur se positionne sur le premier caractère du fichier. Si le fichier n'existe pas (typiquement, nous nous sommes trompé de nom), la fonction fopen renvoie alors NULL.
    • p_fichier=fopen(nom_fichier, "a"); : si le fichier familles.txt existe déjà, il est simplement ouvert. Ensuite, l'ordinateur se positionne sur la fin de ce fichier, prêt à ajouter quelque chose après la dernière ligne. Nous comprenons mieux le "a" : append. Si le fichier n'existe pas, il est créé, et il est donc vide.
  • Ligne 13 : il est toujours prudent de faire ce test. Le pointeur sera nul s'il y a eu un problème lors de l'accès au fichier (nom incorrect pour l'ouverture en lecture, accès en écriture impossible…)
  • Ligne 15 : sortie catastrophe, le programme s'arrête immédiatement. La valeur ‐1 est renvoyée au système d'exploitation. Il est à noter que l'usage de la fonction exit impose d'ajouter la ligne #include <stdlib.h>.
  • Ligne 23 : l'ordinateur lit au clavier le nom d'une personne.
  • Ligne 24 : en fait, un fprintf n'est pas très différent d'un printf. La seule différence est qu'au lieu d'être écrite sur l'écran, la chaîne nom_personne sera écrite dans le fichier familles.txt.
  • Ligne 26 : on referme le fichier pour indiquer au programme C que l'on a fini de travailler sur familles.txt pour l'instant. Il faut toujours penser à faire cette opération.
  • Ligne 29 : ré‐ouverture du fichier, en lecture, cette fois‐ci. Si le fopen se passe bien (ce que nous pouvons supposer !), l'ordinateur se positionne alors au début de la 1re ligne du fichier.
  • Ligne 34 : feof désigne l'abréviation de file end of file. Donc cette ligne se traduit par : tant que l'on n'atteint pas la fin du fichier désigné par p_fichier…

Enfin, voici une autre fonction qui peut se montrer très utile :

 
Sélectionnez
char *fgets(char *ligne, int maxligne, FILE *p_fichiers)

La fonction fgets lit à partir du fichier au maximum maxligne -1 caractères et les stocke dans la chaîne de caractères ligne.

La lecture s'arrête sur \n qui est alors inclus dans la chaîne. La chaîne est complétée par \0. La fonction renvoie NULL si la fin de fichier est atteinte.

Voici un exemple de programme qui va simplement afficher le contenu du fichier essai.txt à l'écran (lisez-le puis étudiez la remarque qui le suit) :
 
Sélectionnez
#include  <stdio.h>
/* Définition de constante */
#define maxligne 100
char ligne[maxligne];
FILE *p_fichier;
int main() {
   p_fichier=fopen("essai.txt","r");
   while (! feof(p_fichier)) {
      fgets(ligne,maxligne,p_fichier);
      if (! feof(p_fichier))
         printf("J'ai lu :%s\n",ligne);
   }
   fclose(p_fichier);
   return 0;
}

Le test suivant peut paraître curieux :

 
Sélectionnez
if (! feof(p_fichier))
   printf("J'ai lu :%s\n",ligne);

En fait, il est nécessaire du fait que la fonction

 
Sélectionnez
feof(p_fichier)

renverra vrai si l'indicateur de fin de fichier du flux pfichier est positionné, c'est-à-dire s'il y a déjà eu une lecture infructueuse (par fgets par exemple).

Ainsi, lorsque le fgets lit la dernière ligne du fichier, un appel, dans la foulée à la fonction feof(p_fichier) renverra faux. Ce n'est que si nous refaisons un fgets (qui sera donc infructueux) que là, le test feof(p_fichier) renverra vrai. Donc finalement, nous voyons bien le problème : pour la toute dernière ligne, le fgets va échouer et l'instruction printf("J'ai lu :%s\n",lignes), si elle était appelée, pourrait bien renvoyer n'importe quoi !

XI-D. Fichiers et structures

Image non disponible Voici un exemple qui mêle fichiers et structures :

 
Sélectionnez
#include <stdio.h> 
#include <stdlib.h>
typedef struct {
   char nom [40];
   char prenom [20];
   int age;
} personne;
int main()  {
   FILE *p_fichier; /* pointeur fichier */
   /* Créer et remplir le fichier */
   p_fichier = fopen("essai.txt","w");
   if (p_fichier == NULL) {
      printf("\aImpossible de créer le fichier \n");
      exit(-1);  // Abandonner le programme
   }
   personne p;
   printf("Veuillez entrer le nom de la personne:");
   scanf("%s",p.nom);
   printf("Veuillez entrer le prénom de la personne:");
   scanf("%s",p.prenom);
   printf("Veuillez entrer l'âge de la personne:");
   scanf("%d",&p.age);   /* ne pas oublier le & !!! */
   fprintf(p_fichier, "%s\n",p.nom);
   fprintf(p_fichier, "%s\n",p.prenom);
   fprintf(p_fichier, "%d\n",p.age);
   fclose(p_fichier);
   return 0;
}

précédentsommairesuivant

  

Licence Creative Commons
Le contenu de cet article est rédigé par Eric Berthomier et Daniel Schang et est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2013 Developpez.com.