手册页指出sscanf
的签名是
sscanf(const char *restrict s, const char *restrict format, ...);
我见过一个answer on 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
。所以我假设n
代表函数结束时sscanf将在字符串s
中的索引。
但变量i
怎么样?这是什么意思?
修改
更明确:我看到sscanf
的签名想要一个类型为char *
的指针作为第一个参数。格式说明符作为seconf参数,因此它知道如何解析字符序列以及与下一个参数一样多的转换说明符变量。我现在明白i
用于保存已解析的整数。
由于只有一个格式说明符,我试图推导出n
的功能。
我对n
的假设是否正确?
答案 0 :(得分:9)
看起来op已经有了他的答案,但是因为我不好意思为自己查看并运行代码......
来自“C The Pocket Reference”(Herbert Shildt的第二版)scanf()部分:
%n接收的整数值等于到目前为止读取的字符数
并返回值:
scanf()函数返回一个等于字段数的数字 已成功分配值
sscanf()函数的工作方式相同,它只是从提供的缓冲区参数(在本例中为s)中输入。 “== 1”测试确保只解析了一个整数,并且!s [n]确保输入缓冲区在解析的整数之后完全终止和/或字符串中只有一个整数。
运行此代码,像“32”这样的s值给出一个“true”值(我们没有将bool定义为我们系统上的类型)但s为“3 2”会给出一个“false”值,因为s [n]在这种情况下为“2”,n的值为2(在这种情况下,解析“3”以创建int)。如果s为“3”,则该函数仍将返回true,因为所有空格都被插入且n的值为3.
另一个示例输入“3m”给出了您所期望的“假”值。
答案 1 :(得分:3)
从sscanf()
的手册页中逐字逐句:
转化
[...]
n
没有预料到的;相反,字符数 从输入到目前为止消耗的是通过下一个指针存储的, 它必须是指向int的指针。这不是一个 转换,虽然可以使用*赋值抑制字符进行抑制。 C 标准说:“执行 %n指令不会增加完成时返回的赋值计数 执行“但是勘误似乎与此相矛盾。可能不是明智的 对%n转换对返回值的影响做出任何假设。
答案 2 :(得分:0)
变量i
表示它已读取整数值。
你想问什么?它不太清楚!代码将(尝试)将字符串中的整数读入'i'
答案 3 :(得分:0)
我想指出原始代码是错误的:
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
将是真的。因此&& amp;的另一部分表达式将执行。并且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将恰好为1。如果s不是整数,则fld将为零或-1。零,如果有其他东西,就像一个单词;如果没有,则为-1,但为空字符串。