3

I have trouble with scanf and a loop on linux.

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

int main(int argc, char ** argv){
    int i = 0;
    char s[255];
    char c;

    while(i<10){
        printf("Here : ");
        scanf(" %s", s);
        printf("%s\n", s);
        i++;
        while((c = getchar()) != '\n' && c != EOF);
    }

    return EXIT_SUCCESS;
}

If in the shell Linux, if I execute my file like this :

echo "lol" | ./testWhileScanf

Then the result will be this :

Here : lol

Here : lol

Here : lol

Here : lol

Here : lol

Here : lol

Here : lol

Here : lol

Here : lol

Here : lol

I dont know why this is the result, a line of my code is to flush the stdin, to not have this kind of problem.

Seeking for solution I tried : __fpurge, fpurge, fflush But none worked.

I would like to get only :

Here ? : lol

Here ? :

And waiting for input. Surely I am missing something here.. but I can't figure what =/

Community
  • 1
  • 1
KlossOne
  • 73
  • 1
  • 8
  • 1
    First, rewrite this code using `fgets` instead of `scanf`. `fgets` has much more sensible behavior. Second, "waiting for input" from the terminal cannot happen when input is being taken from a pipe. – zwol Jan 30 '17 at 22:37
  • In my final code, I use fgets, but here for my test I made it more simple (for me). Oh, I didnt think of that. But then why is "lol" still wrote ? is it because the char * s is not updated with the next scanf ? – KlossOne Jan 30 '17 at 22:40
  • You shouldn't have done that. `scanf` may *seem* simpler, but `fgets` has better ergonomics; using it would have nudged you in the direction of not making the mistake you made. (In fact, you should [never use `scanf` at all](https://stackoverflow.com/questions/24302160/scanf-on-an-istream-object/24318630#24318630).) – zwol Jan 30 '17 at 22:43
  • Ok thank you! How can I put your answer as the good one ? ( I can upvote a comment but.. ) – KlossOne Jan 30 '17 at 22:45
  • If I had written an answer, it would have been identical to dasblinkenlight's answer, except that it would have concluded with "anyway, don't use `scanf`, use `fgets`." I have plenty of imaginary internet points already and will not miss a few more. – zwol Jan 30 '17 at 22:47
  • 2
    Note that you should use `int c;` (not `char c;`) as you will get confusing results for some valid input values on some systems and no EOF detection on some other systems. – Jonathan Leffler Jan 30 '17 at 22:51

1 Answers1

4

When you call

scanf(" %s", s);

for the first time, it sets s to lol, and returns 1. When you call it for the second time, there is no further input, so scanf returns zero without setting your variable. However, your code ignores the return value of scanf, and prints s anyway.

Adding a check and a break should fix this problem:

if (scanf(" %254s", s) != 1) break;

Note the size limiter in the format string, it will prevent scanf from causing buffer overruns.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 3
    I'd add to @KlossOne that you probably didn't notice this while running the program interactively because terminal I/O is line buffered by default. So after the first line, the program "waits" for the next input (which would overwrite `s` anyway and cause you to not notice this). In the pipe, the end is reached so there is nothing more to read and your code runs the 10 times. You can simulate what happened if you run interactively, input one line and then hit control-D to insert a end-of-file. – sidyll Jan 30 '17 at 22:49
  • 1
    In either case, space before `%` in the format string is redundant. – AnT stands with Russia Jan 30 '17 at 22:54
  • Thanks, I now better understand the why ^^ – KlossOne Jan 30 '17 at 23:00