OVH Cloud OVH Cloud

comprendre fgets

94 réponses
Avatar
bpascal123
Bonjour

Avec p2 qui pointe sur une chaine saisie avec fgets (ex."abcd")
dans for ( p2 ; *p2 ; p2++ )
Pourquoi l'incr=E9mentation se fait sur 6 intervalles en m=E9moire.

0 =3D a
1 =3D b
2 =3D c
3 =3D d
4 =3D \0
5 =3D ???

A quoi correspond la derni=E8re position (numero 5) ?

(En fait, je veux dire que je dois d=E9cr=E9menter 2 fois apres la fin
de la boucle for pour pointer p2 sur 'd' en position 3). Ca veut dire
qu'en plus de '\0', fgets inclue un autre caract=E8re.

Question suppl=E9mentaire (culture g=E9n=E9ral en informatique) :
La chaine enregistr=E9e avec fgets se trouve dans la memoire ram ou
dans un des registres?

Merci

10 réponses

Avatar
Antoine Leca
-ed- a écrit :
On 9 nov, 12:54, (Marc Espie) wrote:
De meme, parfois, tu aimerais bien pouvoir dire "okay, je vire tout ce qui
est en attente sur stdio, la maintenant, parce que je vais interagir
directement avec l'utilisateur, et que ca impose de gicler tout ce qu'il
a entre jusqu'ici".



Cette opération doit etre faite systématiquement et de manière
'intelligente' après chaque appel à une fonction de saisie. C'est
tout. L'ordre à respecter absolument est :

1 - Saisir
2 - Nettoyer



Non. Si tu veux une interface utilisateur solide, tu dois distinguer
deux cas très différents :

- soit tu ne contrôles pas exactement ce qui se passe autour, et la
bonne séquence c'est alors
0 - Nettoyer
1 - Saisir
2 - Nettoyer
pour éviter de se faire polluer par des interactions non désirées.
Évidemment c'est d'autant plus important lorsque la saisie est en fait
la confirmation pour une opération avec des conséquences importantes :
un exemple serait la dernière question posée dans l'utilitaire fdisk...


- soit tu contrôles ce qui se passe autour, en particulier si tu es
supposément au milieu de ton programme et que celui-ci est censé avoir
le focus (donc qu'il ne vient pas de réaliser une opération de six
minutes sans donner aucun ressenti à l'utilisateur... mais je dérive),
et alors oui la bonne séquence c'est bien
1 - Saisir
2 - Nettoyer
(ce qui permet à l'utilisateur habitué d'anticiper dans le tampon
clavier ce qui va arriver).


Par ailleurs, dans une bibliothèque d'entrées-sorties bien conçue,
l'opération 2-Nettoyer devrait être gratuite (déjà faite) dans le cas
normal d'opération : cela évite une potentielle erreur au programmeur,
et aussi les effets de course, genre le système qui pique le focus entre
les deux opérations, le passe à un autre fil qui fait une opération
différente d'ES, et le repasse un quantum plus tard pour le nettoyage...
qui va mettre un max de boxon, puisqu'à contre-temps !


Antoine
Avatar
Antoine Leca
candide a écrit :
-ed- a écrit :
Faire entrer un 0 dans un stdin est AMA, un UB ...



"AMA" ?? c'est pour un sondage ou quoi ? Si tu crois que c'est un UB
donne chapitres et versets.



7.19.2p2 : stdin est un flux texte, donc son comportement n'est garanti
que pour les caractères imprimables, 't' et 'n'. '' ne fait pas
partie de cette liste, donc le comportement n'est pas défini.

En POSIX, les choses sont différentes, mais je n'ai pas été vérifié ce
qui se passe avec dans les flux d'entrées, je ne serais pas outre
mesure surpris que ce cas soit exclus pour que les implémentations aient
le droit d'être pourries sur ce point et qu'en même temps les
programmeurs évitent de tabler sur une possibilité qui est quand même
très piègeuse...

Par ailleurs, une bonne implémentation va accepter correctement des
en entrée (et la plupart des *nix aujourd'hui le font), et dnc un bon
programme se doit de prévoir ce qui peut se passer quand on lui envoie
des imprévus dans le flux.


Antoine
Avatar
Antoine Leca
candide a écrit :
Bon, je crois que tu ne comprends mon point de vue. Je ne dis pas pas
fgets() soit mal conçue ou inutile. Si les programmeurs compétents
disent en choeur depuis 20 ans que fgets() est une fonction adaptée à la
capture de lignes et que gets() est un bug, c'est qu'ils ont
certainement raison



En fait, gets() est à l'origine du plus gros bogue de l'internet (le ver
de Morris, à cause d'un gets() par vraiment sûr dans l'utilitaire finger
de BSD).

Dans les années 85-94, le contexte était alors à des machines bien moins
puissantes, les programmes étaient généralement considérés comme
uniformément ou généralement bénéfiques, et les ravages du ver de Morris
ont frappé les esprits mais cela n'a pas été interprété par tout le
monde comme la nécessité de revoir à fond toutes les méthodes de
programmation, surtout en C.

En 2001 puis en 2003 les programmeurs de Microsoft ont subi deux chocs
similaires (Code Red puis Slammer), qui les ont conduits à revoir en
profondeur leurs manières de programmer.

Aujourd'hui, les choses ont pas mal changées : ainsi le comité C (dont
pon peut penser ce que l'on veut, mais il y a là des gens qui savent un
peu de quoi ils parlent) est aujourd'hui très engagé dans la volonté de
rendre C « sûr » (je ne me prononcerais pas sur la qualité de leurs
solutions concrètes, par exemple aux problèmes de fgets()).


Antoine
Avatar
espie
In article <hdrjis$72p$,
Antoine Leca wrote:
Aujourd'hui, les choses ont pas mal changées : ainsi le comité C (dont
pon peut penser ce que l'on veut, mais il y a là des gens qui savent un
peu de quoi ils parlent) est aujourd'hui très engagé dans la volonté de
rendre C « sûr » (je ne me prononcerais pas sur la qualité de leurs
solutions concrètes, par exemple aux problèmes de fgets()).



