[C] Input di stringhe

wall98
Salve ragazzi, l'altro giorno ho fatto un programma solutore di equazioni, come input ho utilizzato un array di char, quindi per inserire l'equazione bisogna mettere un carattere, premere invio, mettere un carattere, premere invio ecc.
Beh questo non è proprio user friendly, come posso fare in modo che l'input avvenga quando è stata scritta tutta l'equazione?
potreste postarmi il codice stringa per fare cio?
(importante: mi serve che ogni carattere venga salvato in un char diverso)

Grazie :)

Risposte
BoG3
hai provato con:
char s[80];
scanf("%79s",s);

??
PS: la stringa è comunque un array di char, quindi... sara' per forza memorizzata carattere per carattere ;)
PPS: ricorda che alla fine stringa c'è il terminatore di stringa, quindi avrai sempre N-1 caratteri a disposizione per la tua equazione. infatti, la stringa s dichiarata sopra ha 79 spazzi + l'80-esimo per il terminatore di stringa

wall98
Appena posso lo provo, comunque so che funzionera, mi mancavano le basi teoriche per sviluppare il codice.

PS: che vuoi dire che avro sempre N-1 caratteri a disposizione? mettiamo di aver scritto tutta l'equazione ma ho ancora dei caratteri disponibili, che succede?

Return89
Vuol dire che in un array di N elementi ne potrai utilizzare solamente N-1 visto che l'ultimo elemento è utilizzato dal carattere per indicare che l'array è finito.
Se invece di 79 caratteri ne utilizzi 10 cosa succede? Nulla, semplicemente (non so come vuoi strutturare questo algoritmo ma) dopo aver letto ogni carattere devi verificare che il successivo sia un carattere valido (continua esecuzione) e non il terminatore (esce dalla funzione).

nessuno.nobody
Solo una precisazione:
quando dichiari una variabile, non sai mai che valore questa potrà avere.
Quindi anche nel caso in cui stai dichiarando un array di char, per sicurezza ti consiglio di usare memset per riempirla di '\0', in modo che sei sicuro che anche nel caso in cui l'utente inserisca una stringa di lunghezza minore dell'ampiezza dell'array, questa sia correttamente terminata

wall98
Chiarisco subito che di istruzioni ne conosco poche, di solito faccio tutto con quelle, e spesso il codice non è molto elegante, anzi..

"nessuno.nobody":
Solo una precisazione:
quando dichiari una variabile, non sai mai che valore questa potrà avere.
Quindi anche nel caso in cui stai dichiarando un array di char, per sicurezza ti consiglio di usare memset per riempirla di '\0', in modo che sei sicuro che anche nel caso in cui l'utente inserisca una stringa di lunghezza minore dell'ampiezza dell'array, questa sia correttamente terminata


in alternativa impostare una for fino al N-1 esimo elemento?


"Return89":
Vuol dire che in un array di N elementi ne potrai utilizzare solamente N-1 visto che l'ultimo elemento è utilizzato dal carattere per indicare che l'array è finito.
Se invece di 79 caratteri ne utilizzi 10 cosa succede? Nulla, semplicemente (non so come vuoi strutturare questo algoritmo ma) dopo aver letto ogni carattere devi verificare che il successivo sia un carattere valido (continua esecuzione) e non il terminatore (esce dalla funzione).


ok capito :)

Return89
"nessuno.nobody":
Solo una precisazione:
quando dichiari una variabile, non sai mai che valore questa potrà avere.
Quindi anche nel caso in cui stai dichiarando un array di char, per sicurezza ti consiglio di usare memset per riempirla di '\0', in modo che sei sicuro che anche nel caso in cui l'utente inserisca una stringa di lunghezza minore dell'ampiezza dell'array, questa sia correttamente terminata

Precisazione: quel che hai scritto non è sempre vero, mai sentito parlare di allocazione dinamica? Chiaramente in questo esercizio non è consigliabile usarla..

Cmq se ho capito quel che vuoi fare io semplicemente userei la funzione gets(stringa) per leggere l'intera equazione scritta da tastiera e poi tramite cicli e controlli la spezzi nei vari coefficienti.
Come hai scritto te conosci ancora poche funzioni ma usare sempre le stesse è sbagliato, non vai mai avanti così oltre a finire sempre con l'utilizzare algoritmi iterativi complessi e poco efficienti

hamming_burst
"Return89":

Cmq se ho capito quel che vuoi fare io semplicemente userei la funzione gets(stringa) per leggere l'intera equazione scritta da tastiera e poi tramite cicli e controlli la spezzi nei vari coefficienti.

qualcuno avrebbe qualcosa da ridire: click.

