sscanf_s不返回字符串的第一个字符 [英] sscanf_s doesn't return first character of string
问题描述
我正在尝试在C字符数组内以逗号分隔的字符串列表中找到第一个字符串(最多4个字符).
I'm trying to find the first string (max 4 characters) in a comma-separated list of strings inside a C char-array.
我正在尝试使用 sscanf_s
(在Windows下)和格式控制字符串%[^,]
:
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; }
}
在调用 sscanf_s
后,temp的内容不是 STR1
,而是 \ 0TR1
( \ 0
是ASCII- 0
的解释).并返回值 -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.
为什么会出现这种行为,以及如何修复代码以获得正确的结果(返回 0
)?
Why do I get that behavior and how do I fix my code to get the right result (return of 0
)?
将char mystring
更改为 mystring []
(我应该确保我在此处正确键入了内容)
changed char mystring
to mystring[]
(I should have made sure I typed it correcly here)
推荐答案
您的代码中存在多个问题:
There are multiple problems in your code:
-
mystring
被定义为char
,而不是字符串指针. - 在
sscanf_s()
中的temp
之后的参数5
应该具有rsize_t
类型,该类型与size_t
.您应将其指定为sizeof(temp)
. - 您应该在格式字符串中指定要存储到目标数组中的最大字符数,以避免在溢出的情况下
sscanf_s
违反直觉的行为. -
sscanf_s
如果可以转换和存储字符串,则返回1
.测试!= 0
还将接受EOF
,这是输入失败,因此temp
的内容不确定.
mystring
is defined as achar
, not a string pointer.- the argument
5
followingtemp
insscanf_s()
should have typersize_t
, which is the same assize_t
. You should specify it assizeof(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
returns1
if it can convert and store the string. Testing!= 0
will also acceptEOF
which is an input failure, for which the contents oftemp
is indeterminate.
这是修改后的版本:
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;
}
}
更新:OP使用Microsoft Visual Studio,它似乎对所谓的 secure 流函数具有不一致的实现.这是他们的
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:
sscanf_s
函数将数据从缓冲区读入每个参数指定的位置.格式字符串后面的参数指定指向类型与格式中的类型说明符相对应的变量的指针.与不太安全的版本sscanf
不同,当您使用类型字段字符c
,C
,s
,S
或包含在[]
中的字符串控件集.缓冲区大小(以字符为单位)必须在每个需要它的缓冲区参数之后立即作为附加参数提供.例如,如果您正在读取一个字符串,则该字符串的缓冲区大小将按以下方式传递:
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 versionsscanf
, a buffer size parameter is required when you use the type field charactersc
,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
缓冲区大小包括终止null.宽度规范字段可用于确保读入的令牌将适合缓冲区.如果未使用宽度指定字段,并且读入的令牌太大而无法容纳在缓冲区中,则不会向该缓冲区写入任何内容.
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
此规范与C标准不兼容,该标准将width参数的类型指定为 rsize_t
,并将类型 rsize_t
设置为与 size_t相同的类型.
.
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
.
结论是,为了提高可移植性,应该避免使用这些 secure 函数并正确使用标准函数,并使用长度前缀来防止缓冲区溢出.
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.
这篇关于sscanf_s不返回字符串的第一个字符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!