Indice del forum Olimpo Informatico
I Forum di Zeus News
Leggi la newsletter gratuita - Attiva il Menu compatto
 
 FAQFAQ   CercaCerca   Lista utentiLista utenti   GruppiGruppi   RegistratiRegistrati 
 ProfiloProfilo   Messaggi privatiMessaggi privati   Log inLog in 

    Newsletter RSS Facebook Twitter Contatti Ricerca
[C] Niubbissimo: dov'è l'errore?
Nuovo argomento   Rispondi    Indice del forum -> Programmazione
Precedente :: Successivo  
Autore Messaggio
Stemby
Eroe in grazia degli dei
Eroe in grazia degli dei


Registrato: 29/07/08 23:55
Messaggi: 78
Residenza: Missaglia (LC)

MessaggioInviato: 30 Lug 2008 00:04    Oggetto: [C] Niubbissimo: dov'è l'errore? Rispondi citando

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
Profilo Invia messaggio privato
Ramon
Semidio
Semidio


Registrato: 07/07/06 01:50
Messaggi: 342

MessaggioInviato: 30 Lug 2008 00:35    Oggetto: Devi prevedere anche il tasto [Invio] Rispondi citando

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
Profilo Invia messaggio privato
Zeus
Amministratore
Amministratore


Registrato: 21/10/00 02:01
Messaggi: 13287
Residenza: San Junipero

MessaggioInviato: 30 Lug 2008 00:45    Oggetto: Rispondi citando

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
Profilo Invia messaggio privato HomePage
Stemby
Eroe in grazia degli dei
Eroe in grazia degli dei


Registrato: 29/07/08 23:55
Messaggi: 78
Residenza: Missaglia (LC)

MessaggioInviato: 30 Lug 2008 07:54    Oggetto: Rispondi citando

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 Shocked

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
Profilo Invia messaggio privato
freemind
Supervisor sezione Programmazione
Supervisor sezione Programmazione


Registrato: 04/04/07 21:28
Messaggi: 4643
Residenza: Internet

MessaggioInviato: 30 Lug 2008 10:00    Oggetto: Rispondi citando

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
Profilo Invia messaggio privato
Stemby
Eroe in grazia degli dei
Eroe in grazia degli dei


Registrato: 29/07/08 23:55
Messaggi: 78
Residenza: Missaglia (LC)

MessaggioInviato: 09 Set 2008 00:29    Oggetto: Rispondi citando

Proseguo la discussione: niubbissimo ero e niubbissimo sono ancora Very Happy (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 Very Happy

Grazie!
Top
Profilo Invia messaggio privato
SverX
Supervisor Macchinisti
Supervisor Macchinisti


Registrato: 25/03/02 12:16
Messaggi: 11810
Residenza: Tokelau

MessaggioInviato: 09 Set 2008 10:06    Oggetto: Rispondi citando

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
Profilo Invia messaggio privato HomePage
Stemby
Eroe in grazia degli dei
Eroe in grazia degli dei


Registrato: 29/07/08 23:55
Messaggi: 78
Residenza: Missaglia (LC)

MessaggioInviato: 09 Set 2008 23:42    Oggetto: Rispondi citando

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? Shocked

Grazie!
Top
Profilo Invia messaggio privato
freemind
Supervisor sezione Programmazione
Supervisor sezione Programmazione


Registrato: 04/04/07 21:28
Messaggi: 4643
Residenza: Internet

MessaggioInviato: 10 Set 2008 00:25    Oggetto: Rispondi citando

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
Profilo Invia messaggio privato
chemicalbit
Dio maturo
Dio maturo


Registrato: 01/04/05 18:59
Messaggi: 18597
Residenza: Milano

MessaggioInviato: 10 Set 2008 09:45    Oggetto: Rispondi citando

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
Profilo Invia messaggio privato
freemind
Supervisor sezione Programmazione
Supervisor sezione Programmazione


Registrato: 04/04/07 21:28
Messaggi: 4643
Residenza: Internet

MessaggioInviato: 10 Set 2008 11:53    Oggetto: Rispondi citando

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
Profilo Invia messaggio privato
chemicalbit
Dio maturo
Dio maturo


Registrato: 01/04/05 18:59
Messaggi: 18597
Residenza: Milano

MessaggioInviato: 10 Set 2008 13:35    Oggetto: Rispondi citando

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
Profilo Invia messaggio privato
Stemby
Eroe in grazia degli dei
Eroe in grazia degli dei


Registrato: 29/07/08 23:55
Messaggi: 78
Residenza: Missaglia (LC)

MessaggioInviato: 10 Set 2008 23:36    Oggetto: Rispondi citando

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
Profilo Invia messaggio privato
chemicalbit
Dio maturo
Dio maturo


Registrato: 01/04/05 18:59
Messaggi: 18597
Residenza: Milano

MessaggioInviato: 10 Set 2008 23:50    Oggetto: Rispondi

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
Profilo Invia messaggio privato
Mostra prima i messaggi di:   
Nuovo argomento   Rispondi    Indice del forum -> Programmazione Tutti i fusi orari sono GMT + 2 ore
Pagina 1 di 1

 
Vai a:  
Non puoi inserire nuovi argomenti
Non puoi rispondere a nessun argomento
Non puoi modificare i tuoi messaggi
Non puoi cancellare i tuoi messaggi
Non puoi votare nei sondaggi