I want to read exactly N bytes from stdin or a file multiple times, then read less than N bytes once and then read EOF. I expected this to work:
char s[5] = "11111";
while (scanf("L", s) != EOF) {
printf("%s", s);
}
However, when I type 1234567890, it prints 1234156781. This is because with c type modifier it doesn't put \0 after read chars.
Other things I tried:
"%4s"reads until first whitespace"%4[^\n]"andfgetsdo read until first end of line"%4[^\0]"doesn't work (why?)"%4[]"doesn't work"%4"doesn't work
CodePudding user response:
Is there a way to scanf up to N characters including spaces and new lines, and store them as a zero-terminated string
No, not with a single scanf() call.
The below comes close, except it does not consume the '\n', nor does it assign anything (including a null character) to buff[] when the first character is '\n'.
#define N 100
char buf[N 1];
if (scan("0[^\n]", buf) == 1) {
"%4[^\0]" doesn't work (why?)
scanf("%4[^\0]", s) is like scanf("%4[^", s).
Both are UB because the format "%4[^" is invalid. The format parsing stops at the first null character.
Perhaps something pathologic like scanf("%4[\001-\377]", s) will "work", yet scanf() is just not the right solution for this task.
fgets() readily reads 1 line, including the '\n'.
#define N 100
char buf[N 1];
if (fgets(buf, sizeof buf, stdin)) {
...
@Timofey X How does fgets() not meet the function needs?
If OP wants to read past '\n', then use fread().
#define N 100
char buf[N 1];
size_t len = fread(buf, 1, N, stdin);
buf[len] = 0;
CodePudding user response:
I want to read exactly N bytes from stdin or a file multiple times, then read less than N bytes once and then read EOF.
You will generally not encounter end-of-file on stdin when it is connected to a terminal/console, unless the user presses a certain OS-specific key combination, such as CTRL D on Linux or CTRL Z on Microsoft Windows.
You probably want the loop to end when you encounter the end of the line (which is when you encounter the newline character).
When using L with scanf, it will attempt to match exactly 4 characters. However, you want it to match up to 4 characters. Also, in the title of your question, you stated that you want scanf to write a terminating null character.
One way of solving this is to use "%4[^\n]" instead of "L", which will match 1 to 4 characters, instead of exactly 4 characters, and will write a terminating null character.
char s[5];
while ( scanf( "%4[^\n]", s ) == 1 ) {
printf( "%s", s );
}
However, this will not read the newline character into the buffer, so that must be done separately, if you want it.
