Problem with scanf

  • Thread starter diegotorquemada
  • Start date
D

diegotorquemada

Hello,

I am wondering why scanf is not reading my data properly:

#include<stdio.h>

// gcc -Wall -std=c99 -o 07_struct 07_struct.c

typedef struct
{
int cod;
char name[50];
char sex;
} person;

int main()
{
int i, n;

printf("How many people = ");
scanf("%d", &n);

person p[n];
for (i=0; i<n; i++)
{
printf("PERSON %d:\n", i+1);
printf("Code = "); scanf("%d", &(p.cod));
printf("Name = "); fgets(p.name, sizeof(p.name), stdin);
printf("Sex M/F = "); scanf("%c", &(p.sex));
printf("\n");
}

puts("\n----------------------------------------------------------------\n");

for (i=0; i<n; i++)
{
printf("PERSON %2d:\n", i+1);
printf("Cod = %d\n", p.cod);
printf("Name = %s\n", p.name);
printf("Sex M/F = %c\n\n", p.sex);
}

return 0;
}



The output of my program is:

diego@earendil:~/programas$ gcc -Wall -std=c99 -o 07_struct 07_struct.c
diego@earendil:~/programas$ ./07_struct
How many people = 3
PERSON 1:
Code = 12
Name = Sex M/F = Andrew

PERSON 2:
Code = Name = Sex M/F = Maria

PERSON 3:
Code = Name = Sex M/F = Robert


----------------------------------------------------------------

PERSON 1:
Cod = 12
Name =

Sex M/F = A

PERSON 2:
Cod = -1208399088
Name = ndrew

Sex M/F = M

PERSON 3:
Cod = -1081416063
Name = aria

Sex M/F = R



can somebody please help me?

Thanks

Diego
 
I

Ivan Shmakov

diegotorquemada said:
Hello, I am wondering why scanf is not reading my data properly:
[...]

printf("Code = "); scanf("%d", &(p.cod));
printf("Name = "); fgets(p.name, sizeof(p.name), stdin);
printf("Sex M/F = "); scanf("%c", &(p.sex));


That's simple. In the example, the input data contains:

12<NEWLINE>
Andrew<NEWLINE>

First scanf () reads "12", the following fgets () reads
<NEWLINE>, and then the second scanf () reads "A".

