Can't figure out what happen with scanf("%[^\n]\n", input) in C language

Viewed 251
char str[20];
scanf("%[^\n]\n", str);
printf(">>>>%s\n", str);

This is my understanding: the first part "[^\n]" means accepting any character except '\n' in order to obtain some character, like the space, from function scanf and store it in str. The second \n is for match the \n which ends the scanf, otherwise the \n will release in input stream and left to next input action.

But when I run it, the result confused me.

xhkjdeiMac:c xhkj$ ./hello
aaaaaaa
ccc
>>>>aaaaaaa

As you can see, I first enter aaaaaaa and hit the enter key, I think it store the aaaaaa into str and already match the \n. But I have to enter something else, like ccc, then I can go to next step and print the str out on the console.

So why did it happen? why should I have to enter something else and hit the enter key again to finish the scanf?

1 Answers
char str[20];
scanf("%[^\n]\n", str);

OP: the first part "[^\n]" means accepting any character except '\n' in order to obtain some character, .... and store it in str.

Not quite.

If the first character read is a '\n', scanning stops. Nothing saved in str, no null character is appended, '\n' remains in stdin and function returns 0 or EOF ( I forget, but it is not 1)

Else non-'\n' characters are read and saved until a '\n' is read. That '\n' is put back into stdin, a null character is appended to str. Scanning continues with format "\n". If 20 or more characters were read, the result in undefined behavior.


Main problem

OP: The second \n is for match the \n which ends the scanf, otherwise the \n will release in input stream and left to next input action.

No. Format "\n" matches any number of white-space, not just 1 '\n'. scanf() consumes white-spaces like '\n', ' ', '\t', ..., until a non-white-space character is read. That non-white-space character is then put back into stdin.

OP: why should I have to enter something else and hit the enter key again to finish the scanf?

The program is waiting was a non-white-space character before it returns. Since stdin is typically line buffered, that non-white-space character is not given to scanf() until it has a following '\n'.


scanf("%[^\n]\n", str); is problematic. Use fgets(). Check return values.

char str[20];
if (fgets(str, sizeof str, stdin)) {
  str[strcspn(str, "\n")] = '\0'; // lop off potential trailing \n if desired
  printf(">>>>%s\n", str);
}

If one, sigh, must use scanf(), consider:

*str = 0;              // Handle case when first letter is \n
scanf("%19[^\n]", str);// Consume up to 19 characters
scanf("%*1[\n]");      // Consume 1 \n if present-independent of success of previous
Related