TP1&2: Utiliser les fonctions d’entrée sortie de base

Plutôt que d’utiliser des arguments passés en ligne de commande, vous allez maintenant utiliser des fonctions d’entrées/sorties. Vous avez déjà vu, dans les exercices précédents, l’utilisation de printf pour afficher le résultat de votre programme qui effectue la somme de deux entiers.

Dans la suite de ce TP, vous allez faire évoluer ce programme en utilisant d’autres sources d’information:

  1. des interactions avec l’utilisateur, via la fonction scanf
  2. des informations contenus dans un fichier via la fonction fscanf

Enfin, vous verrez également comment enregistrer le résultat de vos calcul dans un fichier via la fonction fprintf.

Exercice 1: réaliser la somme de deux entiers via des interactions avec l’utilisateur, en utilisant la fonction scanf. Commençons par la description du comportement de la fonction scanf:

int scanf( const char *format [, arg1 [, arg2]...]);

Les paramètres de cette fonction sont:

  1. une chaine de caractères format, qui peut contient du texte, et peut également contenir des caractères de formatage dont nous expliquerons le rôle par la suite. Les caractères de formatage sont faciles à identifier: ils commencent par le caractère %.
  2. une suite d’arguments de longueur indéfini: la présence de crochets indique que les arguments sont optionnels, la présence des points de suspension indique que le nombre d’arguments possible est indéfini.

Les principes de fonctionnement de scanf sont les suivants:

  • lorsque scanf est appelé, le programme est bloqué jusqu’à ce que l’utilisateur tape une chaine de caractère dans le terminal, puis appuie sur « entrée », « enter », ou « ↵ » (en fonction du clavier)
  • le programme est alors débloqué, et scanf cherche dans ce qui a été tapé par l’utilisateur, une chaine de caractère qui correspond au format. Si c’est le cas, les arguments arg1, arg2, etc. sont initialisés avec les valeurs utilisées dans la chaine de caractère sur le terminal.

NOTE: pour pouvoir initialiser arg1 et arg2 dans l’appel de fonction, arg1 et arg2 doivent être de type pointeurs. Nous passerons donc des adresses ou des pointeurs en paramètre de cette fonction. L’explication vous sera donné un peu plus tard en cours, et sera illustrée dans les TPs.

Valeur retournée : le nombre de valeurs (args) que scanf a réussi à identifier correctement, ou EOF (-1) en cas d’erreur.

