0

So, the program will scan what user type in like "ENQUEUE A" or "DEQUEUE" or "Ctrl^Z". While "Ctrl^Z" will stop the program.

'Cause "ENQUEUE A" have a space, I use while(scanf("%[^\n]", input)==EOF) to keep user typing in until "ctrl^Z" being typed.

But the result is the while loop will automatically start even the user not typing anything, and the loop will keep going forever.

int main()
{
    char input[9];

    puts("\nEnter ENQUEUE (member) or DEQUEUE to process, or Ctrl^Z to stop 
program:");
    while(scanf("%[^\n]", input)!=EOF)
    {
        puts("processing");
    }
}

Thanks for anyone who answering, and sorry for my bad English.

This program intend to deal some Queue issue. And user can type like "ENQUEUE A" to enqueue this letter into queue, or "DEQUEUE" to dequeue it.

The while loop I have now is just for debug test, so it only have one puts function.

The user can keep doing these action until they enter Ctrl+Z. But in my program, even the user hasn't type anything, the loop just automatically going on an infinite loop. And it even not let user type anything.

  • 1
    To read lines use [`fgets`](https://en.cppreference.com/w/c/io/fgets) instead. – Some programmer dude Nov 01 '19 at 08:22
  • As for your problem, can you please elaborate on it? You have a program which have a loop which iterates as long as `scanf` doesn't return `EOF`. And `scanf` will block until something is read (or you press `Ctrl-Z`, possibly followed by `Enter` (Windows is weird that way)). – Some programmer dude Nov 01 '19 at 08:23
  • but fgets cant compare to EOF? – Newbie programmer Nov 01 '19 at 08:24
  • Please read the linked reference, it will tell you what happens when there's an error (or "end of file"). – Some programmer dude Nov 01 '19 at 08:28
  • The loop you have is not infinite, even if it might seem like that since `scanf` won't return until it either have read something matching the format, or there's an error or EOF. Is the problem you have really in the code you show? Please try to create a [mcve] which replicates your problem and that we ourselves can try. Also please take some time to read about [how to ask good questions](http://stackoverflow.com/help/how-to-ask), as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – Some programmer dude Nov 01 '19 at 08:32
  • 2
    I don't suppose the code **before** the incomplete code list you're showing us here performs any input from stdin, like, say, an integer, a string, near anything? Might wanna think about that. Regardless, we don't have a [mcve], which is kind of critical if you want concrete answers, otherwise this is just a guess festival (like I just did). – WhozCraig Nov 01 '19 at 08:38
  • Be careful, the array `input` can't hold a string like `"ENQUEUE X"`! Don't forget that in C all strings are ***null-terminated***. For a string to be able to hold nine characters, it must have space for *ten* to fit the terminator. If it doesn't then `scanf` will write out of bounds and you will have *undefined behavior*. – Some programmer dude Nov 01 '19 at 08:39
  • Thanks for advice! I'll try it out and see if works. – Newbie programmer Nov 01 '19 at 08:44
  • @Someprogrammerdude "since scanf won't return until it either have read something matching the format, or there's an error or EOF" misses one case. When the first character read is a `'\n'`, `scanf("%[^\n]", input)` returns right away. – chux - Reinstate Monica Nov 01 '19 at 08:51
  • Still can't even I give him 1000 slot. Guessing that scanf() might be executed only at first loop but not in the following loop? – Newbie programmer Nov 01 '19 at 08:52
  • @chux I would argue that case still is "matching the format", as the format in this case tells `scanf` to "read everything until a newline is encountered". :) – Some programmer dude Nov 01 '19 at 08:54
  • @Someprogrammerdude `scanf("%[^\n]",...)` with a `'\n'` input returns 0. The C spec calls that a failure: "Otherwise, the function returns the number of input items assigned, ..., or even zero, in the event of an early matching failure." – chux - Reinstate Monica Nov 01 '19 at 09:06

2 Answers2

2

scanf("%[^\n]", input) never reads a '\n'.

If input is "123\n", scanf("%[^\n]", input) will first read "123" and return 1.

On the 2nd loop scanf("%[^\n]", input), will attempt to read "\n", fail leaving '\n' in stdin, input unchanged and return 0.

On the 3rd loop scanf("%[^\n]", input), will attempt to read the same "\n", fail and return 0 and so on.

A dirty alternative is below: (space, width and compare to 1)

while(scanf(" %8[^\n]", input) == 1)

A better approach is to first read with fgets()

while(fgets(input, sizeof input , stdin)) {
    puts("processing");
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

The problem is that the %[ format doesn't consume leading white-space.

When you call it the first time, the newline added to the input buffer from the Enter key will still be left in the buffer. This will be read as the first character in the next call, and will indeed lead to an infinite loop.

There are three improvements you can make to make your code work and work better:

  1. Compare the result of scanf not against EOF but against 1, as scanf will return 1 is something was successfully scanned.

  2. Add a width-specifier to the format so scanf will not write out of bounds of your array.

  3. Add a leading space in the format string to skip (and ignore) leading possible white-space, like newlines.

So your loop should look something like this instead:

while(scanf(" %8[^\n]", input)==1)

The width 8 is for the input buffer you show in your question. It should be equal to the size minus one.


A better solution to read lines is to use fgets instead, as I already mentioned. It will consume the newline, and will not write beyond the bounds of your array (unless you specify the wrong size).

This would then be something like

while (fgets(input, sizeof input, stdin) != NULL)
{
    input[strcspn(input, "\n")] = 0;  // Remove the (possible) newline that `fgets` leaves in your buffer

    // ... rest of your code...
}
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621