PDA

View Full Version : [C] Buffer lettura scanf


Unrue
09-05-2008, 16:18
Vorrei riempire delle strutture dinamiche inserendo input da tastiera. Quindi faccio un uso misto delle scanf e di fgets, quest'ultima per gestire input con spazi. Solo che la scanf mi dà problemi, in quanto non svuota il buffer:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>




struct record_lista
{ char nome[20];
char cognome[20];
char indirizzo[20];
int numero_civico;

};

typedef struct record_lista persona;

int main(void){

int dimension;
int i;

printf("Inserisci la dimensione: \n");
scanf("\n%d",&dimension);


persona*array_din=(persona*)malloc(sizeof(persona)*dimension);

i=0;

for(i;i< dimension;i++) {
printf("Entry numero: %d \n", i+1);

printf("Inserisci il nome: \n");
scanf("\n%d",&array_din[i].nome);

printf("Inserisci il cognome: \n");
scanf("\n%d",&array_din[i].cognome);

printf("Inserisci l'indirizzo: \n");
fgets(&array_din[i].indirizzo,sizeof(array_din[i].indirizzo),stdin);

printf("Inserisci il numero civico: \n");
scanf("\n%s",&array_din[i].indirizzo);



}

i=0;
for(i;i< dimension;i++) {
printf("Entry numero: %d \n", i+1);
printf("Nome: %s\n",&array_din[i].nome);
printf("Cognome: %s\n",&array_din[i].cognome);
printf("Indirizzo: %s\n",&array_din[i].indirizzo);
printf("Numero civico: %d\n",&array_din[i].numero_civico);


}

}


So che mettendo il "\n" all'interno della scanf il problema dovrebbe risolversi. Ma non funziona.. Il programma, dopo aver inserito il nome, mi salta direttamente al numero civico.

..::DAVE::..
09-05-2008, 16:20
metodo casalingo:
dopo la scanf:

while(getchar()!='\n');

legge nel buffer fino a che trova un invio

Unrue
09-05-2008, 16:37
metodo casalingo:
dopo la scanf:

while(getchar()!='\n');

legge nel buffer fino a che trova un invio

Mm, ma con getchar non si mette in attesa di un ulteriore immissione dell'utente? Poi non capisco perché non funziona con il "\n" nella scanf. Comunque, facendo come suggerisci , funziona.

..::DAVE::..
09-05-2008, 17:40
Mm, ma con getchar non si mette in attesa di un ulteriore immissione dell'utente? Poi non capisco perché non funziona con il "\n" nella scanf. Comunque, facendo come suggerisci , funziona.

a me hanno sempre consigliato di non mettere nulla tranne i codici di formato nella scanf (%d %c %s ecc) anche perchè, pur essendo una stringa che contiene i codici di formato( " "), credo proprio che il compilatore non se ne faccia nulla di altri caratteri.
i caratteri inseriti da tastiera vanno tutti in stdin quindi con la getchar() vai a utilizzare lo stesso buffer della scanf.

DanieleC88
09-05-2008, 17:45
NAME
fflush - flush a stream

SYNOPSIS
#include <stdio.h>

int fflush(FILE *stream);

DESCRIPTION
The function fflush() forces a write of all user-space buffered data
for the given output or update stream via the stream's underlying write
function. The open status of the stream is unaffected.

If the stream argument is NULL, fflush() flushes all open output
streams.

Unrue
09-05-2008, 21:22
NAME
fflush - flush a stream

SYNOPSIS
#include <stdio.h>

int fflush(FILE *stream);

DESCRIPTION
The function fflush() forces a write of all user-space buffered data
for the given output or update stream via the stream's underlying write
function. The open status of the stream is unaffected.

If the stream argument is NULL, fflush() flushes all open output
streams.

La fflush per lo standard input sapevo che non andava bene.. il comportamento è indefinito.

DanieleC88
09-05-2008, 21:28
Uh hai ragione lo stream è in input! :D

Due sviste in due giorni... no no, dovrò leggere meglio i messaggi prima di rispondere d'ora in poi... :(

Unrue
09-05-2008, 21:28
i caratteri inseriti da tastiera vanno tutti in stdin quindi con la getchar() vai a utilizzare lo stesso buffer della scanf.

OK, però non capisco: la getchar trova il carattere di a capo nel buffer ed esce dal ciclo, che è quello che ha lasciato la scanf precedente, se ho capito bene. E poi? Chi lo svuota il buffer? Sempre la getchar?

dreadknight
09-05-2008, 22:09
So che mettendo il "\n" all'interno della scanf il problema dovrebbe risolversi. Ma non funziona.. Il programma, dopo aver inserito il nome, mi salta direttamente al numero civico.

prima dell'inserimento dati con le printf, aggiungi questa riga:

fflush(stdin);


Inoltre ci sono degli errori:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>




struct record_lista
{ char nome[20];
char cognome[20];
char indirizzo[20];
int numero_civico;

};

typedef struct record_lista persona;

int main(void){

int dimension;
int i;

printf("Inserisci la dimensione: \n");
scanf("\n%d",&dimension);


persona*array_din=(persona*)malloc(sizeof(persona)*dimension);

i=0;

for(i;i< dimension;i++) {
printf("Entry numero: %d \n", i+1);

printf("Inserisci il nome: \n");
gets(array_din[i].nome); /*è una stringa, non un intero*/

printf("Inserisci il cognome: \n");
gets(array_din[i].cognome);

printf("Inserisci l'indirizzo: \n");
gets(array_din[i].indirizzo);

printf("Inserisci il numero civico: \n");
scanf("\n%d",&array_din[i].indirizzo); /*qui invece è un intero, non una stringa*/



}

i=0;
for(i;i< dimension;i++) {
printf("Entry numero: %d \n", i+1);
printf("Nome: %s\n",array_din[i].nome); /*nella printf non si usa la & */
printf("Cognome: %s\n",array_din[i].cognome);
printf("Indirizzo: %s\n",array_din[i].indirizzo);
printf("Numero civico: %d\n",array_din[i].numero_civico);


}

free(array_dyn);

return 0;
}

