scanf() 语句中"%*[^n]"的格式字符串指示什么?分配抑制器 (*) 和否定扫描集 ([^) 如何协同工作?



我知道引入了带有[转换说明符的扫描集,该转换说明符随后通过^符号的附加插入来指示要匹配或不匹配的字符。

为此,ISO/IEC 9899/1999(C99)中规定:

括号(扫描列表)之间的字符组成扫描集,除非左括号后的字符是扬抑符(^),在这种情况下,扫描集包含所有未出现在扫描列表中扬抑符和右括号之间的字符。

因此,表达式[^n]的意思是,它正在扫描字符,直到在相应流中找到n字符,此处为scanf()stdinn不取自stdinscanf()继续使用下一个格式字符串(如果还有),否则跳到下一个C语句。

接下来是分配抑制算子*:

为此,ISO/IEC 9899/1999(C99)中规定:

除非用*表示禁止赋值,否则转换结果将放在尚未收到转换结果的格式参数后面的第一个参数所指向的对象中。

在f.e.scanf("%*100s",a);的情况下,意味着除非找到尾部空白字符,否则从stdin获取100个字符的序列,但如果a是由101个元素组成的正确定义的char阵列(char a[101];),则不将其分配给a


但是scanf()-语句中的格式字符串"%*[^n]"现在实现了什么?n是否保留在stdin中?

赋值抑制器*和否定扫描集[^如何协同工作?

这是否意味着:

  1. 通过使用*,所有与该格式字符串匹配的字符都取自stdin,但肯定没有分配?,以及
  2. n不是从stdin中提取的,而是用于确定相应格式字符串的扫描操作

我知道[^*各自单独做什么,但不知道它们一起做什么。问题是,将这两者混合在一起,再加上n的否定扫描集,会得到什么结果。


我知道在Stack Overflow上也有一个类似的问题,它只涉及对%[^n]的理解,这里是:%[^\n]在scanf()格式字符串中是什么意思。但是那里的答案对我的问题没有帮助。

%[^n]最多读取但不包括下一个n字符。用通俗的英语,它读一行文字。通常,该行将存储在char *字符串变量中。

char line[SIZE];
scanf("%[^n]", line);

*修饰符会抑制该行为。该行在被读取后被简单地丢弃,并且不需要任何变量。

scanf("%*[^n]");

*不会改变输入的处理方式。在任何一种情况下,从stdin读取下一个n之前的所有内容(但不包括该内容)。假设没有I/O错误,则可以保证从stdin进行的下一次读取将看到nEOF

如果我想读取并随后丢弃stdin中的每个字符(包括n字符),我应该使用哪个scanf()语句?

添加%*c以同时消耗n

scanf("%*[^n]%*c");

为什么%*c而不仅仅是n?如果使用n,它不会只使用一个换行符,还会使用任意数量的空格、制表符和换行符。n匹配任意数量的空白。最好使用%*c来消耗正好1个字符。

// Incorrect
scanf("%*[^n]n");

另请参阅:

  • 如何在扫描文本文件时跳过一行

我可以使用fflush()吗?

不,不要。fflush(stdin)未定义。

[n]的否定扫描集不是完全冗余的吗?因为默认情况下,scanf()会在空白字符第一次出现时终止相应格式字符串的扫描过程?

对于%s,是的,它将停止读取第一个空白字符。%s只读取一个单词。相比之下,%[^n]读取整行。它不会在空格或制表符处停止,只会在换行符处停止。

更普遍地说,使用方括号,只有列出的确切字符才是相关的。空白没有特殊的行为。与%s不同,它不会跳过前导空白,如果遇到空白,也不会提前停止处理。

n是否保留在stdin中?

是的。

但是现在scanf()语句中的格式字符串"%*[^n]"实现了什么?

它读取输入流中的所有字符,直到到达换行符并丢弃它们,而不从输入流中删除换行符。

通过使用*,所有与此格式字符串匹配的字符都取自stdin,但不分配?

正确。

n不是从stdin中获取的,而是用于确定相应格式字符串的扫描操作?

没错。当达到n时,大多数scanf使用ungetc将字符推回输入流。

我知道[^*各自单独做什么,但不知道它们一起做什么。

*放在[^之前,与单独使用[^完全一样,只是它不将输入读取到参数中,而是将其丢弃。

如果您想在之后丢弃n,请使用以下格式字符串:

"%*[^n]%*c"

由于它似乎没有被覆盖,读取换行符之前的所有内容,然后读取换行符的工作方法是:

scanf("%*[^n]%*c");
  • %*[^n]读取并丢弃,直到下一个字符为换行符
  • %*c只读取并丢弃一个字符,根据上面的内容,该字符将是换行符

您也可以将带有%c的换行符读取到变量中,看看您是否真的成功地获得了换行符,但您也可以直接检查EOF或错误,而不必为此烦恼。

  • %[^n]告诉scanf读取所有内容直到换行符('n'),并将其存储在相应的参数中
  • %*[^n]告诉scanf读取所有内容直到换行符('n')并丢弃它而不是存储它

示例:

  • Hi theren输入到scanf("%[^n]", buffer);中会产生buffer内容Hi there和剩余stdin内容n
  • Hi theren输入到scanf("%*[^n]");中导致Hi therestdin和剩余的stdin内容n中被扫描和丢弃

请注意,如果遇到的第一个字符是n字符,则%[^n]%*[^n]都将失败。一旦失败,stdin保持不变,scanf返回,导致格式字符串的其余部分被忽略。


如果您希望使用scanf删除清除stdin的一行并包括换行符,请使用

scanf("%*[^n]"); /* Read and discard everything until a newline character */
scanf("%*c");     /* Discard the newline character */

最新更新