learner learner -4 years ago 61
C Question

Scanf reading twice when input is a mix of int and string

I am trying to read from stdin, one integer and then a string char by char:

#include <stdio.h>
int main(int argc, char const *argv[])
{
int T,N,i;
scanf("%d",&T);

while ( T-- )
{
scanf("%d",&N);
printf("N is %d\n",N );
char ch = getchar();

while ( (int)ch != '\n')
{
ch = getchar();
}

// printf("Outside.\n");
}
return 0;
}


My input is:

4
7
cookie milk milk cookie milk cookie milk
5
cookie cookie milk milk milk
4
milk milk milk milk
1
cookie


But when running, I am getting output like:

./COOMILK < input.txt
N is 7
N is 7
N is 5
N is 5


Why is it reading the same values twice?

Answer Source

Think what the user is doing. He types a number and then what? He hits enter! That is newline, which gets inserted in the stdin buffer, awaiting to be read by your program.

So when you try to read characters, the newline which is stored from before gets, which explains the behavior you are witnessing.


There is no need to cast ch to check for the newline in the inner loop. Moreover, the inner loop would be better as a loop.

getchar() returns an int, not a char, so I would change this, and take into account EOF too. Read more in I'm trying to understand getchar() != EOF.

I would change your to this:

int ch;
while ( T-- )
{
    scanf("%d", &N);                     // read the integer
    ch = getchar();                      // consume the newline
    printf("N is %d\n",N );
    do {
       ch = getchar();                   // read the string char by char
       printf("%c", ch);                 // while printing every char
    } while (ch != '\n' || ch == EOF);   // until you see the newline
}

Output:

Georgioss-MacBook-Pro:~ gsamaras$ gcc -Wall main.c 
Georgioss-MacBook-Pro:~ gsamaras$ ./a.out < input.txt 
N is 7
cookie milk milk cookie milk cookie milk
N is 5
cookie cookie milk milk milk
N is 4
milk milk milk milk
N is 1
cookie

As Ed Heal pointed out, you could take advantage of the return value of scanf() to to ensure that it has read an integer. There are numerous way to do this of course, one could be this:

int check;
do {
    check = scanf("%d", &N);
} while(check != 1);
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download