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

1 2 3 4 5
Avatar
espie
In article <hd18ve$63s$,
Marc Boyer wrote:
Le 06-11-2009, Marc Espie a écrit :
In article <hd11j5$3ck$,
Un moyen pédogogique clair pour indiquer aux étudiants qu'on
commence par raisonner dans un monde gentil, puis qu'on passera
aux choses sérieuses par la suite.



C'est debile. Passer cinq minutes a "je valide ce qui a ete entre, si
c'est pas bon -> abort", c'est quand meme pas serieux.



Sauf que ça suppose que tu explique clairement ce qu'est une erreur,
la notion de fin de flux (toujours un bon moment à expliquer la fin
du clavier), ce qui nous ammène à EOF qui est un entier mais pas un
char, etc...

Tu te souviens qu'un débutant, ça a du mal à trouver le min et
le max dans un tableau de taille fixe ?

Donc, oui, dans mon cours il y avait "les E/S sont gentilles,
faisons de l'algorithmique de base", et puis plus loin "bienvenue
dans le monde réel".



Dans mon cours, il y a "les fonctions d'entree ont un code d'erreur, meme
si on reprend un idiome tout pret, le minimum syndical, c'est erreur -> abort".
Avatar
Marc Boyer
Le 06-11-2009, Marc Espie a écrit :
In article <hd18ve$63s$,
Marc Boyer wrote:
Donc, oui, dans mon cours il y avait "les E/S sont gentilles,
faisons de l'algorithmique de base", et puis plus loin "bienvenue
dans le monde réel".



Dans mon cours, il y a "les fonctions d'entree ont un code d'erreur, meme
si on reprend un idiome tout pret, le minimum syndical, c'est erreur
-> abort".



Et c'est quoi le code d'erreur de scanf ? Et pourquoi getc ne retourne pas
un char ? Et ça veut dire quoi que la valeur de retour est "unsigned char
cast to an int" ?

Non, les codes de retour, c'était la partie "maintenant, on fait attention",
et ça va aussi avec les retours de malloc, etc.

Marc Boyer
--
En prenant aux 10% des francais les plus riches 12% de leurs revenus,
on pourrait doubler les revenus des 10% les plus pauvres.
http://www.inegalites.fr/spip.php?article1&id_mot0
Avatar
espie
In article <hd1ikf$a7p$,
Marc Boyer wrote:
Le 06-11-2009, Marc Espie a écrit :
In article <hd18ve$63s$,
Marc Boyer wrote:
Donc, oui, dans mon cours il y avait "les E/S sont gentilles,
faisons de l'algorithmique de base", et puis plus loin "bienvenue
dans le monde réel".



Dans mon cours, il y a "les fonctions d'entree ont un code d'erreur, meme
si on reprend un idiome tout pret, le minimum syndical, c'est erreur
-> abort".



Et c'est quoi le code d'erreur de scanf ? Et pourquoi getc ne retourne pas
un char ? Et ça veut dire quoi que la valeur de retour est "unsigned char
cast to an int" ?



Ben, on fait ca fonction par fonction, en expliquant comment marche la fonction
ou ce qu'il faut faire avec.

Pour scanf, c'est quand meme tres simple: ca renvoie le nombre de valeurs
converties avec succes, et autre chose en cas de pepin.

C'est pas dur de faire

r = scanf("%d", &d);
if (r != 1) {
fprintf(stderr, "Chef, on a un problemen");
abort();
}

Pour getc: expliquer getc avant de parler d'EOF, ca me parait aberrant.

Dans le pire des cas, je suis pret a leur donner un idiome qui marche,
a utiliser tel quel, quitte a expliquer certains details apres...
Avatar
candide
Marc Boyer a écrit :

Et c'est quoi le code d'erreur de scanf ? Et pourquoi getc ne retourne pas
un char ? Et ça veut dire quoi que la valeur de retour est "unsigned char
cast to an int" ?





