sscanf_s doesn't return first character of string

无人久伴 提交于 2021-01-28 18:38:42

问题


I'm trying to find the first string (max 4 characters) in a comma-separated list of strings inside a C char-array.

I'm trying to achieve this by using sscanf_s (under Windows) and the format-control string %[^,]:

char mystring[] = "STR1,STR2";
char temp[5];

if (sscanf_s(mystring, "%[^,]", temp, 5) != 0) {
    if (strcmp(temp, "STR1") == 0) { return 0; }
    else if (strcmp(temp, "STR2") == 0) { return 1; }
    else { return -1; }
}

After calling sscanf_s the content of temp is not STR1 but \0TR1 (\0 being the ASCII-interpretation of 0). And the value -1 is returned.

Why do I get that behavior and how do I fix my code to get the right result (return of 0)?

EDIT: changed char mystring to mystring[] (I should have made sure I typed it correcly here)


回答1:


There are multiple problems in your code:

  • mystring is defined as a char, not a string pointer.
  • the argument 5 following temp in sscanf_s() should have type rsize_t, which is the same as size_t. You should specify it as sizeof(temp).
  • you should specify the maximum number of characters to store into the destination array in the format string, to avoid the counter-intuitive behavior of sscanf_s in case of overflow.
  • sscanf_s returns 1 if it can convert and store the string. Testing != 0 will also accept EOF which is an input failure, for which the contents of temp is indeterminate.

Here is a modified version:

const char *mystring = "STR1,STR2";
char temp[5];

if (sscanf_s(mystring, "%4[^,]", temp, sizeof temp) == 1) {
    if (strcmp(temp, "STR1") == 0) {
        return 0;
    } else
    if (strcmp(temp, "STR2") == 0) {
        return 1; 
    } else {
        return -1;
    }
}

UPDATE: The OP uses Microsoft Visual Studio, which seems to have a non-conforming implemtation of the so-called secure stream functions. Here is an citation from their documentation page:

The sscanf_s function reads data from buffer into the location that's given by each argument. The arguments after the format string specify pointers to variables that have a type that corresponds to a type specifier in format. Unlike the less secure version sscanf, a buffer size parameter is required when you use the type field characters c, C, s, S, or string control sets that are enclosed in []. The buffer size in characters must be supplied as an additional parameter immediately after each buffer parameter that requires it. For example, if you are reading into a string, the buffer size for that string is passed as follows:

wchar_t ws[10];
swscanf_s(in_str, L"%9s", ws, (unsigned)_countof(ws)); // buffer size is 10, width specification is 9

The buffer size includes the terminating null. A width specification field may be used to ensure that the token that's read in will fit into the buffer. If no width specification field is used, and the token read in is too big to fit in the buffer, nothing is written to that buffer.

In the case of characters, a single character may be read as follows:

wchar_t wc;
swscanf_s(in_str, L"%c", &wc, 1);

This example reads a single character from the input string and then stores it in a wide-character buffer. When you read multiple characters for non-null terminated strings, unsigned integers are used as the width specification and the buffer size.

char c[4];
sscanf_s(input, "%4c", &c, (unsigned)_countof(c)); // not null terminated

This example reads a single character from the input string and then stores it in a wide-character buffer. When you read multiple characters for non-null terminated strings, unsigned integers are used as the width specification and the buffer size.

char c[4];
sscanf_s(input, "%4c", &c, (unsigned)_countof(c)); // not null terminated

This specification is incompatible with the C Standard, that specifies the type of the width arguments to be rsize_t and type rsize_t to be the same type as size_t.

As a conclusion, for improved portability, one should avoid using these secure functions and use the standard functions correctly, with the length prefix to prevent buffer overruns.




回答2:


edited per the comment from chqrlie

regarding:

if(sscanf_s(mystring, "%[^,]",temp, 5) != 0){

The input format conversion specifier: %[..] always appends a NUL byte to the end of the input. So the input format conversion specifier should be: "%4[^,]" The result after the correction is:

if(sscanf_s(mystring, "%4[^,]",temp, 5) != 0){

also, no matter how many times this code snippet is executed, the returned value wnce the other problems are corrected will ALWAYS be STR1

regarding the statement;

char mystring = "STR1,STR2";

This is not a valid statement. Suggest:

char *mystring = "STR1,STR2";  // notice the '*'

--or--

char mystring[] = "STR1,STR2";  // notice the '[]'


来源:https://stackoverflow.com/questions/60286028/sscanf-s-doesnt-return-first-character-of-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!