[debutant] - Probleme de saisie avec fgets.

- Probleme de saisie avec fgets. [debutant] - C - Programmation

Marsh Posté le 03-11-2005 à 23:49:48    

Bonsoir
 
J'ai un petit programme, pour repondre a un exos, qui permet de saisir une structure (nom, prenom, age, n° secu).
Bon,donc mon probleme vient de la saisie des ces valeurs.
 
La structure est declare en parametres general comme suit :

 
struct identity {
char nom[15];
char prenom[10];
int age;
int secu;
struct identity *next;
}st,tmp;


 
Bon, ensuite dans mon main, j'appele ma fonction saisie qui est :


void saisie (char *anu_secu)  
 
{
 
 FILE *fp;
 char temp[10];
 
 printf("Informations :\n" );
 
 printf("==============\n" );
 
 
 printf ("Nom\t\t : " );
 fgets(st.nom, sizeof(st.nom), stdin);
 fflush (stdout);
 
 
 
     
 
 printf ("Prenom\t\t : " );
 
 fgets(st.prenom, sizeof(st.prenom), stdin);
 
 fflush(stdout);
 
 
 
 printf ("Age\t\t : " );
 
 fgets(temp, sizeof(temp), stdin);
 st.age = strtol(temp, NULL, 10);
 
 fflush(stdout);
 
 
 
 printf ("Numero de secu\t : " );
 
 fgets(temp, sizeof(temp), stdin);
 st.secu = strtol(temp, NULL, 10);
 
 fflush(stdout);
}


 
Alors le probleme vient du fait que, lorsque j'arrive sur cette fonction  au lieu de demander le nom, attendre la saisie, et demander le prenom. J'ai un affichage comme suit :


Informations :
==============
Nom              : Prenom                :


 
En fait il affiche la ligne "prenom", alors que j'ai pas encore rentre le nom.
 
Ps : les librairies utilisés sont :   stdio, stdlib, et ncurses.
Compilateur gcc-4.0.1 (linux)
 
Merci de votre aide


Message édité par le fou le 03-11-2005 à 23:53:55

---------------
Celui qui sauve une vie, sauve l'humanité (Le Talmud) - Personne n'a plus grand amour que celui de donner sa vie pour ses amis (Jean XV, 13)
Reply

Marsh Posté le 03-11-2005 à 23:49:48   

Reply

Marsh Posté le 04-11-2005 à 01:22:16    

printf("..." );
fflush(stdout);
fgets( .... );
 
 
il ne serait peut être pas mauvais de vérifier que fgets ne renvoit pas NULL (auquel cas fin de fichier / erreur)

Reply

Marsh Posté le 04-11-2005 à 01:26:25    

Taz a écrit :

printf("..." );
fflush(stdout);
fgets( .... );
 
 
il ne serait peut être pas mauvais de vérifier que fgets ne renvoit pas NULL (auquel cas fin de fichier / erreur)


 
Non, meme en mettant le fflush entre le printf et le fgets ca ne marche pas.
 
Ce que je ne comprends pas , c'est que si j'utilise un scanf a la place de fgets, je n'ai pas ce probleme la.


---------------
Celui qui sauve une vie, sauve l'humanité (Le Talmud) - Personne n'a plus grand amour que celui de donner sa vie pour ses amis (Jean XV, 13)
Reply

Marsh Posté le 04-11-2005 à 01:49:31    

montre ton code corrigé.

Reply

Marsh Posté le 04-11-2005 à 01:54:30    

Voila l'ensemble de mon code, si j'avais oublie une ligne, et que ce soit elle qui fasse planter :
 

