7

手册页指出的签名sscanf

sscanf(const char *restrict s, const char *restrict format, ...);

在 SO 上看到了一个答案,其中一个函数sscanf用于检查输入是否为整数。

bool is_int(char const* s) {
    int n;
    int i;
    return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
}

!s[n]它似乎建议我们检查是否sscanf扫描字符序列直到终止字符\0。所以我假设代表函数结束时nsscanf 将在字符串中的索引。s

但是变量i呢?这是什么意思?

编辑:

更明确地说:我看到sscanf想要一个类型的指针char *作为第一个参数的签名。格式说明符作为 seconf 参数,因此它知道如何解析字符序列以及与转换说明符一样多的变量作为下一个参数。我现在明白这i是为了保存解析的整数。

由于格式说明符只有一个,我尝试推导出n.

我上面的假设是否n正确?

4

4 回答 4

10

看起来操作员已经有了答案,但是由于我费心自己查找并运行代码...

来自“C The Pocket Reference”(Herbert Shildt 的第二版)scanf() 部分:

%n 接收一个整数值,等于到目前为止读取的字符数

对于返回值:

scanf() 函数返回的数字等于成功赋值的字段数

sscanf() 函数的工作原理相同,它只是从提供的缓冲区参数(在本例中为 s )获取输入。"== 1" 测试确保只解析了一个整数,!s[n] 确保输入缓冲区在解析完整数后很好地终止和/或字符串中实际上只有一个整数。

运行这段代码,像 "32" 这样的 s 值给出了一个 "true" 值(我们没有将 bool 定义为我们系统上的类型)但是 s as "3 2" 给出一个 "false" 值,因为 s[n]在这种情况下是“2”,n 的值为 2(在这种情况下,“3”被解析以创建 int)。如果 s 为“3”,则此函数仍将返回 true,因为所有空格都已输入,并且 n 的值为 3。

另一个示例输入“3m”给出了您所期望的“假”值。

于 2012-11-02T17:57:41.813 回答
4

sscanf()来自的手册页的逐字记录:

转换

[...]

n

没有任何期望;相反,到目前为止从输入消耗的字符数通过 next 指针存储,该指针必须是指向 int 的指针。这不是转换,尽管可以使用 * 赋值抑制字符来抑制它。C 标准说:“执行 %n 指令不会增加执行完成时返回的赋值计数”,但勘误表似乎与此相矛盾。可能最好不要对 %n 转换对返回值的影响做出任何假设。

于 2012-11-02T17:13:54.277 回答
1

我想指出原始代码有问题:

bool is_int(char const* s) {
    int n;
    int i;
    return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
} 

我会解释为什么。我将解释 sscanf 格式字符串。

首先,越野车:

给定输入“1”,即整数 1,sscanf 会将 1 存储到 i 中。那么,由于后面没有空格,sscanf就不会碰n了。并且 n 未初始化。因为 sscanf 将 i 设置为 1,所以 sscanf 返回的值将是 1,表示扫描了 1 个字段。由于 sscanf 返回 1,因此表达式的部分

sscanf(s, "%d %n", &i, &n) == 1

将是真的。因此 && 表达式的另一部分将执行。并且 s[n] 将访问内存中的某个随机位置,因为 n 未初始化。

解释格式:

"%d %n"

尝试扫描可能是十进制数或整数或科学计数法数字的数字。该数字是一个整数,它后面必须至少有一个空格。空白可以是空格、\n、\t 和某些其他不可打印的字符。只有当它后面跟着空格时,它才会将 n 设置为扫描到该点的字符数,包括空格。

此代码可能是预期的:

    static bool is_int(char const* s) 
    {
        int i;
        int fld;
        return (fld = sscanf(s, "%i", &i)) == 1;
    }

    int main(int argc, char * argv[])
    {
        bool ans = false;

        ans = is_int("1");
        ans = is_int("m");

        return 0;
    }

此代码基于,如果 s 是整数,则 sscanf 将扫描它,而 fld 将恰好是一个。如果 s 不是整数,则 fld 将为零或 -1。如果有其他东西,比如一个词,则为零;如果只有一个空字符串,则为 -1。

于 2015-02-12T03:54:10.150 回答
0

那里的变量i意味着直到它读取一个整数值。

你想问什么?不是太清楚!代码将(尝试)将字符串中的整数读入“i”

于 2012-11-02T16:53:37.063 回答