Pour faciliter votre compréhension du fonctionnement de scanf, prenons quelques exemples dans le code source suivant (source complétée: http://www.cplusplus.com/reference/cstdio/scanf/) :

/* scanf example */
#include <stdio.h>

int main ()
{
 char str [80];
 int i;

 printf ("Enter your family name: ");
 scanf ("%79s",str);
 printf ("Enter your age: ");
 scanf ("%d",&i);
 printf ("Mr. %s , %d years old.\n",str,i);
 printf ("Enter a hexadecimal number: ");
 scanf ("%x",&i);
 printf ("You have entered %#x (%d).\n",i,i);
 printf ("Enter your firstname and your promo seperated with a space (Example:Yves 1984)\n");
 int j = scanf ("%s %d", str, &i);
 if(j!=2)
   printf("format error when writing: your firstname your promo; found %d information(s)\n", j);
 else
   printf("Welcome %s, promo %d\n", str, i);
 return 0;
}

Notes: cet exemple de code illustre différentes propriétés de l’usage de la fonction scanf.

  1. Pour commencer, notez que le premier paramètre de la fonction, le format, commence toujours par un caractère de  formatage. Dans le cas contraire, la fonction échoue car elle compare le format avec un contenu inexistant: vous n’avez encore rien tapé sur le terminal.
  2. Deuxièmement, notez qu’un espace est considéré comme un séparateur, et que cet espace est supprimé lors de l’identification des arguments arg1, arg2, etc. (sauf dans le cas du formats %c).
  3. Enfin, notez encore une fois que les arguments sont bien de type pointeurs.

Exercice: modifier le programme TP1and2/part3_IOs/material/sum_scanf.c pour effectuer la somme entre deux entier obtenus grâce à l’utilisation de la fonction scanf.

Pour aller plus loin, faites les exercices qui suivent; il n’est pas obligatoire de finir la partie du TP ci-dessous pour passer au TP suivant lors de la 4ème séance.

Exercice 2: réaliser la somme de N entiers écrits dans un fichier, en utilisant la fonction fscanf. Cette fonction permet d’extraire des information depuis un fichier contenant du texte. Nous allons décrire cette fonction, que vous utiliserez ensuite pour mettre à jour votre programme.

Signature de la fonction:

int fscanf(FILE *stream, const char *format, [arg1, [arg2]...])

Les paramètres de la fonction sont:

  1. un flux d’information, appelé stream, le plus souvent obtenu par ouverture d’un fichier texte via un appel à la fonction fopen. Le fonctionnement de cette fonction sera vu beaucoup plus tard, dans la partie du cours sur les systèmes d’exploitation. Vous verrez comment l’utiliser dans un exemple ci-après.
  2. une chaine de caractère de type format, dont le rôle est similaire à celui du paramètre format de la fonction scanf. La principale différence est qu’on pourra utiliser des chaines de caractères plus compliquées dans fscanf.
  3. un ensemble d’arguments, dont le rôle et l’utilisation sont similaires à ceux des paramètres arg1, arg2, etc. de la fonction scanf.

Les principes de fonctionnement de fscanf sont les suivants:

  1. Lorsque fscanf est appelé, elle déplace un curseur de lecture du fichier, caractère par caractère (nous verrons la fonction système qui permet de réaliser cela dans la partie du cours sur les systèmes d’exploitation).
  2. En déplaçant ce curseur, la fonction fscanf s’arrête dès qu’elle a trouvé dans le fichier une chaine de caractère qui permet d’identifier la valeur du premier caractère de formatage.
  3. La fonction essaie alors d’identifier les valeurs des autres caractères de formatage. Pour chaque caractère de formatage dont la valeur a été identifiée, la fonction fscanf initialise le paramètre arg correspondant avec cette valeur (arg1 avec la correspondance du premier caractère de formatage, arg2 avec la correspondance du deuxième, etc.).

Valeur retournée : le nombre de valeurs (args) que fscanf a réussi à identifier correctement, ou EOF (-1) en cas d’erreur.

Pour faciliter votre compréhension du fonctionnement de fscanf, prenons quelques exemples dans le code source suivant :

Exemple 1: lire un fichier texte « mot à mot »:

#include <stdio.h>


/******************** main ********************/
int main(int argc, char*argv[]) {
 FILE * f;
 char word[30];
 char file_name[80];
 int words_nb, i, ret;

 printf ("file name?\n");
 scanf( "%s", file_name);

 printf ("number of words to read?\n");
 scanf( "%d", &words_nb);


 f = fopen(file_name, "r");
 if (f == NULL){
   printf("Error: file %s does not exist\n", file_name);
   return -1;
 }


 for (i=0; i<words_nb; i++){
   ret = fscanf(f, "%s", word);
   if (ret != 1) printf ("i = %d : error when reading input stream\n", i);
   printf ("word : %s \n", word );
 }

 return 1;
}

Exemple 2:

#include <stdio.h>
int main(int argc, char const *argv[]) {
  char name[80];
  int i;
  FILE * f = fopen("name_list", "r");
  int ret = fscanf(f, "name: %s birth date: %d\n", name, &i);
  while(ret==2)
  {
    printf("Name:%s, approx. age:%d\n", name, 2015-i);
    ret = fscanf(f, "name: %s birth date: %d", name, &i);
  }
  return 0;
}

Exercice: modifier le programme TP1and2/part3_IOs/material/sum_fscanf.c pour effectuer la somme entre deux entier obtenus grâce à l’utilisation de la fonction fscanf.

Exercice 3: écrire le résultat de votre calcul dans un nouveau fichier, en utilisant la fonction fprintf. Pour finir ces petits exercices sur les entrées/sorties, nous allons voir comment enregistrer des informations textuelles dans un fichier plutôt que sur le terminal. Vous allez pour cela utiliser la fonction fprintf.

Signature de la fonction

int fprintf(FILE * stream, const char *format [, arg1 [, arg2]...]);

Les paramètres de la fonction sont:

  1. un flux d’information, appelé stream, le plus souvent obtenu par ouverture d’un fichier texte via un appel à la fonction fopen. Le fonctionnement de cette fonction sera vu beaucoup plus tard, dans la partie du cours sur les systèmes d’exploitation. Vous verrez comment l’utiliser dans un exemple ci-après.
  2. une chaine de caractère de type format, dont le rôle est similaire à celui du paramètre format de la fonction printf.
  3. un ensemble d’arguments, dont le rôle et l’utilisation sont similaires à ceux des paramètres arg1, arg2, etc. de la fonction printf.

Les principes de fonctionnement de fprintf sont les mêmes que ceux de printf, sauf que la chaine de caractère obtenue est sauvegardé dans un flux (un fichier par exemple).

Valeur retournée : le nombre de caractère ajoutés au contenu

Pour faciliter votre compréhension du fonctionnement de fprintf, prenons quelques exemples dans le code source suivant :

#include <stdio.h>
#include <stdlib.h>

int main()
{
   FILE * fp;

   fp = fopen ("file.txt", "w+");
   fprintf(fp, "%s %s %s %d", "We", "are", "in", 2015);
   
 return(0);
}

Exercice: modifier le code de votre programme sum.c pour enregistrer le résultat de la somme de N entier (lus dans un fichier texte avec fscanf) dans un fichier appelé sum_result.

Fin des TPs 1 et 2