Code :
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <ncurses.h>
  4. struct identity {
  5. char nom[15];
  6. char prenom[10];
  7. int age;
  8. int secu;
  9. }st,tmp;
  10. void saisie (char *anu_secu)
  11. {
  12. FILE *fp;
  13. char temp[10];
  14. puts("Informations :" );
  15. puts("==============" );
  16. printf ("Nom\t\t : " );
  17. fflush (stdout);
  18. fgets(st.nom, sizeof st.nom, stdin);
  19.  printf ("Prenom\t\t : " );
  20. fflush (stdout);
  21. fgets(st.prenom, sizeof st.prenom, stdin);
  22. printf ("Age\t\t : " );
  23.         fflush(stdout);
  24.         fgets(temp, sizeof(temp), stdin);
  25. st.age = strtol(temp, NULL, 10);
  26. printf ("Numero de secu\t : " );
  27.         fflush(stdout);
  28. fgets(temp, sizeof(temp), stdin);
  29. st.secu = strtol(temp, NULL, 10);
  30. //ECRITURE DU NOM
  31. puts ("ouverture du fichier en cours.." );
  32. fp=fopen (anu_secu,"a+" );
  33. puts("\nEcriture du nom dans le fichier" );
  34. fprintf (fp, "%s",st.nom);
  35. fprintf(fp,"\n" );
  36. //ECRITURE DU PRENOM
  37. puts("\nEcriture du nom dans le fichier" );
  38. fprintf (fp, "%s",st.prenom);
  39. fprintf(fp,"\n" );
  40. // ECRITURE DE L AGE
  41. puts("\nEcriture de l'age dans le fichier" );
  42. fprintf (fp, "%d",st.age);
  43. fprintf(fp,"\n" );
  44.         // ECRITURE DU NUMERO DE SECU
  45. puts("\nEcriture du numero de secu dans le fichier" );
  46. fprintf (fp, "%d",st.secu);
  47. fprintf(fp,"\n" );
  48. puts("\nFermeture du fichier" );
  49. fclose(fp);
  50. }
  51. void visu (char *anu_secu)
  52. {
  53. FILE *fp;
  54. printf("Nom desire\t: " );
  55. scanf("%s",tmp.nom);
  56. getchar();
  57. puts ("ouverture du fichier en cours.." );
  58. fp=fopen (anu_secu,"r+" );
  59. fseek (fp,0,SEEK_SET);
  60. //RECHERCHE
  61. while (strcmp(tmp.nom,st.nom)!=0) {
  62.  fscanf(fp,"%[^\n]\n",st.nom);
  63.  fscanf (fp,"%[^\n]\n",tmp.prenom);
  64.  fscanf (fp,"%d[^\n]\n",&tmp.age);
  65.  fscanf (fp,"%d[^\n]\n",&tmp.secu);
  66. }
  67. //AFFICHAGE
  68. system("clear" );
  69. puts("Informations : " );
  70. puts("===============" );
  71. puts("\n" );
  72. printf("Nom\t\t : %s\n",tmp.nom);
  73. printf("Prenom\t\t : %s\n",tmp.prenom);
  74. printf("Age\t\t : %d\n",tmp.age);
  75. printf("Numero de secu\t : %d\n",tmp.secu);
  76. getchar();
  77. }
  78. int main (void)
  79. {
  80. char *anu_secu="/home/beware/TPC/anu_secu.txt";
  81. char *tmp="/home/beware/TPC/tmp.txt";
  82. int c=0;
  83. char temp[2];
  84. while (c != 3)
  85. {
  86. system("clear" );
  87. printf("\t\t{-------------------MENU-------------------}\n" );
  88. printf("\t\t{                                          }\n" );
  89. printf("\t\t{                                          }\n" );
  90. printf("\t\t{     1 - Saisir une nouvelle fiche        }\n" );
  91. printf("\t\t{     2 - Visualiser les fiches            }\n" );
  92. printf("\t\t{     3 - Quitter                          }\n" );
  93. printf("\t\t{                                          }\n" );
  94. printf("\t\t{------------------------------------------}\n" );
  95. puts("\n\n\n" );
  96. printf("Choix : " );
  97. fflush(stdout);
  98. fgets(temp, sizeof(temp), stdin);
  99. c = strtol(temp, NULL, 10);
  100. system("clear" );
  101. if (c==1)
  102. {
  103.         saisie(anu_secu);
  104. }
  105. else if (c==2)
  106. {
  107.  visu(anu_secu);
  108. }
  109. }
  110. }


Message édité par le fou le 04-11-2005 à 01:58:01