Return89
Per quale astruso motivo non dovrebbe mai essere usata questa funzione? sentiamo :)

(P.S.: in sede d'esame prediligo pure io il classico ciclo)

nessuno.nobody
"Return89":
Precisazione: quel che hai scritto non è sempre vero, mai sentito parlare di allocazione dinamica? Chiaramente in questo esercizio non è consigliabile usarla..

Ovviamente sì. Ma non stavamo parlando di questo caso.
"Return89":
Cmq se ho capito quel che vuoi fare io semplicemente userei la funzione gets(stringa) per leggere l'intera equazione scritta da tastiera

Non è un buon consiglio.
Stai consigliando di utilizzare una funzione che non ha controlli sul numero d caratteri in ingresso. Mai sentito parlare di buffer overflow?
La funzione che andrebbe usata, non è né la scanf né la gets, ma la fgets. Dato che in tal modo puoi specificare la lunghezza massima che la funzione può leggere.
In ogni caso, anche se usi l'allocazione dimamica, la memoria va lo stesso inizializzata ad un valore noto, e la memset va usata anche in quel caso.
Dopo una malloc, è l'ideale azzerare il buffer appena allocato. (A meno che tu non sti usanso una calloc, che è implementata esattamente come malloc + memset a zero.)

"wall98":
in alternativa impostare una for fino al N-1 esimo elemento?

Per fare cosa?

wall98
per riempire di caratteri ogni char, allo scopo di evitare che rimangango variabili non dichiarate..

Return89
"nessuno.nobody":

Non è un buon consiglio.
Stai consigliando di utilizzare una funzione che non ha controlli sul numero d caratteri in ingresso. Mai sentito parlare di buffer overflow?
La funzione che andrebbe usata, non è né la scanf né la gets, ma la fgets. Dato che in tal modo puoi specificare la lunghezza massima che la funzione può leggere.
In ogni caso, anche se usi l'allocazione dimamica, la memoria va lo stesso inizializzata ad un valore noto, e la memset va usata anche in quel caso.
Dopo una malloc, è l'ideale azzerare il buffer appena allocato. (A meno che tu non sti usanso una calloc, che è implementata esattamente come malloc + memset a zero.)

Certo che conosco l'overflow ma a differenza di molti di voi (senza offesa eh! Ma leggo di moderatori che linkano discutibili link..) io non mi limito a leggere un articolo scritto da un tizio su di un forum, bensì faccio delle prove e verifico i risultati. La funzione gets è una funzione definita "pericolosa" solo perché RISCHIA di provocare overflow. Questo vuol dire che POTREBBE essere generato codice incontrollato che POTREBBE provocare risultati imprevisti.
Se fai le dovute prove (con il tuo compilatore e non con quello del tipo che sostiene che gli vengono modificate anche le variabili, con "invasioni di celle di memoria"..) ti accorgerai che probabilmente ti verrà segnalato qualche danger ma ai fini del tuo programma, probabilmente, non avrai problemi.
E comunque penso che sia stupido dire "la funzione gets non va assolutamente insegnata, usata, definita o consegnata ai posteri" solo perché un uso improprio potrebbe creare problemi. E' come se dicessi che lo scanf con lettura di un valore int non va usato perché se inserisco un numero troppo grande che supera i limiti del tipo int esso non viene letto correttamente.
Detto ciò la fgets è sicuramente una soluzione più ottimale come hai detto te, ma in questa discussione ho letto di un utente (wall) che è alle prime armi e a quanto pare sa utilizzare giusto le 4-5 funzioni che insegnano anche alle medie. Quindi proporgli la gets (funzione semplificata della fgets) penso gli possa servire a capire cosa vuol dire lettura di una riga, poi successivamente capirà i pro ed i contro e probabilmente utilizzerà la fgets o tornerà ai suoi cicli iterativi.
Non ho capito solo il tuo discorso sull'inizializzazione della memoria allocata. Non è che una volta che chiedi nuova memoria devi per forza utilizzarla completamente e subito..

hamming_burst
"Return89":
Detto ciò la fgets è sicuramente una soluzione più ottimale come hai detto te, ma in questa discussione ho letto di un utente (wall) che è alle prime armi e a quanto pare sa utilizzare giusto le 4-5 funzioni che insegnano anche alle medie. Quindi proporgli la gets (funzione semplificata della fgets) penso gli possa servire a capire cosa vuol dire lettura di una riga, poi successivamente capirà i pro ed i contro e probabilmente utilizzerà la fgets o tornerà ai suoi cicli iterativi.

sotto questa visione hai ragione a dubitare della pericolosità della gets e che alla fin fine un esercizio. Ma è bene saperlo, anche non approfonditamente, ma solo come appunto d'informazione. Infatti il mio link a tal sito: http://www.gidnetwork.com/b-56.html era per l'OP.
"Return89":
io non mi limito a leggere un articolo scritto da un tizio su di un forum, bensì faccio delle prove e verifico i risultati. La funzione gets è una funzione definita "pericolosa" solo perché RISCHIA di provocare overflow. Questo vuol dire che POTREBBE essere generato codice incontrollato che POTREBBE provocare risultati imprevisti.
Se fai le dovute prove (con il tuo compilatore e non con quello del tipo che sostiene che gli vengono modificate anche le variabili, con "invasioni di celle di memoria"..) ti accorgerai che probabilmente ti verrà segnalato qualche danger ma ai fini del tuo programma, probabilmente, non avrai problemi.
E comunque penso che sia stupido dire "la funzione gets non va assolutamente insegnata, usata, definita o consegnata ai posteri" solo perché un uso improprio potrebbe creare problemi. E' come se dicessi che lo scanf con lettura di un valore int non va usato perché se inserisco un numero troppo grande che supera i limiti del tipo int esso non viene letto correttamente.

Forse sul tuo computer potrà funzionare sempre, ma fuori dal tuo ambiente di compilazione sei conscio che ci potrebbero essere problemi.
Infatti è proprio questo il problema principale: il condizionale, il possibile, il potrebbe, non è sufficiente per riternere superfluo l'errore che nascerebbe sull'utilizzo sconsiderato di una funzione piuttosto che un'altra.
E' questa una delle fonte di buona parte dei problemi, bug, errori che nascono in ogni codice. Ovviamente questo discorso è valido in visione più ampia rispetto all'esercizio di tale post.

Return89
"hamming_burst":
[quote="Return89"]Detto ciò la fgets è sicuramente una soluzione più ottimale come hai detto te, ma in questa discussione ho letto di un utente (wall) che è alle prime armi e a quanto pare sa utilizzare giusto le 4-5 funzioni che insegnano anche alle medie. Quindi proporgli la gets (funzione semplificata della fgets) penso gli possa servire a capire cosa vuol dire lettura di una riga, poi successivamente capirà i pro ed i contro e probabilmente utilizzerà la fgets o tornerà ai suoi cicli iterativi.

sotto questa visione hai ragione a dubitare della pericolosità della gets e che alla fin fine un esercizio. Ma è bene saperlo, anche non approfonditamente, ma solo come appunto d'informazione. Infatti il mio link a tal sito: http://www.gidnetwork.com/b-56.html era per l'OP.
"Return89":
io non mi limito a leggere un articolo scritto da un tizio su di un forum, bensì faccio delle prove e verifico i risultati. La funzione gets è una funzione definita "pericolosa" solo perché RISCHIA di provocare overflow. Questo vuol dire che POTREBBE essere generato codice incontrollato che POTREBBE provocare risultati imprevisti.
Se fai le dovute prove (con il tuo compilatore e non con quello del tipo che sostiene che gli vengono modificate anche le variabili, con "invasioni di celle di memoria"..) ti accorgerai che probabilmente ti verrà segnalato qualche danger ma ai fini del tuo programma, probabilmente, non avrai problemi.
E comunque penso che sia stupido dire "la funzione gets non va assolutamente insegnata, usata, definita o consegnata ai posteri" solo perché un uso improprio potrebbe creare problemi. E' come se dicessi che lo scanf con lettura di un valore int non va usato perché se inserisco un numero troppo grande che supera i limiti del tipo int esso non viene letto correttamente.

Forse sul tuo computer potrà funzionare sempre, ma fuori dal tuo ambiente di compilazione sei conscio che ci potrebbero essere problemi.
Infatti è proprio questo il problema principale: il condizionale, il possibile, il potrebbe, non è sufficiente per riternere superfluo l'errore che nascerebbe sull'utilizzo sconsiderato di una funzione piuttosto che un'altra.
E' questa una delle fonte di buona parte dei problemi, bug, errori che nascono in ogni codice. Ovviamente questo discorso è valido in visione più ampia rispetto all'esercizio di tale post.[/quote]

Pienamente d'accordo con te :smt023

apatriarca
In base alla famosa legge di Murphy, "se qualcosa può andare storto, lo farà". Ogni codice che fa uso di gets è per sua natura bacato. È infatti possibile farlo crashare o funzionare in modo scorretto senza grossi problemi. È sufficiente passare una riga abbastanza lunga in input al programma. Il fatto che probabilmente funzionerà correttamente in molte situazioni non significa che funzionerà correttamente in ogni situazione. Se il proprio obiettivo è quello di sviluppare un programma utilizzabile e relativamente sicuro e robusto, allora non si può fare affidamento su di una funzione come gets. Sono ancora convinto della mia opinione: non esiste alcun uso corretto della funzione gets e va quindi evitata a tutti i costi. Non va quindi né insegnata, né usata. Oltretutto fgets non è molto più complicata da usare e costringe a preoccuparsi della dimensione del buffer che viene usato (cosa decisamente positiva a mio parere). Ritengo che per un principiante sia particolarmente dannoso l'uso di gets in quanto potrebbe non comprendere per quale ragione il proprio codice non funzioni correttamente con alcuni input. fgets è molto più sicura da questo punto di vista, non ci sono errori nascosti di cui preoccuparsi.
E non si tratta di una opinione presa da qualche sito e ritenuta corretta a priori. Ho parecchi anni di esperienza con il C e vengo pagato per farlo. La mia opinione su gets è inoltre condivisa da praticamente tutta la comunità di programmatori C e quella funzione è stata deprecata nello standard del 1999 del C e rimossa nell'ultimo standard del 2011..

nessuno.nobody
"Return89":
Se fai le dovute prove (con il tuo compilatore e non con quello del tipo che sostiene che gli vengono modificate anche le variabili, con "invasioni di celle di memoria"..) ti accorgerai che probabilmente ti verrà segnalato qualche danger ma ai fini del tuo programma, probabilmente, non avrai problemi.

Guarda che fare prove non vuol dire esattamente nulla.
Ti è sempre andata bene perché da un po' di tempo diversi compilatori (leggi come gcc e fork vari) hanno aggiunto l'opzione attiva di default per attivare lo Stack-Smashing Protector.
Compila i tuoi programmi cui cui hai fatto "le prove" (dato che non crediamo a ciò che le persone dicono, magari sono tutti scemi), con gcc passando come parametro --fno-stack-protector e poi dimmi se è tutto rosa e fiori.

p.s: mi scuso se sono sembrato irruento, non era mia intenzione

Return89
"nessuno.nobody":
[quote="Return89"]Se fai le dovute prove (con il tuo compilatore e non con quello del tipo che sostiene che gli vengono modificate anche le variabili, con "invasioni di celle di memoria"..) ti accorgerai che probabilmente ti verrà segnalato qualche danger ma ai fini del tuo programma, probabilmente, non avrai problemi.

Guarda che fare prove non vuol dire esattamente nulla.
Ti è sempre andata bene perché da un po' di tempo diversi compilatori (leggi come gcc e fork vari) hanno aggiunto l'opzione attiva di default per attivare lo Stack-Smashing Protector.
Compila i tuoi programmi cui cui hai fatto "le prove" (dato che non crediamo a ciò che le persone dicono, magari sono tutti scemi), con gcc passando come parametro --fno-stack-protector e poi dimmi se è tutto rosa e fiori.
p.s: mi scuso se sono sembrato irruento, non era mia intenzione[/quote]
Tranquillo, non sei sembrato irruento ma più che altro direi che hai fatto la figura dello sc**o.
Abbiamo già risolto la questione ma tu ti ostini a ripetere cose lette su yahoo answer.
Se leggessi quel che ho scritto io, ti accorgeresti ho appunto usato frasi come: probabilmente a te funzionerà, nel tuo compilatore, non nel compilatore di altri. Quindi direi che non hai proprio capito quel che dicevo. Anzi incollare qui i parametri da inserire su gcc mi può solo far sorridere.
Se posso darti un consiglio usa più fantasia e meno schemi preconfezionati da libri/web.
p.s.: mi scuso se sono sembrato irruento, non era mia intenzione

apatriarca
@Return89: Ti invito a moderare i toni (ho censurato io quello che avevi scritto). Non c'è alcun motivo di offendere altri utenti e dare per scontato che le loro risposte siano solo frutto di una ricerca sul web o da altre fonti senza alcun intervento critico da parte loro. Personalmente non credo che inserire dei controlli automatici per evitare il buffer overflow sia comunque una soluzione per aggirare i problemi di gets. L'unico risultato che si ottiene è quello di far crashare il programma, mentre con fgets è possibile gestire meglio l'errore (per esempio stampando un messaggio di errore e richiedendo all'utente di inserire una riga valida o allocando un buffer più grande..). Ma non credo abbia senso continuare questa discussione. La risposta all'utente è stata data e il discorso gets vs fgets è fine a se stesso. gets è stato pure eliminato dallo standard C..

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.