Ici et dans tes messages précédents, tu as parfaitement traduit les
réactions des étudiants (et encore d'étudiants qui réagissent !)


Non, les codes de retour, c'était la partie "maintenant, on fait attention",
et ça va aussi avec les retours de malloc, etc.




Absolument. Question de progressivité qui s'impose pour moi comme une
évidence.
Avatar
candide
Marc Espie a écrit :
In article <4af3831b$0$748$,
candide wrote:
A part ça, fgets() est tellement bien pensée que la première chose qu'on
fait c'est de ... la recoder. Et c'est une pratique générale à ce que
j'ai pu constater.



Grave n'importe quoi. C'est totalement inexact.

fgets() respecte les principes de conception de la libc. En particulier,
elle ne gere *pas* la memoire de l'utilisateur (ce qui se passe dans les
tampons internes des fichiers). Du coup, dans enormement de cas de figure,
pour faire quelque chose de robuste et tout terrain, il faut utiliser fgets
plus un allocateur memoire (celui de la libc par exemple, mais pas toujours).




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 et un bon programmeur doit s'y plier. Qu'il soit à
la charge du programmeur de gérer la mémoire du tampon ne me choque pas
du tout.

Ce que je dis, c'est que contrairement à ce que vous pensez, fgets() est
une fonction compliquée à comprendre par les débutants (débutants ça va
jusqu'à L3 Info, oui !). Ce qui m'affole c'est que vous (-ed- et toi)
n'arriviez pas à concevoir cette difficulté. Alors tu as peut-être en
face de toi des étudiants en école d'ingénieurs en _informatique_ (et
donc qui a priori doivent bouffer du C/C++) et qui sont peut-être assez
doués mais sache qu'un étudiant à la fac en L1 de sciences de
l'ingénieur (= physique-chimie-meca), il a énormément de mal avec le C
de même qu'un élève dans une écoles d'ingénieurs généralistes qui doit
passer sous les fourches caudines du C.




sur fgetln s'il est disponible. Ca n'est pas tres complique. A mon sens,
c'est a la portee de n'importe quel programmeur C competent.



Oui, donc on ne parle pas des mêmes personnes. Oui bien utiliser fgets()
ou savoir utiliser une fonction équivalente proposée par une
bibliothèque fait partie du boulot d'un programmeur C (au sens large).
Avatar
candide
Marc Espie a écrit :


C'est pas une raison pour lui donner des trucs faux.






Fondamentalement, je milite pour une censure des entrées/sorties
ou tout du moins un usage contrôlé et limité et de
leur donner une fonction :



*) ludique (jeu en console, éviter la recompilation
systématique lors du "test")

*) utilitaire (et à ce moment pas d'entrées sur l'entrée standard qui
est super-casse gueule et de toute façon peu commode) pour pouvoir
récupérer des entrées en grand nombre (un lexique, un graphe, etc) ou
produire des sorties de taille importante

Disons que dans l'apprentissage du langage C, pour moi, la maitrise des
entrées n'est pas prioritaire et cela résulte d'une évidence : connaître
le contenu de stdio.h nécessite de bien connaître le langage
(d'ailleurs, ce n'est pas pour rien que la Norme sépare le langage de
la bibliothèque). Dans mon auto-formation du C, je me rends compte
que finalement, avoir essayé de comprendre des fonctions standard de
stdio.h ou string.h n'a fait que ralentir ma progression un peu comme
si je courais deux lièvres à la fois.





Chez toi, peut-etre. Chez moi, non. Une gestion d'erreur minimale, ca n'est
pas complique: juste dire que c'est pas bon et quitter. C'est le minimum
vital aujourd'hui. Si tu apprends du C, on n'est plus il y a quinze ans,
et il faut des le debut eviter que tes debutants fassent du trou de securite
au kilometre.




Je comprends ton point de vue et si tes étudiants n'en sont pas
troublés, il n'y a aucune raison de s'en priver. Pour moi, les
entrées ne sont qu'un prétexte et sont un domaine à part. Mélanger les
deux en début d'apprentissage, c'est de la surcharge, tel est mon avis
en tous cas.





C'est pas parce que les gens qui font Cpython ne savent pas lire OU essaient
de faire des trucs tres bizarres que fgets est mauvais. C'est pourtant tres
simple d'emploi comme fonction si on sait lire.





Simple une fois qu'on a compris comme dirait monsieur de lapalisse.
Moi, ce n'est pas comme ça que je mesure la difficulté de compréhension.
je pense que l'acquisition des mécanisme de fgets() cause
majoritairement un trouble, le témoignage du codeur de CPython qui
assurément est un codeur expérimenté en témoigne et il te suffit de
parcourir les archives de ce forum et d'autres forums pour comprendre
que c'est une réalité.


