Search code examples
cinputscanf

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


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("%4c", 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

Solution

  • 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("%100[^\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;