What you need to know
The problem with %[^\n]
is that it fails when the first character to be read is the newline character, and pushes it back into the stdin
.
The Problem
After you enter a number for the first scanf
, you press Enter. %d
in the first scanf
consumes the number, leaving the newline character ('\n'
), generated by the Enter keypress, in the standard input stream (stdin
). %[^\n]
in the next scanf
sees this \n
and fails for the reason given in the first paragraph of this answer.
Fixes
Solutions include:
Changing scanf("%d", &i);
to scanf("%d%*c", &i);
. What %*c
does is, it scans and discards a character.
I wouldn't recommend this way because an evil user could trick the scanf
by inputting something like <number><a character>\n
, ex: 2j\n
and you'll face the same problem again.
Adding a space (any whitespace character will do) before %[^\n]
, i.e, changing scanf("%[^\n]", str);
to scanf(" %[^\n]", str);
as @Bathsheba mentioned in a comment.
What the whitespace character does is, it scans and discards any number of whitespace characters, including none, until the first non-whitespace character.
This means that any leading whitespace characters will be skipped when inputting for the second scanf
.
This is my recommendation: Clear the stdin
after every scanf
. Create a function:
void flushstdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
and call it after every scanf
using flushstdin();
.
Other issues:
Issues unrelated to your problem include:
You don't deal with the case if scanf
fails. This can be due to a variety of reasons, say, malformed input, like inputting an alphabet for %d
.
To do this, check the return value of scanf
. It returns the number of items successfully scanned and assigned or -1 if EOF
was encountered.
You don't check for buffer overflows. You need to prevent scanning in more than 1023 characters (+1 for the NUL-terminator) into str
.
This can be acheived by using a length specifier in scanf
.
- The standards require
main
to be declared using either int main(void)
or int main(int argc, char* argv[])
, not int main()
.
- You forgot to include
stdio.h
(for printf
and scanf
)
Fixed, Complete Program
#include <stdio.h>
void flushstdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
int main(void)
{
int i;
char str[1024];
int retVal;
while((retVal = scanf("%d", &i)) != 1)
{
if(retVal == 0)
{
fputs("Invalid input; Try again", stderr);
flushstdin();
}
else
{
fputs("EOF detected; Bailing out!", stderr);
return -1;
}
}
flushstdin();
while((retVal = scanf("%1023[^\n]", str)) != 1)
{
if(retVal == 0)
{
fputs("Empty input; Try again", stderr);
flushstdin();
}
else
{
fputs("EOF detected; Bailing out!", stderr);
return -1;
}
}
flushstdin();
printf("%d\n", i);
printf("%s\n", str);
return 0;
}