Home > Net >  Is there a way to scanf up to N characters including spaces and new lines, and store them as a zero-
Is there a way to scanf up to N characters including spaces and new lines, and store them as a zero-

Time:12-28

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]" and fgets 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.

  • Related