c - scanf 函数、说明符 %s 和新行

标签 c

我读入了 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 to strtod, strtol, etc., are unacceptable to fscanf.

286) No special provisions are made for multibyte characters in the matching rules used by the c, 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/

相关文章:

c - 发送到特定远程 ip 的第一条 UDP 消息丢失

c - 尝试使用两个初始化列表初始化二维结构数组时发出警告

c - MPI_Send 或 MPI_Recv 给出段错误

C函数原型(prototype) : void f(). 是否推荐?

c++ - 通过双击 Windows 中的文件调用命令行程序

c - 在 make_request 中使用什么样的自旋锁?

Android NDK 在 JNI 中使用来自 c 代码的 .so 库

android - 如何将 signal() 移植到 sigaction()?

c - C 中 printf 的函数

C 编程语言 , 制作有用的程序