PDA

Visualizza la versione completa : [C] Alternative a scanf()


GliderKite
30-11-2010, 19:32
Come da titolo, i possibili problemi collegati all'utilizzo di questa funzione pongono il problema di trovare una possibile alternativa a questa cosi come alle funzioni derivate.

Molto spesso si legge nel web di utenti che sconsigliano caldamente l'utilizzo di questa funzione, senza però indicarne effettivamente alternative concrete.

Allora mi chiedo: Esistono? Se si, quali? Pro e contro?

MdE2005
30-11-2010, 19:42
Originariamente inviato da GliderKite
Come da titolo, i possibili problemi collegati all'utilizzo di questa funzione pongono il problema di trovare una possibile alternativa a questa cosi come alle funzioni derivate.
Esatto



Originariamente inviato da GliderKite
Molto spesso si legge nel web di utenti che sconsigliano caldamente l'utilizzo di questa funzione, senza però indicarne effettivamente alternative concrete.
Eccomi qua..in questo forum penso di averlo ripetuto decine di volte.



Originariamente inviato da GliderKite
Allora mi chiedo: Esistono? Se si, quali? Pro e contro?
Si, la fgets (attenzione, no gets), ovviamente con qualche accorgimento come puoi vedere in questi esempi:

leggere riga (http://www.daniweb.com/code/showthread.php?t=216532)
leggere floating (http://www.daniweb.com/code/showthread.php?t=216599)
leggere interi (http://www.daniweb.com/code/showthread.php?t=216521)


Ciao :)

YuYevon
30-11-2010, 20:39
Originariamente inviato da GliderKite
Allora mi chiedo: Esistono? Se si, quali? Pro e contro?

Qualcuno nel mondo poi potrebbe suggerirti la scanf_s(); quel qualcuno vuole il tuo male, non ascoltarlo.

GliderKite
30-11-2010, 21:00
Originariamente inviato da YuYevon
Qualcuno nel mondo poi potrebbe suggerirti la scanf_s(); quel qualcuno vuole il tuo male, non ascoltarlo.


:zizi:

Parli come il mio IDE:
warning C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead.

:popcorn: #define _CRT_SECURE_NO_WARNINGS :mem:



Negli esempi riportati viene utilizzata la sscanf(), anche questa funzione è deprecata...

Inoltre ho provato adesso il primo esempio:



char *mygetline(char *line, int size)
{
if ( fgets(line, size, stdin) )
{
char *newline = strchr(line, '\n'); /* check for trailing '\n' */
if ( newline )
{
*newline = '\0'; /* overwrite the '\n' with a terminating null */
}
}
return line;
}



Puoi spiegarmelo? Perchè non riesco a capire la differenza tra questo ed un semplice utilizzo nel main() di questo:



fgets( line, sizeof(line), stdin );


Grazie.

YuYevon
30-11-2010, 21:55
Originariamente inviato da GliderKite
Negli esempi riportati viene utilizzata la sscanf(), anche questa funzione è deprecata...


Non è deprecato nulla, formalmente è deprecata solo la gets(). Che poi certe funzioni abbiamo dei problemi noti è fuori dubbio, ma tra questo e dichiarare una funzione "deprecated" ci dovrebbe passare di mezzo una cosa che si chiama ISO.


Originariamente inviato da GliderKite
Inoltre ho provato adesso il primo esempio:
[...]


Se la fgets() restituisce un valore diverso da NULL, significa che non c'è stato alcun errore e che non si è raggiunto l'EOF senza leggere alcun carattere; a quel punto quindi si entra nel corpo dell'if esterno e si cerca un eventuale '\n' alla fine della stringa letta perché la fgets() di default ce lo aggiunge sempre a meno che la lettura non sia terminata per un EOF, e quell'eventuale '\n' viene rimpiazzato con un terminatore classico '\0'.

GliderKite
30-11-2010, 22:25
Originariamente inviato da YuYevon
Non è deprecato nulla, formalmente è deprecata solo la gets(). Che poi certe funzioni abbiamo dei problemi noti è fuori dubbio, ma tra questo e dichiarare una funzione "deprecated" ci dovrebbe passare di mezzo una cosa che si chiama ISO.



Se la fgets() restituisce un valore diverso da NULL, significa che non c'è stato alcun errore e che non si è raggiunto l'EOF senza leggere alcun carattere; a quel punto quindi si entra nel corpo dell'if esterno e si cerca un eventuale '\n' alla fine della stringa letta perché la fgets() di default ce lo aggiunge sempre a meno che la lettura non sia terminata per un EOF, e quell'eventuale '\n' viene rimpiazzato con un terminatore classico '\0'.


Non sono io a dirlo ma l'output di compilazione (To disable deprecation )...

E senza entrare nel merito di quella "cosa" che si chiama ISO, non sarà difficile fartelo confermare.


Emh... no...
Guarda che la fgets() esegue già di suo tutto quello che hai descritto, tranne per il fatto che non aggiunge il carattere di newline ma quello di fine stringa..., quindi tutta la funzione è inutile, perchè ripete un compito che è già stato eseguito dalla fgets stessa.


fgets()

...A null character is automatically appended in str after the characters read to signal the end of the C string.

MItaly
30-11-2010, 22:30
Non sono d'accordo. La scanf è sicura e comoda se usata in maniera adeguata, ossia non usando mai %s ma specificando il numero massimo di caratteri da acquisire (%numeros, ove numero è specificabile anche come argomento) e ricordandosi di controllare sempre il valore restituito dalla funzione.
Per quanto concerne il rischio di far casino con gli specificatori di formato, praticamente tutti i compilatori moderni segnalano gli eventuali errori a compile time.

... certo, gli iostream grazie all'overloading degli operatori, sono molto più comodi... :D

GliderKite
30-11-2010, 22:52
Originariamente inviato da MItaly
Non sono d'accordo. La scanf è sicura e comoda se usata in maniera adeguata, ossia non usando mai %s ma specificando il numero massimo di caratteri da acquisire (%numeros, ove numero è specificabile anche come argomento) e ricordandosi di controllare sempre il valore restituito dalla funzione.
Per quanto concerne il rischio di far casino con gli specificatori di formato, praticamente tutti i compilatori moderni segnalano gli eventuali errori a compile time.

... certo, gli iostream grazie all'overloading degli operatori, sono molto più comodi... :D

Be non c'è dubbio su iostream :)

Rimanendo in C-style il parametro [width] che indica il numero di caratteri massimi da acquisire è indubbiamente un vantaggio, ma rimane il fatto che la scanf() non può essere considerata una funzione "sicura", quindi "deprecabile" dove s'intende: Security CRT (http://msdn.microsoft.com/en-us/library/8ef0s5kh.aspx)

MItaly
30-11-2010, 23:05
Originariamente inviato da GliderKite
ma rimane il fatto che la scanf() non può essere considerata una funzione "sicura"
Escludendo gli sforamenti da buffer (evitati dallo specificatore di larghezza) in che circostanze la scanf risulta non sicura?

GliderKite
30-11-2010, 23:44
Semplice.

Tanto per cominciare il parametro che indica la lunghezza massima da leggere dev'essere necessariamente una costante, quindi non può essere determinato run-time.

Poi l'utilizzo di scanf implica necessariamente la certezza del tipo di input, e fino a quando uno si limita a programmi del tipo hello world application questi problemi non li nota, ma manca poco da li a programmi dove l'utilizzo di una scanf è assolutamente da evitare.

Qualcuno potrebbe dire che se non sei sicuro dell'input leggi l'intera riga e elabori successivamente i dati. Solo pensare di risolvere un problema, di qualsiasi tipo, con questa soluzione è poco efficiente. Si potrebbe fare, la scanf() accetta come delimitatore di default un carattere white-space o End-Of-File, ma tu ricordi esattamente la sintassi per fare ciò? Io no personalmente, dovrei andarmela a riguardare e credo anche l'utente medio o comunque meno esperto. Basandomi spesso sul dover determinare l'efficienza di un algoritmo ho imparato a dover considerare anche il tempo di implementazione e usare la scanf in questo caso vorrebbe dire aver tempo da perdere, potendo usare invece la fgets().

La scanf() lascia inoltre sul buffer di input normalmente la newline di fine riga e se uno non sta attento ogni volta (magari con un %*c o fflush(stdin)) diventa nuovamente una rottura se non ci sei abituato.

Insomma non è solo una questione del codice della funzione, ma di come può essere utilizzata dall'utente medio. Ed è questo che poi sta alla base dello sviluppo del linguaggio di programmazione stesso, basti vedere lo sviluppo del C++, molto più "comodo" e più "semplice" del C sotto questi aspetti, o meglio ancora lo sviluppo da Visual Basic a Visual Basic .NET.

Per concludere, ci saranno sicuramente altre motivazioni che ad un non espertissimo programmatore come me sfuggono. :)

PS: le vostre opinioni e suggerimenti sempre ben accetti, siamo qui anche per imparare :)

Loading