NULL arg allowed by sscanf?

Is a NULL pointer allowed as a string to save the result when calling sscanf ? I don't know anything about this in any documentation, but it seems to work 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); return 0; } 

Output: s: (null)

+6
c scanf
source share
6 answers
<Not p> No:

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

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

+6
source share

As pointed out in other answers, NULL not valid for going to sscanf as an extra argument.

http://www.cplusplus.com/reference/cstdio/sscanf talks about additional arguments:

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

For the %s qualifier, these extracted characters are ::

Any number of characters without spaces, stopping when the first character is found. A trailing null character is automatically added at the end of a stored sequence.

So, when “characters with no spaces” and “null termination” are stored, segfault will exist. This is exactly what Visual Studio will give (you can verify that this fails http://webcompiler.cloudapp.net/ ):

enter image description here

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

The GNU C library supports the dynamic allocation conversion specifier (as a non-standard extension) using the a symbol. This feature, apparently, is present, at least, as glibc 2.0.
Starting with version 2.7, glibc also provides the m modifier for the same purpose as the a modifier.

[ Source ]

So, since libc extracts into the buffer built internally before sscanf and then checks that the buffer parameter has no flags set before it is assigned, it will never write characters to the NULL buffer parameter.

I can’t stress that this is non-standard and cannot be guaranteed even between minor library updates. A much better way to do this is to use a sub-qualifier * , which:

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

[ Source ]

This can be done, for example, as follows:

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

Obviously, the true branch of the triple is non-op, but I included it with the expectation that other data should be read from the string.

+4
source share

The manpage says that when using %s argument must be a pointer with enough space for the string and \0 . Therefore, I assume that the behavior in your case is undefined. It can work, it can also lead to a memory failure or corruption and cause problems later.

+1
source share

No, it is forbidden. sscanf% s expects char * to point to a large enough buffer, printf% s wants a buffer nul char *. Everything else leads to undefined behavior. (And this means that some implementations may define and process the null pointer in a certain way; other implementations may not be).

+1
source share

I did not find anything in the standard explicit form regarding NULL and *printf / *scanf .

I believe this is undefined behavior 1 since it is considered passing an argument that is not related to the format specifier (§7.19.6.1 ¶13, §7.19.6.2 ¶13): %s means that you are going to pass a pointer to the first element of the character array (large enough for the received string for *scanf containing the NUL -termined string for *printf ) - and passing NULL does not satisfy this requirement.


1. In this case, UB shows how “just ignoring the acquisition” and “printing (null)”, on other platforms this can lead to the crash of airplanes across the sky or the usual nasal demons .
+1
source share

Allocate memory to s. Assign s to an array of characters. Then run the program. The 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; } 
-2
source share

All Articles