Les entrees sont compliquees. C'est le cas dans tous les langages.
Il faudra bien tot ou tard l'expliquer a tes debutants.




Bof, ça dépend à qui tu t'adresses. Il y a
énormément de gens qui ne font du C qu'à
l'école ou à la fac.






Mais sortir gets de sa poubelle, surtout avec tous les arguments
fallacieux que tu avances:
1/ c'est grotesque
2/ c'est une faute qui peut avoir des consequences graves.





Oui, je comprends que tu sois irrité par ce que j'ai dit toi qui
es sensible aux questions de sécurité.


Perso, j'aimerais bien que l'incidence des trous de securite diminue
dans ces prochaines annees, donc si tu pouvais arreter d'enseigner le C,
au fond, ca serait pas plus mal...




Je n'enseigne pas le C ni l'informatique d'ailleurs. Mais j'ai pu faire
des TP de graphes à des étudiants (math et infos) qui avaient un ou deux
ans ans de C, et le résultat n'était vraiment pas brillant, et il ne
s'agit pas de déficiences dans la connaissance des E/S mais tout
simplement dans le langage. Et cela concernait aussi les étudiants qui
avait fait un parcours parallèle genre BTS voire IUT.
Avatar
candide
-ed- a écrit :
On 6 nov, 02:59, candide wrote:
Tiens à propos, tu parles de fgets() dans "ta" faq sur developpez :



Ma FAQ ?



J'ai écrit :

"ta" faq

tu as vu les guillemets ? tu connais la sémantique des guillemets en
français ?

Par ailleurs, tu es le rédacteur de la réponse, Celui Qui Sait. Donc Tu
assumes Tes Erreurs, en particulier Ton prototype de fgets() est faux,
ça la fout mal quand on prétend enseigner fgets().


Si il y a une erreur, il suffit de la signaler.



Faudrait aussi les corriger. T'as corrigé sur ton site la grossière
erreur que contient ta fonction de comparaison d'entiers pour qsort() ?


Qui ne fait pas
d'erreurs...



Pas toi ;)



Sinon, tes explications sont imbitables pour celui qui ne connait pas,
c'est vraiment d'une confusion ...



Il n'est de pire sourd que celui qui ne veut rien entendre ...



Non j'ai lu et relu tes explications, c'est vraiment le degré zéro.


A part ça, fgets() est tellement bien pensée que la première chose qu'on
fait c'est de ... la recoder. Et c'est une pratique générale à ce que
j'ai pu constater.



Bof, on peut très bien utiliser fgets() telle quelle. Il suffit de la
faire suivre par une fonction de nettoyage adéquate. C'est largement
suffisant pour faire du code rapidement et simplement (étudiants,
petits projets...) On peut aussi, si on préfère combiner les deux
fonctions en une seule. C'est peut être ce que tu appelles
'recoder'...




Oui, elle ne se suffit pas à elle-même pour les besoins les plus triviaux.



Mais on peut aussi recoder complétement une fonction de saisie de
lignes. Je l'ai fait dans ma CLIB (fget_line()). Elle utilise un
tableau dynamique automatique qui fait qu'on a plus de problèmes de
tailles... Reste à penser à libérer le buffer alloué...



Tu crois m'impressionner ...

Dans ta fonction read_stdin(), tu utilises strchr(), pourtant il est



Oui, car c'est la seule façon simple de déterminer si le 'n' est
présent ou non et d'agir en conséquence.



Non, ce n'est pas la seule façon.


quand même moins couteux d'utiliser strlen() et de se placer en avant



Certainement pas. strchr() fait une boucle qui s'arrête au premier
caractère trouvé ou au 0 final. strlen() fait une boucle qui s'arrête
au zéro final. Tu vois la différence ?



Vu la spécification de fgets(), le 'n' arrive à la fin s'il arrive.
Donc a priori ton strchr() fait deux fois plus de boulot que strlen()
puisque strchr() doit tester deux caractères ('n' et contrôler la
sortie de la chaîne). Bon effectivement, ça c'est la théorie mais en
pratique les temps sont équivalents donc je retire ma remarque.