---------------
Celui qui sauve une vie, sauve l'humanité (Le Talmud) - Personne n'a plus grand amour que celui de donner sa vie pour ses amis (Jean XV, 13)
Reply

Marsh Posté le 04-11-2005 à 04:33:32    

1) <ncruses.h> ne te sert à rien. manque <string.h>.
2) // commentaire C++, pas C
3) char *anu_secu = "/home/beware/TPC/anu_secu.txt"; mauvais
   const char *anu_secu = "/home/beware/TPC/anu_secu.txt"; OK
4) t'as le droit de grouper tes prinfs
 
   printf("ligne1\n"
           "ligne2\n"
           ... );
 
 
5) et enfin :
fgets(temp, sizeof(temp), stdin);
 
bravo tu as lu 2 caractère. Un chiffre (espérons le) et un '\0' sont désormais dans temp. Et l'\n' il est passé où ? il est toujours dans le buffer ! Résultat, le prochain fgets il lit une ligne vide (ce qui lui convient très bien). Bon vu ton niveau, on a qu'à dire "agrandit temp" à 80caratères.

Reply

Marsh Posté le 04-11-2005 à 04:33:54    

ah oui : pourquoi des variables globales ...

Reply

Marsh Posté le 04-11-2005 à 06:51:51    

Taz a écrit :

2) // commentaire C++, pas C


 
// est un commentaire C valable en C99 (m'étais fait avoir aussi).

Reply

Marsh Posté le 04-11-2005 à 11:59:49    

Taz a écrit :


1) <ncruses.h> ne te sert à rien. manque <string.h>.
2) // commentaire C++, pas C
3) char *anu_secu = "/home/beware/TPC/anu_secu.txt"; mauvais
   const char *anu_secu = "/home/beware/TPC/anu_secu.txt"; OK


Mais quand j'appele ma fonction :
saisie(anu_secu);
Il me dit que le parametre anu_secu n'est pas bon.
 

Taz a écrit :


4) t'as le droit de grouper tes prinfs
 
   printf("ligne1\n"
           "ligne2\n"
           ... );


 
D'accord je savais pas qu'il etait possible de faire ca.
merci
 

Taz a écrit :


5) et enfin :
fgets(temp, sizeof(temp), stdin);
 
bravo tu as lu 2 caractère. Un chiffre (espérons le) et un '\0' sont désormais dans temp. Et l'\n' il est passé où ? il est toujours dans le buffer ! Résultat, le prochain fgets il lit une ligne vide (ce qui lui convient très bien). Bon vu ton niveau, on a qu'à dire "agrandit temp" à 80caratères.


 
Ah oui je comprends mieux pourquoi alors je sautais une saisie. En fait ormis, le cas du temp pas assez grand, je pensais naivement que le fflush vidait le buffer d'entree et donc empechait qu' un \n ne s'y trouve. Mais apparement c'est pas ca.
 
 
PS :  
merci beaucoup pour ton aide.
 
La variable globale n'a rien a faire, il est vrai il faut que je l'integre dans mon main, et que je balance les pointeurs quand j'en ai besoin.
 


---------------
Celui qui sauve une vie, sauve l'humanité (Le Talmud) - Personne n'a plus grand amour que celui de donner sa vie pour ses amis (Jean XV, 13)
Reply

Marsh Posté le 04-11-2005 à 12:27:26    

Lorsque je fais un fgets pour ma saisie au clavier, je capture donc le \n.
 
Y  a til un moyen, ormis faire une boucle pour le detecter, de ne pas ecrire le \n dans le fichier?


---------------
Celui qui sauve une vie, sauve l'humanité (Le Talmud) - Personne n'a plus grand amour que celui de donner sa vie pour ses amis (Jean XV, 13)
Reply

Marsh Posté le 04-11-2005 à 12:27:26   

Reply

Marsh Posté le 04-11-2005 à 12:51:25    

le fou a écrit :

Lorsque je fais un fgets pour ma saisie au clavier, je capture donc le \n.
 
Y  a til un moyen, ormis faire une boucle pour le detecter, de ne pas ecrire le \n dans le fichier?


 
Oui, en utilisant par exemple strrchr() qui retourne un pointeur sur un caractère recherché dans une chaîne.

