Comprendre l'usage de STDIN ???

Fermé
salmamk27 Messages postés 3 Date d'inscription jeudi 7 mars 2019 Statut Membre Dernière intervention 14 mars 2019 - 7 mars 2019 à 13:06
salmamk27 Messages postés 3 Date d'inscription jeudi 7 mars 2019 Statut Membre Dernière intervention 14 mars 2019 - 9 mars 2019 à 19:18
Bien bonjour !
je viens de commencer les fichiers et j'ai trouvé un mot que je n'est pas colpris l'usage qui est :
printf("input a sentence for the file :");
fgets(str,sizeof str,stdin);
fprintf(fptr,"%s",str);
printf("the file (filesalma.txt) is created ");

STDIN ???

1 réponse

[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 7 mars 2019 à 18:17
Bonjour salmamk27,

fgets()
est une fonction définie dans l'entête standard
stdio.h
et dont le prototype est le suivant :

char * fgets ( char * str, int num, FILE * stream );

cf. http://www.cplusplus.com/reference/cstdio/fgets/

Son 3ème argument est un pointeur sur
FILE
permettant d'accéder à un flux de lecture.

Puisque tu dis que étudies les fichiers, tu dois savoir qu'un tel pointeur sur
FILE
sur un flux de lecture peut être défini par l'ouverture d'un fichier avec
fopen()
en lecture.

De fait, tu peux, bien sûr, utiliser
fgets()
pour lire le contenu disponible dans un fichier.

Mais tu peux aussi passer à
fgets()
le pointeur sur
FILE
"stdin" qui est définit par
stdio.h
.

La norme du C prévoit que
stdin
est un pointeur sur FILE permettant d'accéder au flux de l'entrée standard (que tu n'as pas à ouvrir avec
fopen()
, car il est déjà disponible selon le standard du C, et que tu ne devrais pas fermer avec
fclose()
).

http://www.cplusplus.com/reference/cstdio/stdin/?kw=stdin

Ce flux de l'entrée standard est, normalement, le flux des caractères entrés au clavier (cela peut être aussi un flux redirigé ayant une autre origine), mis en tampon par le système et qui est accessible par cette fonction
fgets()
si tu lui passes
stdin
en 3ème argument. Le même flux
stdin
est accédé par d'autres fonctions définies par
stdio.h
conçues pour lire ce flux seulement (comme
scanf()
ou
getchar()
, qui ne nécessitent pas que tu précises le flux, car elles n'opèrent que sur l'entrée standard).

Ici,
stdin
se comporte exactement comme le flux d'un fichier ouvert en lecture.

Utilisée pour lire des informations provenant d'une saisie par l'utilisateur au clavier, la fonction
fgets()
a cet avantage qu'il est facile au programme de limiter la lecture du flux à un nombre maximal de
char
à lire, pour ne pas dépasser la capacité de l'espace mémoire utilisé pour stocker ce qui est lu : dans ton cas l'emplacement pointé par
str
. La lecture du flux est donc limitée à ce qui figure en 2ème argument (
sizeof str
la fonction prenant en compte le caractère terminateur
'\0'
qui est ajouté).

C'est une façon recommandée d'éviter les risques de débordement de tampon et de corruption de la mémoire, qui peut occasionner des plantages, comportements imprévisibles ou des problèmes de sécurité, en ignorant les
char
saisis en plus qui dépasseraient la capacité de stockage indiquée y compris le caractère terminateur.

Cette limitation du nombre de
char
lus sur le flux d'entrée standard est également possible avec
scanf()
, en utilisant les spécificateurs de taille de cette fonction, mais cette façon de faire est moins naturelle et peut être omise par les programmeurs inattentifs.

Par exemple :

        char str[50] = { '\0' };

        printf("Veuillez taper 49 caractères au plus\n");
        if (scanf("%49[^\n]", str) == 1) {
            printf("J'ai récupéré : [%s]\n", str);
        }

Tu dois déduire toi même de la taille disponible l'espace nécessaire au caractère terminateur
'\0'
ajouté par
scanf()
.

Il y a d'autres différences et subtilités, concernant ces fonctions mais je m'arrêterai là pour le moment :-)

Il y a aussi d'autres flux standard définis par le C :
  • le flux de sortie standard (écran du terminal normalement, sauf redirection) :
    stdout
    (là où va le résultat de printf() par exemple)
  • le flux (de sortie) d'erreur standard (idem) :
    stderr
    (là où va le résultat de perror() par exemple)

Voir :
http://www.cplusplus.com/reference/cstdio/stdout/
http://www.cplusplus.com/reference/cstdio/stderr/

Dal
3
Dalfab Messages postés 706 Date d'inscription dimanche 7 février 2016 Statut Membre Dernière intervention 2 novembre 2023 101
7 mars 2019 à 17:55
Quand on voit le nombre de codes qui utilisent des
scanf()
en
"%s"
ou en
"%[]"
qui omettent de préciser la taille maximum du buffer, on peut affirmer qu'il y a énormément de programmeurs inattentifs ;-)
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 7 mars 2019 à 19:24
Oui, c'est vrai que cet oubli est très fréquent.

Dans l'enseignement initial du C il peut même être volontaire par l'enseignant, pour utiliser intentionnellement
scanf()
de façon simplifiée avec
"%s"
(un peu comme un pendant "naturel" à
printf()
avec ce qui semble être le même
"%s"
), pour gérer une entrée au clavier sans considérations de robustesse ou de sécurisation du code à ce stade pour ne pas "embrouiller" les personnes débutantes.

La réalité est que
scanf()
est une des fonctions les plus délicates à (bien) utiliser du langage C... il n'y a qu'à voir la taille de la page de manuel de cette fonction.

Elle est quand même pratique lorsqu'elle est bien utilisée...

Comme tu le sais,
fgets()
pour gérer
stdin
a ses propres problèmes ou contraintes : possible inclusion du retour chariot
'\n'
avant le caractère terminateur (si la taille de la saisie le permet), supposant un retraitement de la chaîne obtenue au clavier, si ce retour chariot est indésirable... d'un autre côté
scanf()
ne prend pas le retour chariot, qui reste dans
stdin
...

@salmamk27 : on peut en dire plus sur ces aspects, car tu ne fais qu'entrevoir la partie immergée de l'iceberg. Les deux fonctions nécessitent d'être attentifs au contenu obtenu et à celui restant dans le tampon
stdin
, non consommé par
scanf()
ou
fgets()
qui peut être différent, si on ne veut pas se retrouver avec des surprises selon les opérations suivantes de lecture de
stdin
à réaliser.

Il est aussi déconseillé de mélanger l'usage des deux fonctions, compte tenu de leurs comportements différents.
0
salmamk27 Messages postés 3 Date d'inscription jeudi 7 mars 2019 Statut Membre Dernière intervention 14 mars 2019
9 mars 2019 à 19:18
merci beaucoup je tiendrais a ne pas melanger l'usage comme vous avez dit
0