1

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?

gsamaras
  • 71,951
  • 46
  • 188
  • 305
learner
  • 4,614
  • 7
  • 54
  • 98

2 Answers2

3

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.

As Ed Heal pointed out, you could take advantage of the return value of scanf() to to ensure that it has read an integer.

I would change your to this:

int ch;
while ( T-- )
{
    if(scanf("%d", &N) != 1) // read the integer and check the return value
    {
        printf("I was expecting to read an integer! Exiting...\n");
        return 1;
    }
    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
Community
  • 1
  • 1
gsamaras
  • 71,951
  • 46
  • 188
  • 305
1

With some clever?! use of scanf - See manual page - you can simplify the code to:

#include <stdio.h>
int main(int argc, char const *argv[])
{
    int T,N,i;
    if (scanf("%d\n",&T) != 1) { // Notice the new line
       // Do so error reporting
       return 1;
    }

    while ( T-- )
    {
        if (scanf("%d\n%*[^\n]\n",&N) != 1) { // Please see scanf for an explaination
           // Do some error reporting
           return 1;
        }
    }
    return 0;
}

EDIT

Explanation of scanf format

  1. %d - Read integer
  2. \n - Read new line
  3. %*[^\n} - Read anything but new line, throwing away the result
  4. \n - Finally read a new line
Ed Heal
  • 59,252
  • 17
  • 87
  • 127
  • 2
    Detail: `"\n"` does not only read a new line, it will read 0 or more white spaces including a new line(s). – chux - Reinstate Monica May 21 '17 at 10:32
  • @chux - Good point - But after reading `%*[^\n]` can it be anything else? – Ed Heal May 21 '17 at 10:32
  • 1
    1) No, yet `'\n'` is used after `"%d"` too. 2) An unexpected result of `scanf("%d\n%*[^\n]\n",&N)` is that the function does not return until some non-white-space is entered after `"123\nabc\n"`. To reads _lines_ as OP implies with `while(\n)`, better to use `fgets()` as `scanf()` is the wrong tool for this job. – chux - Reinstate Monica May 21 '17 at 10:39