Precedente :: Successivo |
Autore |
Messaggio |
Stemby Eroe in grazia degli dei

Registrato: 29/07/08 23:55 Messaggi: 78 Residenza: Missaglia (LC)
|
Inviato: 30 Lug 2008 00:04 Oggetto: [C] Niubbissimo: dov'è l'errore? |
|
|
Buona sera a tutti. Mi sono appena iscritto sperando di trovare qui supporto nell'apprendere il C.
Sto studiando il Kernighan-Ritchie (seconda edizione) e sto man mano facendo delle prove. Per ora sono verso la fine del capitolo 1.
In questo listato minimale che ho prodotto, dove sta l'errore? Perché non mi chiede il secondo carattere di input e decide (come?) che si tratta di un ritorno a capo?
Codice: |
#include <stdio.h>
int carattere;
main()
{
printf("Scegliere un carattere: ");
carattere = getchar();
printf("Carattere scelto: numero %d della tabella ASCII\n", carattere);
printf("Scegliere un altro carattere: ");
carattere = getchar();
printf("Eccolo: il numero %d della tabella ASCII\n", carattere);
}
|
Grazie! |
|
Top |
|
 |
Ramon Semidio

Registrato: 07/07/06 01:50 Messaggi: 342
|
Inviato: 30 Lug 2008 00:35 Oggetto: Devi prevedere anche il tasto [Invio] |
|
|
Come puoi notare dall'output del programma, ti viene stampato il codice ASCII del carattere che hai inserito e, subito dopo, il codice ASCII 10; a quel punto il programma termina senza chiederti (apparentemente) il secondo carattere
Il codice ASCII 10 rappresenta un "line feed" = avanzamento linea (o nuova linea); in pratica, quando inserisci un carattere e premi [Invio], stai inserendo automaticamente un secondo carattere che è appunto il "line feed".
Per prevedere questa situazione, ti basta inserire un "doppio getchar()" per leggere ogni carattere; si ottiene quindi questa situazione:
Codice: |
printf("Scegliere un carattere: ");
carattere = getchar();
getchar(); /* per il "line feed" */
printf("Carattere scelto: numero %d della tabella ASCII\n", carattere);
printf("Scegliere un altro carattere: ");
carattere = getchar();
printf("Eccolo: il numero %d della tabella ASCII\n", carattere);
|
P.S. A seconda del sistema operativo usato, al posto del codice ASCII 10 ti potrebbe comparire il codice ASCII 13 (ritorno carrello). |
|
Top |
|
 |
Zeus Amministratore


Registrato: 21/10/00 02:01 Messaggi: 13287 Residenza: San Junipero
|
Inviato: 30 Lug 2008 00:45 Oggetto: |
|
|
La funzione getchar legge il primo carattere dallo standard input (ovvero la tastiera) e lo restituisce sotto forma di intero. La prima getchar del tuo listato legge il primo carattere e lo va a piazzare in un suo buffer; ma getchar non restituisce il controllo al tuo programma finche' non premi anche il tasto invio. A questo punto la getchar ritorna il valore del carattere inserito e lo colloca nella tua variabile intera carattere, ma inserisce anche il carattere "Invio" nel buffer. Ecco perché la seconda getchar non ha più bisogno di alcun input dalla tastiera: lo va a prendere direttamente dal buffer. Qui trova il carattere "Invio" e te lo restituisce. |
|
Top |
|
 |
Stemby Eroe in grazia degli dei