S'ils etaient engages de facon pratique, ils auraient integre strlcpy et
strlcat a la prochaine version de la norme, au lieu des especes de monstres
de fonctions de chaine validees, que personne ne va utiliser tellement elles
sont lourdingues et malcommodes (et en plus, ne correspondent a aucun prior
art).
Avatar
Éric Lévénez
Antoine Leca a écrit :

7.19.2p2 : stdin est un flux texte, donc son comportement n'est garanti
que pour les caractères imprimables, 't' et 'n'. '' ne fait pas
partie de cette liste, donc le comportement n'est pas défini.



J'aime bien le "no new-line character is immediately preceded by space
characters"...

En 7.19.3p7 il est indiqué que stdin est un flux de texte au démarrage,
mais comme on peut changer cela juste après, qu'est-ce qui oblige dans
la norme stdin a être un flux texte après le démarrage du programme ?


--
Éric Lévénez
FAQ de fclc : <http://www.levenez.com/lang/c/faq/>
Avatar
Antoine Leca
Marc Espie écrivit :
(et en plus, ne correspondent a aucun prior art).



En fait si, c'est directement dérivé de ce que MS a fait dans VC++ 2005.

J'ai pas dit que je trouvai(s) cela extraordinaire, pas taper !


Antoine
Avatar
Antoine Leca
Éric Lévénez a écrit :
Antoine Leca a écrit :

7.19.2p2 : stdin est un flux texte, donc son comportement n'est
garanti que pour les caractères imprimables, 't' et 'n'. '' ne
fait pas partie de cette liste, donc le comportement n'est pas défini.



J'aime bien le "no new-line character is immediately preceded by space
characters"...



C'est dû aux implémentations qui ne savent enregistrer que des
enregistrements de taille fixe (genre mainframes des années 70), et qui
utilisent l'espace comme caractère de bourrage : le code de stdio est
alors prié de supprimer tout espace en fin de ligne ; ce qui fait qu'il
n'est pas possible de garder de manière perenne et portable des
caractères espace en fin de ligne.
D'un point de vue d'interface, je trouve cela plutôt bien, les espaces
en fin de ligne peuvent souvent être un problème et rarement une solution.


En 7.19.3p7 il est indiqué que stdin est un flux de texte au démarrage,
mais comme on peut changer cela juste après, qu'est-ce qui oblige dans
la norme stdin a être un flux texte après le démarrage du programme ?



7.19.5.4p3 dit que l'effet et les conditions de réussite de
freopen(NULL, mode, stream) sont définies par l'implémentation, ce qui
permet à une implémentation de ne pas permettre cette utilisation du
tout, et fait que tu ne peux pas te prévaloir de cette fonctionnalité de
manière portable.

Mais peut-ètre existe-t-il d'autres manières de changer le mode de stdin


Antoine
Avatar
espie
In article <hds4fl$rbe$,
Antoine Leca wrote:
Marc Espie écrivit :
(et en plus, ne correspondent a aucun prior art).



En fait si, c'est directement dérivé de ce que MS a fait dans VC++ 2005.

J'ai pas dit que je trouvai(s) cela extraordinaire, pas taper !



Ah ben je reformule ailleurs: c'est juste extraordinairement lourdingue
et mal foutu. M'etonne pas que ca vienne de chez crosoft.
Avatar
bpascal123
Bonjour/bonsoir,

Est-ce que fgets a un comportement différent selon l'OS (Djgpp
Microsoft xp ou Linux Gcc) ? Parce que sous Windows le pointeur se
trouve 1 position supplémentaire après la fin de la chaîne saisie ave c
fgets ce qui va en contradiction avec le premier post (peut-être j'ai
écrit le premier post sous linux et c'est pourquoi aujourd'hui je ne
me retrouve qu'une position après au lieu de 2.

Si quelqu'un peut m'aider. J'ai le sentiment de passer beaucoup de
temps sur point particulier qui ne devrait pas avoir d'importance pour
un débutant car à un niveau plus élevé, la saisie se fait de mani ère
très rigoureuse avec flush ou getchar =''n' ....

Merci,

Pascal
Avatar
Samuel Devulder
a écrit :

Si quelqu'un peut m'aider. J'ai le sentiment de passer beaucoup de
temps sur point particulier qui ne devrait pas avoir d'importance pour
un débutant car à un niveau plus élevé, la saisie se fait de manière
très rigoureuse avec flush ou getchar =''n' ....



Tu t'es laissé noyé dans les querelles un peu vaines de spécialistes qui
on fait dériver le fil loin, très loin, de ton pb initial. Si tu
pouvais (re)poster l'essentiel du code pour qu'on rappelle correctement
ton histoire de -1 / -2? Parce que selon moi ton pb est simple et la
solution avait été donnée très tot dans le fil: buffer contenant
"abcdn" et donc d est à l'offset -2 par rapport à la position du ''.

sam.