Come faccio a sapere se ho raggiunto la fine della stringa?
Ricade tutto integralmente sotto la tua responsabilità. Il paradigma fondante del linguaggio C è "il programmatore deve sapere ciò che fa".
Sia dunque, per fissare le idee,
di la dimensione iniziale allocata per il buffer, una dimensione prudenziale: ad esempio, sia
di = 128.
Si deve conteggiare ogni singolo carattere accettato, tramite un totalizzatore incrementato ad ogni input, che denominiamo ad esempio
char_count: il controllo del superamento del limite preimpostato si ottiene quindi, banalmente, confrontando
di con
char_count.
Per tua cultura personale, sappi inoltre che:
- La gestione a decremento di
char_count (inizializzato alla dimensione allocata e confrontato con lo zero) è prestazionalmente equivalente sui PC all'idioma del totalizzatore incrementale, ma risulta maggiormente efficiente su molte piattaforme esotiche.
Tuttavia, su quest'ultime sovente non esiste alcunché di assimilabile ad una interfaccia uomo-macchina tradizionale.
- La
realloc() è un'operazione solitamente devastante per quanto attiene l'aspetto prestazionale di un'applicazione;
- Esiste una sintassi
regexp Posix del sottosistema
scanf(), supportata dalla vasta maggioranza dei compilatori C/C++, che consente di segregare l'input evitando pericolosi sconfinamenti, come nel seguente
esempio che non accetta più di LENGTH caratteri nel buffer:
#include <stdio.h>
#include <string.h>
#define LENGTH 4
#define BUFFER_SIZE (LENGTH + 1)
#define str(x) # x
#define xstr(x) str(x)
int main(void)
{
char buff[BUFFER_SIZE];
int rc;
printf("\nSCANF : please enter text => \n");
rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", buff);
if (!feof(stdin))
{
getc(stdin);
}
if (rc == 0 || rc == EOF)
{
*buff = '\0';
}
printf("\nSCANF : length is %u\n", (unsigned)strlen(buff));
printf("size is %u\n", (unsigned)sizeof(buff));
printf("string is #%s#\n", buff);
return 0;
}
Le "strane"
macro str() e xstr() presenti servono per aggirare un noto limite sintattico, rendendo possibile l'uso di un simbolo di
preprocessore nella stringa di formato.
Per chi necessita dei sottotitoli: nulla (o quasi) impedisce ovviamente di utilizzare direttamente la forma dinamica banale
char fmt_str[16];
int max_len = LENGTH;
...
sprintf(fmt_str, "%%%d[^\\n]%%*[^\\n]", max_len);
scanf(fmt_str, buff);
...e ovviamente si può anche inserire scolasticamente la costante letterale entro la stringa di formato, ma le differenze tra i tre approcci sono ben evidenti.
Quello qui proposto nel primo esempio
fissa la dimensione a compile time, pur mantenendo la flessibilità di una costante manifesta, il che lo rende immediatamente superiore all'approccio bovino del letterale; il secondo metodo, proposto immediatamente sopra questo paragrafo, è dinamico e avviene a runtime, con una (sia pur minima) penalità prestazionale e con inerenti rischi (sia pur remoti) di avvelenamento/iniezione di stack o heap - mentre nel primo caso la stringa di formato viene trattata come costante da qualsiasi compilatore minimamente decente, e quindi gestita in apposito segmento di memoria logicamente protetto su x86 e affini.
EDIT: Aggiunti alcuni utili link su segnalazione del buon Bonzo, che ringrazio. 