请看一下这段代码:
char line1[10], line2[10];
int rtn;
rtn = scanf("%9[a]%9[^\n]", line1, line2);
printf("line1 = %s|\nline2 = %s|\n", line1, line2);
printf("rtn = %d\n", rtn);
输出:
$ gcc line.c -o line
$ ./line
abook
line1 = a|
line2 = book|
rtn = 2
$./line
book
line1 = |
line2 = �Js�|
rtn = 0
$
对于输入 abook
,%9[a]
在 b
来自 book
并存储之前解析的a
+\0
在 line1
。
然后 %9[^\n]
解析剩下的行,并将刚刚解析的 book
+\0
存储在 line2
.
这里请注意两点:
- 在存储解析的输入时,
\0
附加在它的末尾,因为%[]
是字符串的转换说明符。 - 当
%9[a]
在b
失败时,scanf
没有退出。它只是继续扫描进一步的输入。
现在对于输入 book
,%9[a]
应该在 book
的 b
处失败并且应该仅将 \0
存储在 line1
中,因为此处未解析任何内容。
然后 %9[^\n]
应该解析剩余的行,并且应该将刚刚解析的 book
+\0
存储在 line2
。
现在,让我们看看到底发生了什么:
这里的返回值为 0,表示 scanf
没有给任何变量赋值。 scanf
没有分配任何值就直接退出了。所以 line2
处的垃圾数据。在 line1
的情况下,垃圾数据恰好是一个 NULL
字符。
但这很奇怪!不是吗?
我的意思是,如果 %[...]
在输入的第一个字符处失败,则 scanf
退出。 (即使在 scanf
语句中有额外的转换说明符。)
但是,如果相同的 %[...]
在第一个字符以外的任何其他字符处失败,则 scanf
只是继续扫描进一步的输入。 (当然,如果有额外的转换说明符。)它不会退出。
那么为什么会出现这种不一致呢?
为什么不让 scanf
语句继续扫描输入(当然如果有额外的转换说明符)即使 %[...]
在输入的第一个字符处失败?与其他情况完全一样。
这种不一致背后有什么特殊原因吗?
$ gcc --version
gcc (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3
最佳答案
2) When
%9[a]
failed at b,scanf
didn't exit. It simply went on scanning further input.
是的,%9[a]
指令意味着“存储最多 9 个'a'
,但至少one"(1),所以转换 %9[a]
没有失败,它成功了。它发现的 'a'
少于它可以消耗的数量,但这并不是失败。输入匹配在'b'
处失败,但转换成功。
(1) 在描述转换的 7.21.6.2 (12) 中指定:
[
Matches a nonempty sequence of characters from a set of expected characters (the scanset).
Now for input book,
%9[a]
should fail at b from the book and should store just'\0'
at line1 since here nothing was parsed. Then%9[^\n]
should parse the remaining line and should store just now parsedbook+\0
at line2.
没有。它应该在转换失败时退出。第一次转换 %9[a]
失败,因此 scanf
应该停止并返回 0,因为没有转换成功。
始终检查scanf
的返回值。
这是指定的(对于fscanf
,但是scanf
等同于fscanf
with stdin
作为输入流)在 7.21.6.2 (16) 中:
The
fscanf
function returns the value of the macroEOF
if an input failure occurs before the first conversion (if any) has completed. Otherwise, the function returns the number of input items assigned, which can be fewer than provided for, or even zero, in the event of an early matching failure.Here output for
line1
is nothing which is exactly what we expected. An empty string!
你不能期待任何事情。数组 line1
和 line2
没有初始化,所以当转换失败时,它们的内容仍然是不确定的。在这种情况下,line1
在第一个 0 字节之前不包含任何可打印字符。
But for
line2
it's garbage chars! We didn't expect this. So how did this happen ?
这就是 line2
的内容。从来没有为元素分配任何值,因此它们是调用 scanf
之前的任何值。
关于c - 与 C 中 scanf() 中的 [ ] 转换说明符的逻辑不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16778044/