[英]Different behaviour of scanset in following C code
对于scanset中的0-9范围,如果输入字符串12345thisisnice输出是12345,这是正确的,但是对于输入thisisnice12345输出是a @,这是错误的,我认为,为什么这是错误的?
/* A simple scanset example */
#include <stdio.h>
int main(void)
{
char str[128];
printf("Enter a string: ");
scanf("%[9-0]s", str);
printf("You entered: %s\n", str);
return 0;
}
我希望thisisnice12345的o / p为12345,但实际的o / p是a @
这是您程序的改进版本:
#include <stdio.h>
int main(void)
{
char str[128];
printf("Enter a string: ");
if(scanf("%[0-9]", str) == 1)
printf("You entered: \"%s\"\n", str);
else printf("You entered nothing.\n");
return 0;
}
正确的scanset是%[0-9]
,顺序为数字,后跟s
。 (在这种情况下,尾随s
是无害的,但是在其他情况下会引起问题。)更重要的是,如果scanf
返回0,则表明它不匹配,因此在str
没有存储任何内容。
您的代码具有未定义的行为。 您没有初始化str
,并且第二个输入scanf
没有读取任何字段(“ thisisnice12345”不是以数字开头 ),因此不写入str
。 如果随后是printf
-ing str
,则您正在读取未初始化的变量,该变量是未定义的行为。
您需要检查scanf
的返回值。 仅在scanf
返回1时才写入str
。
scanf
函数系列无法执行复杂的正则表达式 。 但是它有一些功能。 如果要阅读用户输入的第一个数字,可以使用:
%[0-9]
仅读取一个数字(警告其0-9
而不是9-0
) %[^0-9]
读取除数字以外的所有数字 %*[^0-9]
读取除数字以外的所有内容,并忽略它。 所以你可以这样写:
/* A simple scanset example */
#include <stdio.h>
int main(void)
{
char str[128];
int ret;
printf("Enter a string: ");
/* Try to read a number at input start */
ret = scanf("%[0-9]", str);
if (1 != ret){
/* if reading failed, try to re-read the input,
ignoring all that is before the number */
ret = scanf("%*[^0-9]%[0-9]", str);
}
if (1 != ret)
printf("no match");
else
printf("You entered: %s\n", str);
return 0;
}
如注释中所指出的,如果读取大小受到限制,则此代码会更好:
%8[0-9]
将scanf
限制为只能读取8个数字字符。 #include <stdio.h>
int main(void)
{
char str[8+1];
int ret;
printf("Enter a string: ");
/* Try to read a number at input start */
ret = scanf("%8[0-9]", str);
if (1 != ret){
/* if reading failed, try to re-read the input,
ignoring all that is before the number */
ret = scanf("%*[^0-9]%8[0-9]", str);
}
if (1 != ret)
printf("no match");
else
printf("You entered: %s\n", str);
return 0;
}
但是在这段代码中,您将不得不处理一个新的事实:如果用户输入的数字太大,该如何处理? ( strlen
可以提供帮助,或strto[u]l
...)
Enter a string: 1234567891011
You entered: 12345678
s
不属于scanset指定符。 是%[...]
,不是%[...]s
! 现在C标准说
- 如果
-
字符位于扫描列表中,并且不是第一个字符,也不是第二个字符(第一个字符是^
,也不是最后一个字符,则该行为是实现定义的。
所以行为
scanf("%[9-0]", str);
是实现定义的。 允许实现的行为类似于%[-09]
或以任何其他实现定义的方式运行。
现在,例如, Glibc记录了连字符表示字符范围,但是POSIX将其留给实现。 即使这样, %[9-0]
是否具有该范围内的所有字符的问题还是值得怀疑的。 总而言之,最好不要编写任何这样的代码。 如果不指定缓冲区长度, scanf
很危险。 由于您被一个兼容性错误所困扰,因此最好不要再猜测其他平台上的行为,而只需编写
int rv = scanf("%127[0123456789]", str);
if (rv == 1) {
...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.