Registrato: 29/07/08 23:55 Messaggi: 78 Residenza: Missaglia (LC)
|
Inviato: 30 Lug 2008 07:54 Oggetto: |
|
|
Grazie ad entrambi!
Era all'incirca quello che sospettavo (avevo capito che ASCII 10 era l'invio che si dava), ma adesso mi è chiaro il meccanismo che sta dietro.
Che casino
Sostanzialmente devo ricordarmi di svuotare il buffer della tastiera ogni volta. Non c'è una funzione della libreria standard che abbia questo compito? Anche perché il codice proposto da Ramon credo che non sia il massimo: se uno immette più di un carattere prima dell'invio, sono da capo, quindi bisogna mettere o un controllo sul numero dei caratteri immessi oppure un ciclo che mi svuoti il buffer e che prosegua finché non è vuoto del tutto, giusto?
(immagino comunque che ci siano altri metodi più evoluti per l'I/O, adesso procedo nello studio). |
|
Top |
|
 |
freemind Supervisor sezione Programmazione


Registrato: 04/04/07 21:28 Messaggi: 4643 Residenza: Internet
|
Inviato: 30 Lug 2008 10:00 Oggetto: |
|
|
Diciamo che dipende da quello che devi fare.
In generale per svuotare il buffer di tastiera potresti usare "fflush()".
In generale per leggere da tastiera però conviene usare scanf(...). |
|
Top |
|
 |
Stemby Eroe in grazia degli dei

Registrato: 29/07/08 23:55 Messaggi: 78 Residenza: Missaglia (LC)
|
Inviato: 09 Set 2008 00:29 Oggetto: |
|
|
Proseguo la discussione: niubbissimo ero e niubbissimo sono ancora (sono al secondo capitolo inoltrato del K&R).
Avendo bisogno di prendere un input numerico da tastiera, ho scritto questa funzione (chiudete entrambi gli occhi sul gets, please, lo scopo è puramente didattico, è l'unico metodo che per ora son riuscito ad applicare e al momento non mi interessa cambiarlo):
Codice: |
int scegli_numero(char s[]) /* converte l'input da tastiera in intero */
{
int i;
gets(s); /* **************** funzione pericolosa, bisognerebbe sostituirla *************************** */
i = atoi(s);
return i;
}
|
Visto che nel mio caso le cifre da pescare sono sempre al massimo 2, ho pensato di fare un vettore di 3 caratteri, per stare comodo ma senza usare molto più dello stretto indispensabile.
Quindi ho definito questa costante:
Codice: |
#define BUFSIZE 3 /* numero di caratteri messi nel buffer */
|
Questo è il prototipo della funzione:
Codice: |
int scegli_numero(char scelta[]);
|
Questa la variabile che ho chiamato "scelta", all'interno della funzione main:
Codice: |
char scelta[BUFSIZE];
|
E questo è ad esempio uno dei passaggi in cui richiamo la mia funzione:
Codice: |
printf("Durata del turno (ore): ");
turno = scegli_numero(scelta);
printf("%d ore\n", turno);
|
Ora, io mi aspettavo che mi pescasse solo 3 caratteri, invece me ne prende anche molti di più.
Dove sbaglio? Cosa mi sfugge? In pratica: cosa non ho capito
Grazie! |
|
Top |
|
 |
SverX Supervisor Macchinisti


Registrato: 25/03/02 12:16 Messaggi: 11810 Residenza: Tokelau
|
Inviato: 09 Set 2008 10:06 Oggetto: |
|
|
Stemby ha scritto: | io mi aspettavo che mi pescasse solo 3 caratteri, invece me ne prende anche molti di più. |
La funzione che usi accetta in input una stringa di qualunque lunghezza, poi il problema sarà che tu hai predisposto un buffer di solo 3 caratteri quindi -presumibilmente- andrai a sovrascrivere della memoria allocata ad altre variabili...
o cambi funzione o utilizzi un buffer molto più lungo e speri che comunque la sua lunghezza non venga superata... |
|
Top |
|
 |
Stemby Eroe in grazia degli dei

Registrato: 29/07/08 23:55 Messaggi: 78 Residenza: Missaglia (LC)
|
Inviato: 09 Set 2008 23:42 Oggetto: |
|
|
SverX ha scritto: | Stemby ha scritto: | io mi aspettavo che mi pescasse solo 3 caratteri, invece me ne prende anche molti di più. |
La funzione che usi accetta in input una stringa di qualunque lunghezza, poi il problema sarà che tu hai predisposto un buffer di solo 3 caratteri quindi -presumibilmente- andrai a sovrascrivere della memoria allocata ad altre variabili...
|
Ah sì? Interessante... non è che semplicemente i caratteri di troppo vengono scartati e basta? O al limite che vadano a sovrascrivere i primi 3?
Com'è possibile che si vadano a sovrascrivere altre variabili?
Grazie! |
|
Top |
|
 |
freemind Supervisor sezione Programmazione


Registrato: 04/04/07 21:28 Messaggi: 4643 Residenza: Internet
|
Inviato: 10 Set 2008 00:25 Oggetto: |
|
|
Occhio:
Codice: |
char scelta[BUFSIZE];
|
crea un vettore char di BUFSIZE elementi.
Nella funzione:
Codice: |
int scegli_numero(char s[]) /* converte l'input da tastiera in intero */
{
int i;
gets(s); /* **************** funzione pericolosa, bisognerebbe sostituirla *************************** */
i = atoi(s);
return i;
}
|
il parametro s è un vettore di cui non sappiamo la lunghezza.
La funzione gets preleva una stringa letta da stdin (tastiera) fino a che non trova un '\n'.
Se tu digiti:"1234567890" e batti invio, lei prende tutti i caratteri. Il resto della funzione converte in int (se riesce) e lo ritorna.
Dato che alla funzione che hai scritto stai passando un vettore, questo viene passato per indirizzo e quindi C cercherà di mettere dentro alla var "scelta" quello che la gets ha letto da tastiera.
Dato che però la tua var può contenere solo 3 elementi, se la stringa è più lunga avverà un buffer overflow con tutti i cazzi e mazzi che conseguono.
O fai in modo che la tua funzioni prelevi solo i primi due caratteri della stringa letta con gets oppure fai modo che la funzione termini se non trova 2 caratteri (sto escludendo il terminatore).
Inoltre non mi è chiaro a cosa ti serve passare la stringa alla tua funzione: se togli il parametro e lo definisci all'iterno e quando chiami non passi nulla, otterresti lo stesso risultato (a livello logico se ho capito il problema); la var esterna non ti serve più e il buffer overflow non si genera. |
|
Top |
|
 |
chemicalbit Dio maturo


Registrato: 01/04/05 18:59 Messaggi: 18597 Residenza: Milano
|
Inviato: 10 Set 2008 09:45 Oggetto: |
|
|
freemind ha scritto: | Inoltre non mi è chiaro a cosa ti serve passare la stringa alla tua funzione: se togli il parametro e lo definisci all'iterno e quando chiami non passi nulla, otterresti lo stesso risultato (a livello logico se ho capito il problema); la var esterna non ti serve più e il buffer overflow non si genera. | Invece a me non è chiaro quello che stai proponendo tu:
con "interno" intendi all'interno delal funzione scegli_numero e con esterno intendi nel main?
Ma facendocosì come posso utilizzare la stringa nel main? |
|
Top |
|
 |
freemind Supervisor sezione Programmazione


Registrato: 04/04/07 21:28 Messaggi: 4643 Residenza: Internet
|
Inviato: 10 Set 2008 11:53 Oggetto: |
|
|
Con interno intendo dentro alla funzione scegli_numero e con esterno intendo la var definita nel main.
Se il problema è solo quello di leggere una stringa da tastiera e convertirla in intero non serve passare alla funzione numero anche la stringa del main; ovviamente se la stringa letta ti serve anche dopo, va bene che la funzione abbia il parametro però bisogna impedire i buffer overflow. |
|
Top |
|
 |
chemicalbit Dio maturo


Registrato: 01/04/05 18:59 Messaggi: 18597 Residenza: Milano
|
Inviato: 10 Set 2008 13:35 Oggetto: |
|
|
Ah, ho capito,
quindi la stringa la generi all'interno della funzione,
e nel main non serve (il main usa il valore int ritornato dalla funzione).
Giusto. |
|
Top |
|
 |
Stemby Eroe in grazia degli dei

Registrato: 29/07/08 23:55 Messaggi: 78 Residenza: Missaglia (LC)
|
Inviato: 10 Set 2008 23:36 Oggetto: |
|
|
chemicalbit ha scritto: | Ah, ho capito,
|
Io invece non troppo: più ho meno ho capito il discorso (in effetti appare anche a me parecchio pleonastico il mio listato) però concretamente come avrei potuto fare? Lo scopo è esattamente e unicamente quello di convertire una stringa in un intero.
Grazie! |
|
Top |
|
 |
chemicalbit Dio maturo


Registrato: 01/04/05 18:59 Messaggi: 18597 Residenza: Milano
|
Inviato: 10 Set 2008 23:50 Oggetto: |
|
|
Stemby ha scritto: | però concretamente come avrei potuto fare? | Nel main usi solo l'int.
Nella funzione (a cui non passi il parametro della stringa), definisci la stringa, prendi l'input e lo metti nella stringa. converti la stringa nell'int, e a quel punto la stringa non ti serve più. La funzione ritornerà il valore dell'int. |
|
Top |
|
 |
|