Fgets non funziona dopo scanf

#include  #include  #include  void delspace(char *str); int main() { int i, loops; char s1[101], s2[101]; scanf("%d", &loops); while (loops--) { fgets(s1, 101, stdin); fgets(s2, 101, stdin); s1[strlen(s1)] = '\0'; s2[strlen(s2)] = '\0'; if (s1[0] == '\n' && s2[0] == '\n') { printf("YES\n"); continue; } delspace(s1); delspace(s2); for (i = 0; s1[i] != '\0'; i++) s1[i] = tolower(s1[i]); for (i = 0; s2[i] != '\0'; i++) s2[i] = tolower(s2[i]); if (strcmp(s1, s2) == 0) { printf("YES\n"); } else { printf("NO\n"); } } return 0; } void delspace(char* str) { int i = 0; int j = 0; char sTmp[strlen(str)]; while (str[i++] != '\0') { if (str[i] != ' ') { sTmp[j++] = str[i]; } } sTmp[j] = '\0'; strcpy(str, sTmp); } 

Dopo aver inserito “loops”, “s1” è stata assegnata automaticamente una riga vuota. Come succede? Sono sicuro che la mia tastiera funziona bene.

scanf() legge esattamente quello che gli hai chiesto, lasciando il seguente \n dalla fine di quella riga nel buffer dove fgets() lo leggerà. O fai qualcosa per consumare la nuova riga o (la mia soluzione preferita) fgets() e poi sscanf() da quella stringa.

scanf lascia gli spazi nel buffer di input, inclusi i caratteri di nuova riga. Per utilizzare Fgets per leggere la riga successiva è necessario rimuovere manualmente il resto della riga corrente:

 int c; do{ c = getchar(); }while(c != EOF && c != '\n'); 

Vayn,

Geekoaur ha risposto bene alla tua domanda, sto solo segnalando un altro “problema” con il tuo codice.

La riga s1[strlen(s1)] = '\0'; è un no-op se s1 è già giustamente terminato con null PRIMA che venga eseguito.

Ma se s1 NON è già completamente terminato con null PRIMA che questa riga venga eseguita (e tu sei sfortunato) causerà:

  • un SIGSEGV su un sistema POSIX (* nix).
  • un GPF su Windows.

Questo perché strlen basicaly trova l’indice del terminatore null esistente e lo restituisce! Ecco un’implementazione valida e non ottimizzata di strlen:

 int strlen(char *string) { int i = 0; while(string[i] != '\0') { ++i; } return i; } 

Quindi … Se sei DAVVERO preoccupato che le stringhe NON siano terminate da null, faresti qualcosa del tipo:

  • string[sizeof(string)]='\0'; su stringhe automatiche locali (dove il compilatore “conosce” la dimensione della stringa);
  • o string[SIZE_OF_STRING] per tutte le altre stringhe, dove SIZE_OF_STRING è (più comunemente) una costante di #define ‘o una variabile che si mantiene specificatamente per memorizzare la SIZE corrente (non la lunghezza) di una stringa allocata dynamicmente.

E se VERAMENTE, DAVVERO, VERAMENTE si preoccupa che le stringhe non vengano terminate con null (come se si trattasse di metodi di librerie “sporche” (ad esempio l’ATMI di Tuxedo per esempio), ANCHE “cancella” le “stringhe di ritorno” prima di passarle ai metodi di libreria sospetti con:

  • before: memset(string, NULL, SIZE_OF_STRING);
  • invocare: DirtyFunction(/*out*/string) ;
  • after: string[SIZE_OF_STRING]='\0'

I SIG11 sono una soluzione completa da trovare perché (a meno che non li si “agganci” con un processore di segnale e si dica altrimenti, essi causano un hard-terminate del programma, quindi non è ansible registrare nulla (dopo il fatto) per aiutare a capire dove-in-the-hell-did-that-come-from … specialmente considerando che in molti casi la linea di codice che lancia il SIG11 non è vicino alla causa effettiva della stringa, perdendo il suo terminatore null.

Ha senso per te?

Acclamazione amico. Keith.

PS: ATTENZIONE: strncpy NON è sempre nullterminate … probabilmente intendevi invece strlcpy . L’ho imparato nel modo più duro … quando è scoppiata una fatturazione da 60 milioni di dollari.


MODIFICARE:

FYI: Ecco una versione “sicura” (non ottimizzata) di strlen che chiamerò strnlen (penso che dovrebbe essere in stdlib . Sigh.).

 // retuns the length of the string (capped at size-1) int strnlen(char *string, int size) { int i = 0; while( i 

So che è molto vecchio. Sono nuovo di c e volevo controllare il mio metodo, che utilizza getchar :

 #include  int main() { printf("Please enter your name\n"); char string[10]; scanf("%s", string); printf("Hello %s\n", string); //getchar(); # un commenting this line, fgets perfectly works!! printf("Please enter your name again\n"); fgets ( string, 10, stdin ); printf("Hello again %s", string); getchar(); } 

basta mettere scanf("%d\n",&loops);

invece di scanf("%d",&loops);

Il seguente funziona se fgets() viene “saltato” dopo aver usato scanf()

Dopo aver detto:

 scanf("%d", &loops); 

Dire:

 char garbage[100]; fgets(garbage,100,stdin); 

Questo memorizzerà qualsiasi cosa rimasto nel buffer di input nella variabile garbage.

Questo cancellerà in modo efficace il buffer di input e ti permetterà di usare fgets() seguito.

EDIT: ho appreso di recente che esiste una soluzione più semplice di quella sopra. Se dici getchar () dopo scanf (), ti permetterà di usare fgets () senza problemi. getchar () otterrà il carattere successivo nel buffer di input, che in questo caso sarà ‘\ n’. Una volta rimosso ‘\ n’ dal buffer di input, fgets dovrebbe funzionare bene.

Ho risolto il tuo problema. Ora il tuo programma sta funzionando bene. Se hai qualche dubbio puoi chiedermelo.

  #include #include  int main() { int i, age; char phone[10]; char name[100]; printf("ENTER YOUR NAME:"); fgets(name , 100 , stdin); printf("ENTER YOUR AGE:"); scanf("%d",&age); printf("ENTER YOUR PHONE NUMBER:"); scanf(" "); fgets(phone,10,stdin); printf("\nStudent detail\n"); printf("Name: "); fputs(name , stdout ); printf("Age: %d\n",age); printf("Phone Number: "); puts(phone); printf("----\n"); return 0; }