0
votes

NOTE: Please notice this is not a duplicate of Why is scanf() causing infinite loop in this code? , I've already seen that question but the issue there is that he checks for ==0 instead of !=EOF. Also, his problem is different, the "infinite loop" there still waits for user input, it just does not exit.

I have the following while loop:

while ((read = scanf(" (%d,%d)\n", &src, &dst)) != EOF) {
                if(read != 2 ||
                         src >= N || src < 0 ||
                         dst >= N || dst < 0) {
                        printf("invalid input, should be (N,N)");
                } else
                        matrix[src][dst] = 1;
        }

The intention of which is to read input in the format (int,int), to stop reading when EOF is read, and to try again if an invalid input is received.

The probelm is, that scanf works only for the first iteration, after that there is an infinite loop. The program does not wait for user input, it just keeps assuming that the last input is the same.

read, src, and dst are of type int.

I have looked at similar questions, but they seem to fail for checking if scanf returns 0 instead of checking for EOF, and the answers tells them to switch to EOF.

2
remove \n from the scanf - Spikatrix
@user3121023 , that's no good, it will stop recieving input after an invalid input. - Tom Klino
@CoolGuy I actually started without \n, had the same problem. I added it because I seen a recomondation to it from another question. And to your second question, any input - valid or invalid - replicates the issue. - Tom Klino
@Tom , Try int c;while((c=getchar())!='\n' && c!=EOF); in the body of the if - Spikatrix
@Tom , Just add int c;while((c=getchar())!='\n' && c!=EOF); just after printf("invalid input, should be (N,N)"); - Spikatrix

2 Answers

2
votes

You need to use

int c;
while((c=getchar()) != '\n' && c != EOF);

at the end of the while loop in order to clear/flush the standard input stream(stdin). Why? The answer can be seen below:

The scanf with the format string(" (%d,%d)\n") you have requires the user to type

  1. An opening bracket(()
  2. A number(For the first %d)
  3. A comma(,)
  4. A number(For the last %d)

The space(First character of the format string of your scanf) and the newline character(\n which is the last character of the format string of your scanf) are considered to be whitespace characters. Lets see what the C11 standard has to say about whitespace characters in the format string of fscanf(Yes. I said fscanf because it is equivalent to scanf when the first argument is stdin):

7.21.6.2 The fscanf function

[...]

  1. A directive composed of white-space character(s) is executed by reading input up to the first non-white-space character (which remains unread), or until no more characters can be read. The directive never fails

So, all whitespace characters skips/discards all whitespace characters, if any, until the first non-whitespace character as seen in the quote above. This means that the space at the start of the format string of your scanf cleans all leading whitespace until the first non-whitespace character and the \n character does the same.

When you enter the right data as per the format string in the scanf, the execution of the scanf does not end. This is because the \n hadn't found a non-whitespace character in the stdin and will stop scanning only when it finds one. So, you have to remove it.

The next problem lies when the user types something else which is not as per the format string of the scanf. When this happens, scanf fails and returns. The rest of the data which caused the scanf to fail prevails in the stdin. This character is seen by the scanf when it is called the next time. This can also make the scanf fail. This causes an infinite loop.

To fix it, you have to clean/clear/flush the stdin in each iteration of the while loop using the method shown above.

-1
votes

scanf prompts the user for some input. Assuming the user does what's expected of them, they will type some digits, and they will hit the enter key.

The digits will be stored in the input buffer, but so will a newline character, which was added by the fact that they hit the enter key.

scanf will parse the digits to produce an integer, which it stores in the src variable. It stops at the newline character, which remains in the input buffer.

Later, second scanf which looks for a newline character in the input buffer. It finds one immediately, so it doesn't need to prompt the user for any more input.