La fgets:
- termina sempre la stringa con il NUL (= il carattere 0);
- legge tutti i caratteri dati in input fino al newline, compreso il newline a meno che il buffer che le hai passato non sia troppo corto, nel qual caso arriva a riempire fino al penultimo carattere del buffer (l'ultimo viene usato per il terminatore NUL);
- se lo stream di input termina, non verrà "inventato" alcun newline.
In pratica, fgets funziona così:
Per cui:codice:char *fgets(char *s, int size, FILE *stream) { int i, c; for(i=0; i<size-1; ++i) { c = getc(stream); if(c==EOF) break; s[i] = (char)c; if(c=='\n') break; } s[i]=0; if(ferror(stream) || (c==EOF && i==0)) return NULL; return s; }
- la stringa che ottieni è sempre una stringa C valida (ovvero, è sempre terminata con il NUL);
- non vengono mai scritti caratteri oltre la dimensione che gli hai detto;
- se c'è stata tutta la riga, l'ultimo carattere sicuramente è un newline;
- se non c'è un newline in coda, o non c'è stata tutta la riga, oppure lo stream è terminato (o si è verificato un errore); puoi verificare questa condizione provando a leggere nuovamente e/o verificando lo stato dello stream con feof/ferror.
Quindi,
gestisce solo il caso "banale" - ovvero, c'è stato tutto e lo stream non è terminato; una gestione un po' più safe può essere:codice:nome[strlen(nome)-1] = 0;
- il check su sz!=0 è per essere sicuri che la stringa effettivamente contenga almeno un carattere prima di andare a vedere il penultimo carattere (modificare nome[-1] è undefined behavior);codice:int sz = strlen(nome); if(sz!=0 && nome[sz-1]=='\n') nome[sz-1]=0;
- il check sul fatto che il penultimo carattere sia effettivamente un newline è per non perdere l'ultimo carattere se siamo alla fine dello stream
... poi se vuoi gestire correttamente input più lunghi la cosa si fa un po' più complicata e richiede l'allocazione dinamica...

Rispondi quotando
) strcspn:
