了解Scanf - 处理格式化输入

时间:2013-03-11 01:52:58

标签: c

我正在试图找出scanf的确切工作原理。如果我编写这样的代码:

scanf("%s %d %f", name, &age, &wage);

输入此作为标准输入:

james 20 34000.25

然后分别打印出姓名,年龄和工资,我得到了人们所期望的,就像我投入标准输入一样。但是,如果我输入这样的内容:

scanf("%s/%d/%f", name, &age, &wage);

我将其作为标准输入输入:

james/20/34000.25

我得到字符串james/20/34000.25作为字符串值,0和0.00000分别表示整数和浮点值。我认为scanf会像处理第一个版本中的空格一样处理斜杠。如果用户输入斜杠分隔值,我怎么能得到它,我可以适当地将值分配给变量?

2 个答案:

答案 0 :(得分:4)

%s匹配非空格字符(并且它是一个贪婪的匹配:它不会回溯以查看是否可以进行其他匹配)要匹配非正斜杠字符,请使用%[^/]

(另请注意,scanf字符串中的空格字符(匹配零个或多个空格字符)与非空格非百分号字符的行为非常不同,例如'/'(完全匹配{{ 1}})

答案 1 :(得分:2)

要匹配以空格分隔的输入和斜杠分隔的输入,您需要一个适度复杂的格式字符串:

if (scanf("%[^ /]%*1[ /]%d%*1[ /]%f", name, &age, &wage) == 3)
    ...data was read properly...
else
    ...something went wrong...

第一个转换规范是一个扫描集,它接受一系列非空白,非斜杠(因此它将停在第一个空白处或斜杠处)。最好指定接受多少个字符的上限,以避免stack overflow;例如,如果是char name[32];,那么%31[^ /](注意一个一个)。第二个转换规范%*1[ /]接受一个空格或斜杠1的单个字符([ /]),并且不会将其分配给任何变量(*)。第三个转换规范是标准数字输入,跳过前导空格,允许输入负数等。第四个转换规范与第二个相同,第五个是float的标准格式(这意味着具有7位有效数字的34000.25位于可表示值范围的外端。)

请注意,“出错了”部分很难将错误报告给用户。这就是为什么许多人(包括我自己)建议不要使用scanf()fscanf(),而是更喜欢使用fgets()或者POSIX getline来读取用户的一行,然后使用sscanf()进行分析。您可以更轻松地报告问题。另请注意,scanf()的返回值是成功分配的数量;它不计算包含*的转换规范。