我不明白此扫描集如何工作
scanf("%*[^:]%*2c%[^\n]", str1);// 1st scanf
完整的代码是
int main()
{
int ch;
char str1[100];
printf("Enter input\n");
scanf("%*[^:]%*2c%[^\n]", str1);
printf("input is: %s",str1);
return 0;
}
如果输入为
任意组合:您可以自由使用任何组合。
输出为
输入为:您可以自由使用任何组合。
当我%*[^:]
从scanf中删除
现在scanf是 scanf("%*2c%[^\n]", str1); //2nd scanf
使用相同的输入
任意组合:您可以自由使用任何组合。
输出为
输入是:y组合:您可以自由使用任何组合。
所以如果我%*2c
从第一个scanf中删除
现在scanf是 scanf("%*[^:]%[^\n]", str1); \\3rd scanf
输入为
任意组合:您可以自由使用任何组合。
输出为
输入为::您可以自由使用任何组合。
Agian,如果我%[^\n]
从第一个scanf中删除。
现在scanf是 scanf("%*[^:]%*2c", str1); \\4th scanf
输入为
任意组合:您可以自由使用任何组合。
输出为
垃圾值。
问题是每个scanf中的scanset如何工作?请逐步说明。
scanf
在https://en.cppreference.com/w/c/io/fscanf上查看文档:
转换规格。每个转换规范具有以下格式:
介绍性的%字符
(可选)禁止分配字符*。如果存在此选项,则该函数不会将转换结果分配给任何接收参数。
(可选)整数(大于零),它指定最大字段宽度,即在执行当前转换规范所指定的转换时允许该函数使用的最大字符数。
...
[组]
- 匹配字符集中的非空字符序列。如果集合中的第一个字符是^,则匹配集合中所有不在的字符...
因此,请分解您的格式字符串:
%*[^:]
-将所有内容匹配到:
,但不要分配给变量。本质上忽略冒号之前的所有内容。
%*2c
-匹配2个字符,但同样不要分配它们。因此,在此之后跳过冒号和字符。
%[^\n]
-匹配所有内容(最多\n
换行符),这将分配给str1
。因此,第一个冒号和后一个字符之后的所有内容都将在此处进行匹配和分配。
因此,使用input Any combination: You are free to use any combination.
,忽略的部分为Any combination:
,而结果str1
为You are free to use any combination.
scanf("%*[^:]%*2c", str1)
导致打印出垃圾的原因是,这两个格式说明符均未分配str1
,而未初始化。恰好在str1
数组的内存中的字节值是要打印的内容,因此是毫无意义的。这种情况下,大多数现代编译器都应警告scanf
(或printf
)样式函数未使用的参数。因此,请确保您已打开警告,并尝试解释和解决它们。
如果输入的全格式字符串不包含:
,可能会发生同样的情况,在这种情况下,输入scanf
将永远不会到达分配的部分,str1
并且结果将再次成为垃圾。为了解决这个问题,您需要查看的返回值scanf
:
返回值
成功分配的接收参数的数量(如果在分配第一个接收参数之前发生匹配失败,则为零);如果在分配第一个接收参数之前发生输入失败,则为EOF。
在这种情况下,您将得到,EOF
因为输入将在str1
分配之前结束。为确保str1
有效,您需要检查返回值是1
。
最后,如评论中所述,这里还有另一个问题,如果用户在大于str1
数组的可跳过部分后面输入内容,则输入内容。请注意,scanf
它将\0
在字符串的结尾自动添加一个终止符,因此输入的指定部分的最大长度为99个字符。如果输入较大,它将超出缓冲区的末端并覆盖原本不应该的内存。这很可能导致程序表现异常或崩溃。通过将最大字段宽度说明符添加到转换说明符中,可以使格式字符串安全。简而言之,更改%[^\n]
为%99[^\n]
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句