简体   繁体   中英

User typing null terminator in scanf

Can a user type null terminator in an input, for which scanf is used, so the length of the input would be 0?

char msg[1000];
scanf("%1000s",msg); // the user would type nothing: '' or '\0'

On many systems, the answer is "Yes".

Usually, the magic sequence is Control-@ .

The character code for @ is usually 64, one less the that of A (65). Control-A is character code 1; one less is character code 0, aka '\\0' .

Note that to get a zero-length input, you'd have to type the null byte as the first non-space character, and you would still need to hit return to enter the input. Your program would find it hard to reliably identify what else was entered after the null byte.

Some systems allow the terminal user to enter a NUL byte by pressing Ctrl - @ . scanf() would then store this byte into the destination array, but would most likely not consider this byte to constitute a word separator, so input parsing would continue until end of file or a whitespace character such as newline is entered.

There is no way to tell from the destination array if a NUL byte was stored after other characters, nor precisely how many further characters have been read after this NUL byte. But if scanf() returned 1 and msg has a zero length, the only possibility is that the user entered a NUL byte after a possibly empty sequence of whitespace characters.

This would also be the only possibility for fgets() to return an empty string when passed a destination array with a size greater than 1.

If input is read from a file instead of a terminal, it is always a possibility for the file to contain NUL bytes and care should be taken to avoid undefined behavior if it happens. For example, here is a classic bug:

char msg[1000];
if (fgets(msg, sizeof msg, stdin)) {
    int len = strlen(msg);
    if (msg[len - 1] == '\n') {  // potential undefined behavior!
        msg[--len] = '\0'       // potential undefined behavior!
    }
    ...
}

Also note that your code has a flaw: the maximum number of characters to store into the destination should be 999 , not 1000 :

char msg[1000];
if (scanf("%999s",msg) == 1) {
    /* word was read from the user */
    if (*msg == '\0') {
        printf("user entered a NUL byte\n");
    }
}

Can a user type null terminator in an input, for which scanf is used, so the length of the input would be 0?

In addition to a user typing in a null character , stdin could use re-directed input that contains null characters.

foo < data.bin

Detail: When the first character scanned is a null character or '\\0' , it is read like any other character and saved like any other non-white-space character. So the length of input is still more than 0, but the value reported by strlen(msg) is fooled by the embedded null character and returns zero.

fgets() has the same problem as scanf() in this regard: strlen(msg) does not alway report the number of characters read.

Non-standard getline() does return the number of characters read and is a way out of this.


@Stargateur mentions using "%n" to store the number of characters saved in msg . Perhaps like

char msg[1000 + 1];
int start, end;
if (1 == scanf(" %n%1000s%n", &start, msg, &end)) {
  printf("%d characters read\n", end - start);
}

IAC, we are trying to cope with a corner weakness of scanf() and family. The best read input solution depends on additional factors, not mentioned by OP.

Yes, it possible because '\\0' is a non-white-space. scanf() will consider that is the end of the string. So %s can match a empty string.

You can use the m specifier to allocate a corresponding buffer to hold the input. Note this is POSIX 200112L standard.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void) {
    char *str;
    int n;
    if (scanf("%ms%n", &str, &n) == 1) {
      printf("I read %d character(s).\n", n);
      if (strlen(str) != 0) {
        printf("str = %s\n", str);
      }
      else {
        printf("str is empty");
      }
      free(str);
    }
    else {
      printf("The user enter nothing");
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM