18 aprile 2008
Misteri del C
Oggi pomeriggio, approfittando di una giornata lavorativa relativamente tranquilla, mi sono messo a ricontrollare quegli algoritmi in C che avevo fatto vedere a lezione lo scorso mercoledì e che mi avevano fatto rimediare una figura piuttosto barbina. E mi sono accorto di una cosa quantomeno curiosa.

Osservate il listato presente a questo link.
Qual è il problema, direte voi? Nessuno, verrebbe da dire. Sembra tutto semplice e lineare. E invece un problema c’è. L’algoritmo in questione riesce ad individuare correttamente un elemento all’interno della sequenza, solo e soltanto se questo è il primo. Se l’elemento ricercato non è il primo del vettore, il programma restituirà “Elemento non presente”, indipendentemente dal fatto che il carattere sia incluso o meno all’interno dell’array. Dopo una breve analisi, sono riuscito a risalire alla fonte del problema. Ma non a comprenderlo. In sostanza, infatti, il ciclo while effettua una sola iterazione. Questo perchè il programma “perde” il valore della variabile n. Per la precisione lo perde quando viene eseguita l’istruzione scanf(“%1s”, &c);. Che, per qualche astruso motivo, rende n uguale a zero. Le prove sono state fatte con GCC, sia sul Mac (GCC 4.0) sia su Windows in ambiente Cygwin (non ho controllato se la versione del compilatore è la medesima). Ottenendo lo stesso identico risultato. Il tutto puzza come un bug di GCC. Qualcuno di voi ascoltatori è in grado di darmi un feedback, provando con un compilatore diverso o con una qualche altra versione di GCC?
Comments(11)


Ciao,
credo che il problema sia dovuto al fatto che leggi i caratteri come se fossero stringhe (%1s) ma li salvi in char senza considerare il carattere di terminazione ”.
vedi ad esempio qui: http://support.microsoft.com/kb/42075
ciao ciao,
Luigi
Ciao Luigi e grazie per il commento.
Subito avevo pensato anche io ad un problema di questo tipo. In realtà non si tratta di questo. I caratteri vengono letti correttamente ed i confronti funzionano bene. Per qualche strano motivo è il valore di n che viene “perso” durante l’esecuzione. Se stampo n prima e dopo l’istruzione scanf(“%1s”, &c);, ottengo due valori diversi: quello corretto prima, 0 dopo. E così il ciclo while viene eseguito solo una volta (ed il programma mi trova l’elemento che sto cercando solo se questo è il primo dell’array).
PS: toglimi una curiosità, sei il Luigi dell’AIRLab per caso?
A me funziona, riempendo le righe mancanti sul codice che hai postato ovviamente. Eccolo comunque:
http://pastebin.com/m3b5b51e5
Ops, non mi ero accorto che nel copia/incolla erano rimaste fuori delle parti… :-/
Che compilatore hai usato?
Scusa il ritardo della risposta, ho usato un gcc classico, se vuoi ti dico la versione:
gcc (GCC) 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2), non ho provato su altri, se ti serve ci provo,
Mistero svelato, ancora una volta grazie al buon Gianluca…
Quello che accade con il codice riportato in questo post è che lo scanf incriminato è scritto in maniera tale da leggere il primo carattere di una stringa, ma cerca di memorizzare anche il valore corrispondente alla pressione del tasto invio. Non essendoci sufficiente spazio in c, che è una variabile char, questa informazione viene scritta sulla zona di memoria attigua, che è quella allocata per n. Da qui il fatto che n, inaspettatamente, si azzeri.
eheheh … errore banalotto, che cmq hai già risolto (menomale). Ai miei studenti avrei “proibito ” di leggere singoli caratteri con lo specificatore di formato per le stringhe, anche se viene utilizzato lo qualificatore di ampiezza… ci si dimentica poi dei terminatori e non si ha più controllo di quel che rimane nei “buffer” di I/O …
Eh sì… però, mica per volermi discolpare a questo punto, ma il codice di cui sopra è stato preso pari pari dal Bellini-Guidi (terza ed., pag. 130). Io mi piglio il cazziatone perchè non mi sono accorto dell’errore, però pretendo che se lo piglino pure gli autori!
hai perfettamente ragione. Un sacco di gente scrive (ha scritto) cacchiate senza rendersene conto. Ti consiglio un libro (giusto per farmi pubblicità, tanto non incasso i diritti d’autore) (ISBN 978-88-7488-231-1): anche qui qualche strafalcione c’è…ma in genere è “diverso” dai soliti testi).
“Diverso” per via di cosa, se posso?
“diverso” per il taglio che abbiamo dato al testo. Dall’ordine di presentazione degli argomenti, ad alcuni “dettagli” che (con non poca modestia) ci fanno distinguere dalla “massa”. Noi tutti abbiamo studiato su testi che trattano il “solito” conto corrente bancario, la solita “fattura” o rubrica … i soliti esempi a volte molto distanti da “casi reali” (intendo esempi non facilmente tangibili da studenti neofiti) o troppo “noiosi” per chi ha dei precedenti studi alle spalle… che tritamento di p…e, eppure siamo circondati da esempi “più avvincenti” e non troppo complicati. Qui puoi leggere la presentazione e l’indice http://www.lucianoquartarone.it/labinfo1/ ma puoi anche richiedere una copia saggio all’editore (io non ne ho più a disposizione). Buona lettura.