在sscanf(s,“%d%n”,&i,&n)中,n代表什么?
手册页指出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
。 所以我假设n
代表索引,当函数结束时,sscanf将在字符串s
。
但是变量i
呢? 这是什么意思?
编辑:
更明确一点:我看到sscanf
的签名想要一个char *
类型的指针作为第一个参数。 格式说明符作为seconf参数,因此它知道如何解析字符序列以及与下一个参数一样多的转换说明符变量。 我现在明白i
是用于保存解析的整数。
由于只有一个格式说明符,我试图推导出n
的函数。
我的假设是否正确?
看起来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”给出了您所期望的“假”值。
来自sscanf()
的手册页:
转换
[…]
ñ
没有任何预期; 相反,从输入到目前为止消耗的字符数通过下一个指针存储,该指针必须是指向int的指针。 这不是转换,尽管可以使用*赋值抑制字符来抑制它。 C标准说:“执行%n指令不会增加执行完成时返回的赋值计数”,但勘误表似乎与此相矛盾。 可能明智的做法是不对%n转换对返回值的影响做出任何假设。
变量i
表示它已读取整数值。
你想问什么呢? 它不太清楚! 代码将(尝试)将字符串中的整数读入’i’
我想指出原始代码是错误的:
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将恰好为1。 如果s不是整数,则fld将为零或-1。 零,如果有其他东西,就像一个单词; 如果没有,只有空字符串-1。