开发者

NULL arg allowed to sscanf?

Is a NULL pointer allowed as the string to store result in in a call to sscanf?

I don't find anything about it in any documentation but it seems to be working fine. Same thing with scanf.

Example:

int main(int arc, char* argv[])
{
  char* s = NULL;
  sscanf("Privjet mir!", "%s", s);
  printf("s: %s\n", s);
开发者_C百科  return 0;
}

Output: s: (null)


No:

Matches a sequence of non-white-space characters; the next pointer must be a pointer to character array that is long enough to hold the input sequence and the terminating null character ('\0'), which is added automatically. The input string stops at white space or at the maximum field width, whichever occurs first.

(http://linux.die.net/man/3/sscanf)


As is mentioned by the other answers NULL is not valid to pass to sscanf as an additional argument.

http://www.cplusplus.com/reference/cstdio/sscanf says of additional arguments:

Depending on the format string, the function may expect a sequence of additional arguments, each containing a pointer to allocated storage where the interpretation of the extracted characters is stored with the appropriate type.

For the %s specifier these extracted characters are:

Any number of non-whitespace characters, stopping at the first whitespace character found. A terminating null character is automatically added at the end of the stored sequence.

So when the "non-whitespace characters" and "terminating null character" is stored, there will be a segfault. Which is exactly what Visual Studio will yield (you can test that this fails at http://webcompiler.cloudapp.net/):

NULL arg allowed to sscanf?

Now as far as non-Visual Studio compilers, libc's extraction code for the %s specifier: https://github.com/ffainelli/uClibc/blob/master/libc/stdio/_scanf.c#L1376 has the leading comment: /* We might have to handle the allocation ourselves */ this is because:

The GNU C library supported the dynamic allocation conversion specifier (as a nonstandard extension) via the a character. This feature seems to be present at least as far back as glibc 2.0.
Since version 2.7, glibc also provides the m modifier for the same purpose as the a modifier.

[Source]

So because libc extracts to a buffer constructed internally to sscanf and subsequently checks that the buffer parameter has no flags set before assigning it, it will never write characters to a NULL buffer parameter.

I can't stress enough that this is non-standard, and is not guaranteed to be preserved even between minor library updates. A far better way to do this is to use the * sub-specifier which:

Indicates that the data is to be read from the stream but ignored (i.e. it is not stored in the location pointed by an argument).

[Source]

This could be accomplished like this for example:

s == NULL ? sscanf("Privjet mir!", "%*s") : sscanf("Privjet mir!", "%s", s);

Obviously the true-branch of the ternary is a no-op, but I've included it with the expectation that other data was expected to be read from the string.


The manpage says that, when using %s, the argument must be a pointer with enough space for the string and \0. So my guess would be that the behaviour in your case is undefined. It may work, it may also crash or corrupt memory and cause issues later.


No, this is not allowed. sscanf %s expects a char* pointing to a sufficient large buffer, printf %s wants a nul char* buffer. Anything else results in undefined behavior. (And that means some implementations might detect and handle a null pointer in a certain way, other implementations might not)


I didn't find anything in the standard explicitly concerning NULL and *printf/*scanf.

I suppose that this is undefined behavior1, since it counts as passing an argument that is not coherent with the format specifier (§7.19.6.1 ¶13, §7.19.6.2 ¶13): %s means that a you're going to pass a pointer to the first element of a character array (large enough for the acquired string for *scanf, containing a NUL-terminated string for *printf) - and passing NULL doesn't satisfy this requirement.


1. In this case UB shows as "just ignoring the acquisition" and "printing (null)", on other platforms it may result in planes falling down the sky or the usual nasal demons.


Allocate the memory to s . Assign s to character array. Then run the program. Following will work.

int main(int arc, char* argv[])
{
  char s[100];
  sscanf("Privjet mir!", "%[^\t]s", s);
  printf("s: %s\n", s);
  return 0;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