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ì:
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;
}
Per cui:
- 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,
codice:
nome[strlen(nome)-1] = 0;
gestisce solo il caso "banale" - ovvero, c'è stato tutto e lo stream non è terminato; una gestione un po' più safe può essere:
codice:
int sz = strlen(nome);
if(sz!=0 && nome[sz-1]=='\n') nome[sz-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);
- 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...