si il y a un 'n' ... Bref, de la complication inutile. Je commence à
comprendre pourquoi tu trouves ça compliqué.



Tu ne peux pas comprendre, question d'empathie.

SI tu n'utilises pas les
méthodes simples, c'est sûr que tout devient plus complexe...




C'est une méthode plus simple car je sais que le 'n' est à la fin même
si ton code est plus canonique.
Avatar
candide
-ed- a écrit :


Apprendre fgets correctement est un cauchemar, pas simplement pour le



Mais non. Peut être que tu as du mal, mais la plupart y arrivent.




Explique-nous donc le comportement (effets de bord, retour) de fgets()
lorsque son deuxième argument vaut 1.
Avatar
candide
Marc Espie a écrit :

Mais sortir gets de sa poubelle, surtout avec tous les arguments
fallacieux que tu avances:
1/ c'est grotesque
2/ c'est une faute qui peut avoir des consequences graves.




Le Rationale est pourtant bien modéré concernant cette fonction :

The Committee decided that gets was useful and convenient in those
special circumstances when the programmer does have adequate control
over the input, and as longstanding existing practice, it needed a
standard specification.
Avatar
espie
In article <4af4a2cc$0$438$,
candide wrote:
Ce que je dis, c'est que contrairement à ce que vous pensez, fgets() est
une fonction compliquée à comprendre par les débutants (débutants ça va
jusqu'à L3 Info, oui !). Ce qui m'affole c'est que vous (-ed- et toi)
n'arriviez pas à concevoir cette difficulté. Alors tu as peut-être en
face de toi des étudiants en école d'ingénieurs en _informatique_ (et
donc qui a priori doivent bouffer du C/C++) et qui sont peut-être assez
doués mais sache qu'un étudiant à la fac en L1 de sciences de
l'ingénieur (= physique-chimie-meca), il a énormément de mal avec le C
de même qu'un élève dans une écoles d'ingénieurs généralistes qui doit
passer sous les fourches caudines du C.



Non, j'ai des mecs qui ne sont pas specialement plus doues que les tiens.
Simplement, je sais que je vais les lacher dans la nature pour de vrai, et
qu'ils vont pondre du vrai code qui va etre utilise. Ma mission n'est pas
juste qu'ils comprennent, mais de faire ce que je peux pour qu'ils pondent
du code qui marchent.

Comme je sais tres bien qu'un etudiant retient surtout ce qui l'arrange,
je sais tres bien que, si je lui explique d'abord comment faire des trucs
simples qui ne marchent pas vraiment, puis des trucs plus compliques qui
fonctionnent, il va retenir la premiere version et se depecher d'oublier
la 2e. Donc c'est un point sur lequel je suis inflexible. Et tant pis si
ca va un peu moins vite et si on n'a pas vu toutes les subtilites du
langage a l'arrivee.

J'essaie de leur apprendre comment faire du code qui fonctionne. Pas
forcement du code super-astucieux. Pas forcement des algorithmes super-precis
et relativement tordus. Je ne vois pas pourquoi je ne leur dirais pas que
les entrees-sorties, c'est complique, et que pour un programme qui interagit
avec l'utilisateur, le programmeur va passer facilement 40% de son temps a
faire marcher correctement les dites interactions (en particulier, a valider
les entrees et a s'assurer qu'il n'y a aucune ambiguite pour l'utilisateur).

Si tu veux d'autres exemples, je passe aussi pas mal de temps sur les tableaux,
et je leur dis systematiquement que, dans le doute, il faut verifier l'index
avant d'acceder a un element de tableau. Ou sinon, essayer de faire plus
simple dans le code. Je leur dis aussi qu'ils ne seront pas evalues sur les
astuces tordues qu'ils peuvent mettre dans leur code, bien au contraire. Que
c'est plus difficile de faire du code simple et clair.

Dans un autre ordre d'idees, en programmation OO, je vois passer des tas
d'etudiants qui ont tres bien retenu toutes les subtilites de l'heritage
et qui savent quand les arguments seront co/contra-variants, mais qui degainent
l'heritage pour absolument tout, et me font des classes valises la ou la
composition est l'outil approprie. Ou bien qui ne connaissent pas des pattern
aussi utiles que Template Method ou Compiler Firewall...
1 2 3 4 5