2016-07-27 126 views
3

考虑下面几行:C中的字符串格式%80 [^,]是什么意思?

char szInline[80]; 
char szDescription[80] = { NULL }; 
float fCost = 0; 
sscanf (szInline, "%80[^,], %f", szDescription, &fCost); 

什么是%80 [^,]吗?

+1

btw'{NULL}'应该是'{0}'或'{'\ 0'}'。 'NULL'是一个值为0的指针。将它分配给一个字符应该给你一个*“不兼容的整数转换指针”*警告。 – user3386109

+0

@ user3386109:不幸的是,它很可能不会产生警告。 NULL被扩展为一个实现定义的空指针常量,通常为'0'。(是的,事实上,一个* null指针常量*不一定是指针类型的表达式就像您认为的那样直截了当。) –

+1

@ user3386109:即使将'NULL'定义为'(void *)0'是C标准库实现中非常流行的一种实践,'NULL'不保证/不需要成为指针。它可能是一个整数'0',这将使这个代码有效。但是,你的观点依然存在。 'NULL'在那里没有生意。 NULL应该只保留给指针上下文。 – AnT

回答

4

阅读至多80个字符,直到下一个,逗号。

顺便说一句,该szDescription缓冲器是由1

+1

很好的捕获“太小1”的错误! – dasblinkenlight

+1

@dasblinkenlight:好的bug候选者,但在这种特殊情况下没有任何后果,因为输入字符串的最大长度为79. – chqrlie

+0

@AnT:定义:'char szInline [80];'如果'szInline'不是一个合适的字符串(不包含空字节),代码会调用未定义的行为。我们都假设这个片段省略了'sInline'的初始化,但省略号'...'会使它更加明显。 – chqrlie

1

这里太小是步骤sscanf(szInline, "%80[^,], %f", szDescription, &fCost)

  • sscanf将从,不同180字符之间解析成阵列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()是有用的选择。

+0

有没有办法让scanf匹配80个非逗号字符,以便1也会成功? –

+0

不是直接为'sscanf()':看到我更新的答案。 – chqrlie

相关问题