考虑下面几行:C中的字符串格式%80 [^,]是什么意思?
char szInline[80];
char szDescription[80] = { NULL };
float fCost = 0;
sscanf (szInline, "%80[^,], %f", szDescription, &fCost);
什么是%80 [^,]吗?
考虑下面几行:C中的字符串格式%80 [^,]是什么意思?
char szInline[80];
char szDescription[80] = { NULL };
float fCost = 0;
sscanf (szInline, "%80[^,], %f", szDescription, &fCost);
什么是%80 [^,]吗?
阅读至多80个字符,直到下一个,
逗号。
顺便说一句,该szDescription
缓冲器是由1
很好的捕获“太小1”的错误! – dasblinkenlight
@dasblinkenlight:好的bug候选者,但在这种特殊情况下没有任何后果,因为输入字符串的最大长度为79. – chqrlie
@AnT:定义:'char szInline [80];'如果'szInline'不是一个合适的字符串(不包含空字节),代码会调用未定义的行为。我们都假设这个片段省略了'sInline'的初始化,但省略号'...'会使它更加明显。 – chqrlie
这里太小是步骤sscanf(szInline, "%80[^,], %f", szDescription, &fCost)
:
sscanf
将从,
不同1
和80
字符之间解析成阵列szDescription
,,
字符;'\n'
);float
类型的变量fCost
。EOF
是早期失败的情况。有在那里潜在的问题:
szDescription
太短80个字符加上一个'\0'
终止子,但幸运的是,输入数组szInline
还具有80的长度。如果包含一个正确的字符串,最多79
字符将与sscanf
匹配,因此不会发生溢出。尺寸说明符在这种情况下实际上不需要。,
之后的空格是多余的。 %f
总是忽略主要的空白。谨防sscanf()
将在此输入返回EOF
:,1
因为有从,
不同没有字符从输入字符串的开头进行解析。即使是高级C程序员也常常忽略这种特殊情况。
如果你想接受,
之前可能为空字符串,则不能直接使用sscanf()
,但你可以使用这个:
/* compute the length of the initial sequence upto `,` if any */
size_t len = strcspn(szInline, ",");
/* len < 80 because sizeof(szInline) == 80 */
/* copying the initial string */
memcpy(szDescription, szInline, len);
szDescription[len] = '\0';
if (sscanf(szInline + len, ",%f", &fCost) != 1) {
/* conversion error: no `,` or no number past it */
...
}
sscanf()
有很多怪癖,它是极难的事情正确使用但最重要的解析任务。很少使用的标准功能strspn()
和strcspn()
是有用的选择。
有没有办法让scanf匹配80个非逗号字符,以便1也会成功? –
不是直接为'sscanf()':看到我更新的答案。 – chqrlie
btw'{NULL}'应该是'{0}'或'{'\ 0'}'。 'NULL'是一个值为0的指针。将它分配给一个字符应该给你一个*“不兼容的整数转换指针”*警告。 – user3386109
@ user3386109:不幸的是,它很可能不会产生警告。 NULL被扩展为一个实现定义的空指针常量,通常为'0'。(是的,事实上,一个* null指针常量*不一定是指针类型的表达式就像您认为的那样直截了当。) –
@ user3386109:即使将'NULL'定义为'(void *)0'是C标准库实现中非常流行的一种实践,'NULL'不保证/不需要成为指针。它可能是一个整数'0',这将使这个代码有效。但是,你的观点依然存在。 'NULL'在那里没有生意。 NULL应该只保留给指针上下文。 – AnT