The next iteration gives "no data" for the first scanf () (thus
p[1].cod remains uninitialized -- that's why one'd /always/
check the scanf's return value!), then "ndrew\n" for the name,
and "M" for the second scanf ().

Kaj tiel plu.

[...]
 
J

John Gordon

In said:
I am wondering why scanf is not reading my data properly:

When you do something like this:

scanf("%d", &n);

The user types a number and presses Enter. scanf looks at the format
string, sees %d, and converts the typed number to an integer. However,
you didn't tell scanf to do anything with the Enter ekypress, so it is
left sitting in the input buffer.

Then the call to fgets sees the leftover Enter keypress in the input
stream and gets a blank line.

Generally the best way to fix this is to use fgets() for all your input.
 
D

diegotorquemada

diegotorquemada <[email protected]> writes:


Hello, I am wondering why scanf is not reading my data properly:


[...]



printf("Code = "); scanf("%d", &(p.cod));

printf("Name = "); fgets(p.name, sizeof(p.name), stdin);

printf("Sex M/F = "); scanf("%c", &(p.sex));




That's simple. In the example, the input data contains:



12<NEWLINE>

Andrew<NEWLINE>



First scanf () reads "12", the following fgets () reads

<NEWLINE>, and then the second scanf () reads "A".



The next iteration gives "no data" for the first scanf () (thus

p[1].cod remains uninitialized -- that's why one'd /always/

check the scanf's return value!), then "ndrew\n" for the name,

and "M" for the second scanf ().


You are right Ivan. However said:
Kaj tiel plu.



[...]
 
A

Anand Hariharan

 > Hello, I am wondering why scanf is not reading my data properly:

 >       printf("Code    = ");   scanf("%d", &(p.cod));

 >       printf("Name    = ");   fgets(p.name, sizeof(p.name), stdin);

 >       printf("Sex M/F = ");   scanf("%c", &(p.sex));

   That's simple.  In the example, the input data contains:


   First scanf () reads "12", the following fgets () reads
   <NEWLINE>, and then the second scanf () reads "A".
   The next iteration gives "no data" for the first scanf () (thus
   p[1].cod remains uninitialized -- that's why one'd /always/
   check the scanf's return value!), then "ndrew\n" for the name,
   and "M" for the second scanf ().

You are right Ivan. However, I still do not know how to remove that <NEWLINE> before putting the next scanf() or fgets().



Section 12 in C FAQ might help.

- Anand
 
D

diegotorquemada

Section 12 in C FAQ might help.



- Anand

Thanks Anand... I found the solution there. It was:

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

typedef struct
{
int cod;
char nombre[100];
char sexo;
} persona;

void vaciar_buffer_teclado(void);
void leer_cadena(int n, char cad[n]);

int main()
{
int i, n;
char tmp[100];

printf("Numero de personas = ");
scanf("%d", &n); vaciar_buffer_teclado();

persona p[n];
for (i=0; i<n; i++)
{
printf("PERSONA %d:\n", i+1);
printf("Codigo = ");
scanf("%d", &(p.cod)); vaciar_buffer_teclado();

printf("Nombre = ");
leer_cadena(sizeof(p.nombre), p.nombre);

printf("Sexo M/F = ");
scanf("%s", tmp); vaciar_buffer_teclado();
p.sexo = toupper(tmp[0]);

printf("\n");
}

puts("\n----------------------------------------------------------------\n");

for (i=0; i<n; i++)
{
printf("PERSONA %2d:\n", i+1);
printf("Codigo = %d\n", p.cod);
printf("Nombre = %s\n", p.nombre);
printf("Sexo M/F = %c\n\n", p.sexo);
}

return 0;
}

void vaciar_buffer_teclado(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
return;
}

void leer_cadena(int n, char cad[n])
{
char *p;
if (fgets(cad, n, stdin) == NULL) exit(EXIT_FAILURE);
if ((p = strchr(cad, '\n')) != NULL) *p = '\0'; // remueva el \n
return;
}
 
A

Anand Hariharan

Thanks Anand... I found the solution there. It was:

Some errors/flaws in your solution, am afraid.

(...)
   scanf("%d", &n); vaciar_buffer_teclado();

Check scanf's return value. See Ivan Shmakov's post upthread.

(...)
      scanf("%s", tmp); vaciar_buffer_teclado();

Using scanf with a %s is as bad as gets(). In your case, since you
have
decided that the user's input could never be more than 99 characters
long,
you could just as well put that in the format specifier.


In general, doing I/O (especially the 'I' in I/O) in C is cumbersome,
very easy to go wrong and worse, not even know that you went wrong.
If you
are learning C, there are other constructs and concepts in the
language that
you can invest your time in learning. Rather than get the inputs from
the
console, consider hard-coding your inputs within the code.

my $0.02,
- Anand
 
E

Edward A. Falk

You are right Ivan. However, I still do not know how to remove that <NEWLINE> before
putting the next scanf() or fgets().

I generally avoid scanf() for reasons like this. I prefer fgets() followed
by sscanf()

char line[MAXLINE];

if (fgets(line, sizeof(line), stdin) == NULL) die();
if (sscanf(line, "%d", &code) != 1) die();
if (fgets(name, sizeof(name), stdin) == NULL) die();
if (fgets(line, sizeof(line), stdin) == NULL) die();
if (sscanf(line, "%c", &sex) != 1) die();

You'll also have to trim the trailing newline from name. Actually, do it
right and trim *all* trailing whitespace from name. That's an exercise for
another day, however.

You can also get a little fancy with conversion suppression and scansets:

if (scanf("%d%*[^\n]\n", &code) != 1) die();
if (fgets(name, sizeof(name), stdin) == NULL) die();
if (scanf("%c%*[^\n]\n", &sex) != 1) die();

but it's kind of unreadable. I generally try to avoid excessive
cleverness when I code. As Brian Kernighan once wrote:

Everyone knows that debugging is twice as hard as writing a program in
the first place. So if you're as clever as you can be when you write
it, how will you ever debug it?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top