Back to homepage

La bonne gestion des flux en langage C

Introduction

Rappel sur les flux

En C, un flux est un canal destiné à transmettre ou à recevoir de l'information.
Il peut s'agir de fichier ou de périphériques.
La librairie stdio.h en définit trois pour les périphériques de communications de base :

stdinEntrée standard (clavier)
stdoutSortie standard (écran)
stderrSortie erreur (écran également)

Ansi, pour afficher une erreur, on comprendra qu'il faille utiliser la fonction fprintf et non la fonction printf :

/* printf("message") correspond à fprintf(stdout, "message"); */
printf("Ceci est un texte d'information.\n");

fprintf(stderr, "Ceci est une erreur.\n");

fflush

La légende par laquelle fflush(stdin) pourrait servir à vider le tampon du flux d'entrée avant une saisie est rigoureusement fausse !
En effet, fflush est décrit (cf. man) comme étant destinée aux flux ouverts en écriture, ce qui n'est pas vraiment le cas d'un flux d'entrée !

La lecture de caractères

Lire un caractère en entrée est opération qui peut souvent nous réserver des surprises.
Un retour chariot ou un espace d'une saisie précédente est considéré par le système comme une réponse correcte ;
c'est donc au programmeur de bien gérer le filtrage des caractères autorisés.

Les quatres fonctions suivantes qui suivent sont quasi-identiques :

Le retour-chariot est laissé dans le tampon du flux après une saisie qui aura été validé par la touche Entrée.
Ce caractère sera interprété comme une valeur lue lors d'un prochain appel à l'une de ces fonctions.
Le plus propre est de vidanger le flux après un appel à l'une de ces fonctions.

/* lecture d'un caractère */
char c;
c = getchar();

/* vidange du flux */
while(getchar() != '\n');

Le filtrage

Le filtrage des informations d'entrée est primordiale, l'utilisateur est le seul (ou presque) élément imprévisible dans l'éxécution d'un programme.
Un filtrage pour une saisie de caracètere est facilement implémentable via la boucle do/while ; voici quelques morceaux de code :

/* saisie d'un caractère 'visible' */
char c;
while((c = getchar()) <= 0x20);

/* vidange du flux */
while(getchar() != '\n');
/* saisie d'un chiffre */
char c;
do
	c = getchar();
while(c < '0' || c > '9');

/* vidange du flux */
while(getchar() != '\n');
/* saisie d'une confirmation */
char c;
printf(" [y/n] ?");

/* le ou avec la valeur 0x20 permet
   de forcer la casse en minuscule */
do
	c = getchar() | 0x20;
while (c != 'y' && c != 'n');

/* vidange du flux */
while(getchar() != '\n');

La lecture de chaînes

Au niveau de la lecture de chaines clavier, on peut isoler trois fonctions qui fonctionnent différemment :

La fonction scanf laisse dans le tampon du flux les caractères d'espacements tel que l'espace, la tabulation ou le retour chariot.
En outre, elle ne permet que la saisie d'un mot continu et non d'une phrase à cause des espaces qui servent à délimiter les différents champs.

gets lit une ligne entière au clavier et retire le retour chariot final du tampon du flux.
Il n'y a pas de contrôle de la longueur des informations entrées, il y a donc un risque de débordement.
Pour cette raison, cette fonction est très fortement déconseillée.

fgets, comme gets permet de lire des lignes entières avec des espaces.
Le retour chariot final est également retiré du flux du tampon mais il faut savoir qu'il sera placé dans le tampon qui retourne les données.
Le programmeur a donc à sa charge le fait de le retirer :

/* lecture d'une ligne de texte */
fgets(buffer, sizeof(buffer), stream);

/* on retire le '\n' */
buffer[strlen(buffer)-1] = '\0';

Les autres types de données

La fonction scanf permet la lecture d'information de type entier, flottant ou personnalisé.

Le retour chariot ainsi que les données qui n'interessent pas la fonction sont laissée dans le flux.
On doit par conséquent vidanger le flux manuellement après une lecture avec scanf.

/* lecture d'un entier */
int i;
scanf("%d", &i);

/* vidange du flux */
while(getchar() != '\n');

Conclusion

La saisie caractère par caractère laissera forcément le retour chariot dans le tampon de flux.
Il sera donc plus efficace d'utiliser la fonction la plus simple : getchar

Pour les saisies de chaines, la fonction qui permet de gérer proprement une ligne entière est fgets.
Il sera nécessaire de retirer le retour chariot qui sera retournée dans le buffer, à la suite des données utiles (voir plus haut).

La fonction scanf sera egalement utile pour les saisies personnalisées (décimal, hexadécimal, mots simples, etc.).

Pour les fonctions getchar et scanf, il conviendra de retirer les données superflues ainsi que le retour chariot pour les fonctions opérant par la suite sur le flux (voir plus haut).

contact/mail protection