DanieleC88
09-05-2008, 22:24
prima dell'inserimento dati con le printf, aggiungi questa riga:

fflush(stdin);



No, leggi su, è contro gli standards, ha ragione. Otterresti un comportamento indefinito, è implementata "per funzionare" solo dal compilatore C della Microsoft. Al massimo può leggere fino alla fine o con scanf("%*s"); finché non riceve più nulla.

..::DAVE::..
09-05-2008, 22:29
OK, però non capisco: la getchar trova il carattere di a capo nel buffer ed esce dal ciclo, che è quello che ha lasciato la scanf precedente, se ho capito bene. E poi? Chi lo svuota il buffer? Sempre la getchar?

nessuno lo svuota dato che la getchar si prende l'invio della scanf e non lo riempie in altra maniera...
il buffer avrà sempre i dati di prima ma quello che da fastidio alle scanf è il \n

dreadknight
09-05-2008, 22:32
c'erano degli errori nel codice, penso di aver corretto tutto. Ora bisogna solo compilare e vedere se funziona

Unrue
10-05-2008, 12:31
prima dell'inserimento dati con le printf, aggiungi questa riga:

fflush(stdin);


Inoltre ci sono degli errori:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>




struct record_lista
{ char nome[20];
char cognome[20];
char indirizzo[20];
int numero_civico;

};

typedef struct record_lista persona;

int main(void){

int dimension;
int i;

printf("Inserisci la dimensione: \n");
scanf("\n%d",&dimension);


persona*array_din=(persona*)malloc(sizeof(persona)*dimension);

i=0;

for(i;i< dimension;i++) {
printf("Entry numero: %d \n", i+1);

printf("Inserisci il nome: \n");
gets(array_din[i].nome); /*è una stringa, non un intero*/

printf("Inserisci il cognome: \n");
gets(array_din[i].cognome);

printf("Inserisci l'indirizzo: \n");
gets(array_din[i].indirizzo);

printf("Inserisci il numero civico: \n");
scanf("\n%d",&array_din[i].indirizzo); /*qui invece è un intero, non una stringa*/



}

i=0;
for(i;i< dimension;i++) {
printf("Entry numero: %d \n", i+1);
printf("Nome: %s\n",array_din[i].nome); /*nella printf non si usa la & */
printf("Cognome: %s\n",array_din[i].cognome);
printf("Indirizzo: %s\n",array_din[i].indirizzo);
printf("Numero civico: %d\n",array_din[i].numero_civico);


}

free(array_dyn);

return 0;
}


La gets è deprecata. Non capisco perché è un errore usare la fgets al posto della tua consigliata gets :mbe:

Unrue
10-05-2008, 12:36
nessuno lo svuota dato che la getchar si prende l'invio della scanf e non lo riempie in altra maniera...
il buffer avrà sempre i dati di prima ma quello che da fastidio alle scanf è il \n

Ma se la getchar legge il '\n' senza toglierlo dal buffer, una eventuale scanf successiva non si ritrova con lo stesso problema?

dreadknight
10-05-2008, 12:44
La gets è deprecata. Non capisco perché è un errore usare la fgets al posto della tua consigliata gets :mbe:

ma hai letto le correzioni? di errori ce n'erano parecchi, se poi vuoi usare fgets fai pure

..::DAVE::..
10-05-2008, 12:44
Ma se la getchar legge il '\n' senza toglierlo dal buffer, una eventuale scanf successiva non si ritrova con lo stesso problema?

leggendo lo 'passa' e poi legge dall'immissione successiva...

Unrue
10-05-2008, 12:55
ma hai letto le correzioni? di errori ce n'erano parecchi, se poi vuoi usare fgets fai pure

Ora funziona tutto. Grazie a tutti :)

Unrue
10-05-2008, 12:59
leggendo lo 'passa' e poi legge dall'immissione successiva...

Dunque, quindi la scanf legge la stringa immessa e si ferma al '\n', solo che non fa avanzare il puntatore del buffer alla posizione successiva, quindi la scanf dopo continua a leggerlo? Invece il getchar legge il '\n' ma avanza il puntatore. Credo sia così.

..::DAVE::..
10-05-2008, 14:49
Dunque, quindi la scanf legge la stringa immessa e si ferma al '\n', solo che non fa avanzare il puntatore del buffer alla posizione successiva, quindi la scanf dopo continua a leggerlo? Invece il getchar legge il '\n' ma avanza il puntatore. Credo sia così.

esatto

Unrue
11-05-2008, 13:06
Trallaltro, sempre una cosa che non ricordo legato a questo esempio: sia la printf che la scanf prendono in ingresso un puntatore a char. Come mai allora nella printf non ci va il & e nella scanf si, quando si passano i parametri?

..::DAVE::..
11-05-2008, 13:29
Trallaltro, sempre una cosa che non ricordo legato a questo esempio: sia la printf che la scanf prendono in ingresso un puntatore a char. Come mai allora nella printf non ci va il & e nella scanf si, quando si passano i parametri?

il puntatore a char si riferisce alla stinga di controllo ("%d" per esempio essendo una stringa un vettore di char (char*))

DanieleC88
11-05-2008, 13:58
Perché printf() deve solo leggere quei valori, scanf() ha bisogno del puntatore a quei valori per scriverci sopra (ad esempio per un char*, che è già un puntatore, non usi & né con printf() né con scanf(); per un int, invece, devi passare un int semplice a printf() e un int* a scanf()).