我读入了 C11 标准:
Input white-space characters (as specified by the isspace function) are skipped, unless the specification includes a [, c, or n specifier.
所以我明白,如果我使用那个说明符,下一个 scanf
可以包含例如一个新行。
但是如果我这样写:
char buff[5 + 1];
printf("Input: ");
scanf("%10s", buff);
printf("Input: ");
char buff_2[5 + 1];
scanf("%[abcde]", buff_2);
然后我输入,即 RR
然后 Return,
由于 \n
,下一个 scanf
失败。
那么 %s
也不会丢弃新行吗?
最佳答案
So also %s doesn't discard a new line?
%s
告诉 scanf
丢弃任何前导 空格,包括换行符。然后它将读取任何非空白字符,在输入缓冲区中留下任何尾随空白。
因此假设您的输入流看起来像 "\n\ntest\n"
,scanf("%s", buf)
将丢弃两个前导换行符,消耗字符串 "test"
,并在输入流中保留尾随换行符,因此在调用之后输入流看起来像 "\n"
。
编辑
在这里回应 xdevel2000 的评论。
让我们谈谈转换说明符的工作原理。以下是 online C 2011 standard 中的一些相关段落:
7.21.6.2 The fscanf function
...
9 An input item is read from the stream, unless the specification includes an n specifier. An input item is defined as the longest sequence of input characters which does not exceed any specified field width and which is, or is a prefix of, a matching input sequence.285) The first character, if any, after the input item remains unread. If the length of the input item is zero, the execution of the directive fails; this condition is a matching failure unless end-of-file, an encoding error, or a read error prevented input from the stream, in which case it is an input failure.
10 Except in the case of a%
specifier, the input item (or, in the case of a%n
directive, the count of input characters) is converted to a type appropriate to the conversion specifier. If the input item is not a matching sequence, the execution of the directive fails: this condition is a matching failure. Unless assignment suppression was indicated by a*
, the result of the conversion is placed in the object pointed to by the first argument following the format argument that has not already received a conversion result. If this object does not have an appropriate type, or if the result of the conversion cannot be represented in the object, the behavior is undefined.
12 The conversion specifiers and their meanings are:
...
c
Matches a sequence of characters of exactly the number specified by the field width (1 if no field width is present in the directive).286)
...
s
Matches a sequence of non-white-space characters.286)
...
[
Matches a nonempty sequence of characters from a set of expected characters (the scanset).286)
...
285)fscanf
pushes back at most one input character onto the input stream. Therefore, some sequences that are acceptable tostrtod
,strtol
, etc., are unacceptable tofscanf
.
286) No special provisions are made for multibyte characters in the matching rules used by thec
,s
, and[
conversion specifiers — the extent of the input field is determined on a byte-by-byte basis. The resulting field is nevertheless a sequence of multibyte characters that begins in the initial shift state.
%s
匹配一系列非空白字符。这是描述其工作原理的基本算法(不考虑文件末尾或其他异常情况):
c <- next character from input stream
while c is whitespace
c <- next character from input stream
while c is not whitespace
append c to target buffer
c <- next character from input stream
push c back onto input stream
append 0 terminator to target buffer
非空白字符(如果有的话)之后的第一个空白字符被推回输入流以供下一个输入操作读取。
相比之下,%c
说明符的算法非常简单(除非您使用大于 1 的字段宽度,我从未做过,也不会在此处介绍) :
c <- next character from input stream
write c to target
%[
转换说明符的算法有点不同:
c <- next character from input stream
while c is in the list of characters in the scan set
append c to target buffer
c <- next character from input stream
append 0 to target buffer
push c back onto input stream
因此,将任何转换说明符描述为“保留”尾随空格(这意味着尾随空格被保存到目标缓冲区)是错误的;事实并非如此。尾随空格留在输入流中以供下一个输入操作读取。
关于c - scanf 函数、说明符 %s 和新行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28197006/