Reply

Marsh Posté le 04-11-2005 à 13:07:25    

Elmoricq a écrit :

Oui, en utilisant par exemple strrchr() qui retourne un pointeur sur un caractère recherché dans une chaîne.


 
 
Merci beaucoup
ca marche.


---------------
Celui qui sauve une vie, sauve l'humanité (Le Talmud) - Personne n'a plus grand amour que celui de donner sa vie pour ses amis (Jean XV, 13)
Reply

Marsh Posté le 04-11-2005 à 21:58:58    

y'a plus simple :
 
char* chaine = "Coucou\n";
 
chaine[strlen(chaine)-1] = '\0'; // On raccourcit la chaine de 1 caractere pour virer le \n


---------------
char table[] = {112,114,105,110,116,102,40,34,37,99,37,99,37,99,34,44,49,49,48,44,49,48,56,44,57,57,41,59,0}; char* tablePtr = table; while(*tablePtr) printf( "%c",*tablePtr++ );
Reply

Marsh Posté le 04-11-2005 à 22:00:03    

...

Reply

Marsh Posté le 04-11-2005 à 22:06:00    

Ca pourrait bugguer si la chaine etait vide, mais comme elle vient d'un fgets, on recupe forcement au moins un caractere, le \n
 
Donc tu peux faire :
 
fgets(st.prenom, sizeof st.prenom, stdin);
st.prenom[strlen(st.prenom)-1] = '\0'; // Vire le \n


---------------
char table[] = {112,114,105,110,116,102,40,34,37,99,37,99,37,99,34,44,49,49,48,44,49,48,56,44,57,57,41,59,0}; char* tablePtr = table; while(*tablePtr) printf( "%c",*tablePtr++ );
Reply

Marsh Posté le 04-11-2005 à 22:35:51    

nlc a écrit :

Ca pourrait bugguer si la chaine etait vide, mais comme elle vient d'un fgets, on recupe forcement au moins un caractere, le \n
 
Donc tu peux faire :
 
fgets(st.prenom, sizeof st.prenom, stdin);
st.prenom[strlen(st.prenom)-1] = '\0'; // Vire le \n


 
[:mlc]
 
man fgets :
 

Citation :

The fgets() function shall read bytes from stream into the array pointed to by s, until n-1 bytes are read, or a <newline> is read and transferred to s, or an end-of-file condition is encountered. The string is then terminated with a null byte.


 
Ta chaîne n'est pas obligatoirement terminée par un '\n'.
 
Tiens et puis pour rire, tape directement CTRL+C (ou CTRL+D sous Unix) à la saisie de ta chaîne, comme ça, pour rire. [:itm]


Message édité par Elmoricq le 04-11-2005 à 22:36:55
Reply

Marsh Posté le 04-11-2005 à 23:43:01    

Si on fait un control C sur un fgets( temp, sizeof(temp), stdin ) ca coupe completement le programme.
 
Ensuite, si le fgets a lu n-1 octets, c'est qu'il arrive en bout de buffer, donc il s'arrete pour se reserver un octet pour mettre le 0 de fin de chaine.
 
Ce que je voulais dire plus haut, c'est qu'il ne faut pas faire un st.prenom[strlen(st.prenom)-1] = '\0' sur une chaine vide, sinon ca ecrit hors de la zone st.prenom.
 
Mais avec un fgets( temp, sizeof(temp), stdin ), y'a peu de chance pour que la chaine temp fasse 0 !
 
Edit : Ah ! Autant pour moi, le Ctrl D renvoit bien 0 (si on a rien tapé avant), donc pour etre blindé faut faire un test.
Ou mieux, utiliser strchr()  :whistle:
 
[:anathema]
 


Message édité par nlc le 05-11-2005 à 00:05:06

---------------
char table[] = {112,114,105,110,116,102,40,34,37,99,37,99,37,99,34,44,49,49,48,44,49,48,56,44,57,57,41,59,0}; char* tablePtr = table; while(*tablePtr) printf( "%c",*tablePtr++ );
Reply

