【问题标题】:The function sscanf_s fail when I use several strings当我使用多个字符串时,函数 sscanf_s 失败
【发布时间】:2012-11-07 22:16:22
【问题描述】:

我不明白为什么下面的代码会失败:

char    toto[54], titi[54]; //I already tried with allocations

sscanf_s(line, "%s-%s", &toto, &titi, sizeof(toto) + sizeof(titi));

sscanf_s(line, "%s-%s", &toto, &titi, sizeof(toto) + sizeof(titi));

我的问题只是字符串(浮点数、整数、双精度等),我使用 Visual 2010。

有人有想法吗? 非常感谢您的回答。

【问题讨论】:

标签: c visual-studio-2010 parsing scanf


【解决方案1】:

来自sscanf_s() 参考页面:

sscanf_s 函数将数据从缓冲区读取到每个参数给定的位置。格式字符串后面的参数指定指向变量的指针,该变量的类型对应于格式中的类型说明符。 与不太安全的版本 sscanf 不同,在使用类型字段字符 c、C、s、S 和 [ 时需要缓冲区大小参数。必须在每个需要它的缓冲区之后作为附加参数提供以字符为单位的缓冲区大小。有关详细信息,请参阅 scanf_s、_scanf_s_l、wscanf_s、_wscanf_s_l 和 scanf 类型字段字符。

意思是每个缓冲区后面必须跟它的大小:

sscanf_s(line, "%s-%s", toto, sizeof(toto), titi, sizeof(titi));

此外,- 不是空白字符,不会充当"%s" 格式说明符的终止符,因此如果line 包含hello-world,那么它将被读入tototiti 不会分配的。要将- 用作终止符,请使用扫描集:

if (2 == sscanf_s(line, "%[^-]-%s", toto, sizeof(toto), titi, sizeof(titi)))
{
    /* Both 'toto' and 'titi' where assigned. */
}

【讨论】:

  • 非常感谢这个完美的答案。再见。
【解决方案2】:

除非sscanf_s() 非常奇怪,否则您不想传递指向数组的指针 (&toto),而是传递指向数组第一个元素的指针 (toto)。此外,安全函数的目标是避免缓冲区溢出,即您需要为每个单独的缓冲区指定它包含多少个字符:

if (sscanf_s(line, "%s-%s", toto, sizeof(toto), titi, sizeof(titi)) == 2) {
    ...
}

(错误处理,因为尝试读取应始终在处理数据之前检查是否发生错误)

就个人而言,我会使用 std::istringstream 连同字符串和合适的自定义操纵器并完全避免该问题:

std::istream& minus(std::istream& in) {
    if ((in >> std::ws).peek() != std::char_traits<char>::to_int_type('-')) {
        in.setstate(std::ios_base::failbit);
    }
    else {
        in.ignore();
    }
    return in;
}

std::string toto, titi;
if (std::istringstream(line) >> std::skipws >> toto >> minus >> titi)) {
    ...
}

【讨论】:

    猜你喜欢
    • 2020-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多