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]"
andfgets
do 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.