Marsh Posté le 05-11-2005 à 12:21:38    

nlc a écrit :

y'a plus simple :
 
char* chaine = "Coucou\n";
 
chaine[strlen(chaine)-1] = '\0'; // On raccourcit la chaine de 1 caractere pour virer le \n


Non, une chaine n'est pas modifiable.
 


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 05-11-2005 à 12:23:45    

nlc a écrit :

Ca pourrait bugguer si la chaine etait vide, mais comme elle vient d'un fgets, on recupe forcement au moins un caractere, le \n
 
Donc tu peux faire :
 
fgets(st.prenom, sizeof st.prenom, stdin);
st.prenom[strlen(st.prenom)-1] = '\0'; // Vire le \n


Non.
 
La seule méthode reconnue pour éliminer le '\n' est le search'n kill.


char *p = strchr(s, '\n');
 
if (p != NULL)
{
   *p = 0;
}


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 07-11-2005 à 23:14:41    

bonsoir
est il possible de tester si le nombre de caractere rentre lors d'un fgets est compatible avec la capacité du tableau?


---------------
Celui qui sauve une vie, sauve l'humanité (Le Talmud) - Personne n'a plus grand amour que celui de donner sa vie pour ses amis (Jean XV, 13)
Reply

Marsh Posté le 07-11-2005 à 23:21:26    

fgets() ne va pas plus loin que la taille maximum - 1 (pour le caractère '\0' terminal) que tu lui passes en paramètre (et il s'arrête avant s'il rencontre un saut de ligne, ou une fin de fichier).  
 
C'est à toi de passer le bonne taille max.

Message cité 1 fois
Message édité par Elmoricq le 07-11-2005 à 23:22:04
Reply

Marsh Posté le 07-11-2005 à 23:25:30    

Elmoricq a écrit :

fgets() ne va pas plus loin que la taille maximum - 1 (pour le caractère '\0' terminal) que tu lui passes en paramètre (et il s'arrête avant s'il rencontre un saut de ligne, ou une fin de fichier).  
 
C'est à toi de passer le bonne taille max.


 
Oui mais dans le cas, d'une saisie au clavier, par exemple
L utilisateur ne sait pas forcement le nombre max de caractere qui lui est permis de rentrer.
Doit on alors, prevoir plus de place pour le stockage, ou peut ton tester la longueur de la chaine rentre, (par exemple en verifiant, si aucun /n n'apparait dans la chaine stocké?)


---------------
Celui qui sauve une vie, sauve l'humanité (Le Talmud) - Personne n'a plus grand amour que celui de donner sa vie pour ses amis (Jean XV, 13)
Reply

Marsh Posté le 08-11-2005 à 08:08:44    

le fou a écrit :

Oui mais dans le cas, d'une saisie au clavier, par exemple
L utilisateur ne sait pas forcement le nombre max de caractere qui lui est permis de rentrer.
Doit on alors, prevoir plus de place pour le stockage, ou peut ton tester la longueur de la chaine rentre, (par exemple en verifiant, si aucun /n n'apparait dans la chaine stocké?)


Si il est bien utilisé, fgets() ne permettra pas le débordement. Si une tentative de débordement a eu lieu, le '\n' n'est pas présent dans la chaine. Les caractères nons lus seront encore à disposition dans stdin. Il suffit de rappeler fgets() pour lire la suite. On peut aussi les ignorer en bouclant sur stdin avec fgetc(), par exemple, jusquà detection de '\n' ou de EOF.
 
http://mapage.noos.fr/emdel/notes.htm#saisie
http://mapage.noos.fr/emdel/notes.htm#fichiers
 
A l'aide d'une combinaison astucieuse de realloc(), de fgets() (ou de fgetc()) et d'une boucle, on peut saisir une ligne de longueur arbitraire.
 
Bref, il y a plusieurs possibilités. Il est conseillé de les recenser et d'écrire les fonctions correspondantes une bonne fois pour toutes.
 
http://mapage.noos.fr/emdel/clib.htm
Module IO


Message édité par Emmanuel Delahaye le 08-11-2005 à 08:12:10

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed