user6085089
user6085089

Reputation:

Why does my scanf while loop not exit when consuming newline characters?

// Some initialization code

dup2(fd[0], fileno(stdin));

// This process is receiving the output of "ls -1"

while (scanf("%[^\n]s", someCharArray) > 0) {
    scanf("%*c");
    printf("%s\n", someCharArray);
}

This successfully prints all the files. However, the loop never exits. If I take away scanf("%*c"), it does exit, but only the first filename is printed.

I would expect the consuming of the newline character will prepare the outer scanf to scan the next filename, which is what it seems to be doing. But after the final filename is scanned, I expect the nested scanf to not scan anything. Then the outer scanf to not scan anything either. And the while loop exits.

Why is this happening?

Upvotes: 2

Views: 980

Answers (1)

chux
chux

Reputation: 153498

Loop does not exit as it is waiting for more input.

You can

  1. send a pair of \n\n so scanf("%[^\n]... returns 0 as it fails to scan the 2nd \n, or

  2. close stdin (in an implementation specific way) so scanf() return EOF, a negative number.

Better to use fgets(). @WhozCraig Although it is still unclear under what condition you want the loop to end (other than stdin closure).

while (fgets(someCharArray, sizeof someCharArray, stdin)) {
  // Lop off potential trailing \n if desired
  someCharArray[strcspn(someCharArray, "\n")] = '\0';

  printf("%s\n", someCharArray);
}

Note: the "s" in scanf("%[^\n]s", someCharArray) serves no purpose - drop it. Also this format, without a width, does not limit the maximum number of character scanned in to someCharArray and should not be used in quality code.


I would expect the consuming of the newline character will prepare the outer scanf to scan the next filename, which is what it seems to be doing.

Yes - that right. The earlier scanf("%[^\n]... has no limit on the number of characters scanned which could lead to undefined behavior (UB), so why expect the rest of code to behave?

But after the final filename is scanned, I expect the nested scanf to not scan anything.

If the final final filename has a '\n' after it, scanf("%*c"); will consume it. If the final filename lacks any following character, scanf("%*c"); will patiently wait for a character. If the input stream has been close, it will return EOF instead of waiting. Code does not report/test the result of scanf("%*c"); so we are left to guess.

Then the outer scanf to not scan anything either. And the while loop exits.

True, if the first character to scan is a '\n', it will remain in stdin and scanf() will return 0. if stdin is closed, scanf() will return the negative number EOF.

Upvotes: 1

Related Questions