C语言 scanf: "%[^\n]" 跳过第二个输入,但 " %[^\n]" 不会。为什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6083045/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 08:42:57  来源:igfitidea点击:

scanf: "%[^\n]" skips the 2nd input but " %[^\n]" does not. why?

cscanf

提问by phoxis

Consider the following code:

考虑以下代码:

#include <stdio.h>

int main (void)
{
  char str1[128], str2[128], str3[128];

  printf ("\nEnter str1: ");
  scanf ("%[^\n]", str1);
  printf ("\nstr1 = %s", str1);

  printf ("\nEnter str2: ");
  scanf ("%[^\n]", str2);
  printf ("\nstr2 = %s", str2);

  printf ("\nEnter str3: ");
  scanf ("%[^\n]", str3);
  printf ("\nstr3 = %s", str3);

  printf ("\n");
  return 0;
}

When it is executed only the first scanfstops for the prompt. The program does not stop for the next scanfs. But if the format string is changed from "%[^\n]"to " %[^\n]"(note the blank space before %), then it works okay. Does some existing newline character from the previous input buffer is automatically accepted ? But flushing stdindoes not solve this.

当它被执行时,只有第一次scanf停止提示。程序不会在下一个scanfs停止。但是如果格式字符串从 更改"%[^\n]"" %[^\n]"(注意 前面的空格%),则它可以正常工作。是否自动接受来自先前输入缓冲区的某些现有换行符?但是冲洗stdin并不能解决这个问题。

What is the cause of this.

这是什么原因。

回答by Michael Burr

You just need to 'consume' the '\n'character after you've read what you want. Use the following format directive:

你只需要'\n'在阅读完你想要的东西后“消费”这个角色。使用以下格式指令:

"%[^\n]%*c"

Which will read everything up to the newline into the string you pass in, then will consume a single character (the newline) without assigning it to anything (that '*'is 'assignment suppression').

这会将换行符之前的所有内容读入您传入的字符串中,然后将使用单个字符(换行符)而不将其分配给任何内容(即'*'“分配抑制”)。

Otherwise,the newline is left in the input stream waiting to immediately terminate the the subsequent "%[^\n]"format directives.

否则,换行符会留在输入流中,等待立即终止后续的"%[^\n]"格式指令。

The problem with adding a space character to the format directive (" %[^\n]") is that the space will match anywhite space. So, it will eat the newline from the end of the previous input, but it will also eat any other whitespace (including multiple newlines).

向格式指令 ( " %[^\n]")添加空格字符的问题在于空格将匹配任何空格。因此,它会吃掉前一个输入末尾的换行符,但也会吃掉任何其他空格(包括多个换行符)。

Update to your example:

更新您的示例:

  char* fmt = "%[^\n]%*c";

  printf ("\nEnter str1: ");
  scanf (fmt, str1);
  printf ("\nstr1 = %s", str1);

  printf ("\nEnter str2: ");
  scanf (fmt, str2);
  printf ("\nstr2 = %s", str2);

  printf ("\nEnter str3: ");
  scanf (fmt, str3);
  printf ("\nstr2 = %s", str3);

  printf ("\n");

回答by phoxis

When you use scanf()to read the strings, your format string (%[^\n]) tells the function to read every character that is not '\n'. That leaves the '\n'character in the input buffer. So when you try to read str2and str3, scanf()finds the first thing in the buffer is '\n'each time and, because of the format string, doesn't remove it from the input buffer. What you need is a getchar()between the times that you read from the input buffer (often placed immediately after scanf()). Since there is already a '\n'in the buffer, your program won't appear to hang because it won't have to wait for input for getchar()to receive. Try it. :)

当您使用scanf()读取字符串时,您的格式字符串 ( %[^\n]) 会告诉函数读取不是 的每个字符'\n'。这将'\n'字符留在输入缓冲区中。因此,当您尝试读取str2and 时str3,每次都会scanf()发现缓冲区中的第一件事,'\n'并且由于格式字符串,不会将其从输入缓冲区中删除。您需要的是getchar()从输入缓冲区读取的时间之间(通常紧接在 之后scanf())。由于'\n'缓冲区中已经存在 a ,您的程序不会挂起,因为它不必等待输入getchar()来接收。尝试一下。:)

For those who haven't a clue what that scanf()modifier does, here is a relevant excerpt from http://linux.die.net/man/3/scanf-

对于那些不知道该scanf()修饰符的作用的人,这是来自http://linux.die.net/man/3/scanf的相关摘录-

[

Matches a nonempty sequence of characters from the specified set of accepted characters; the next pointer must be a pointer to char, and there must be enough room for all the characters in the string, plus a terminating null byte. The usual skip of leading white space is suppressed. The string is to be made up of characters in (or not in) a particular set; the set is defined by the characters between the open bracket [ character and a close bracket ] character. The set excludes those characters if the first character after the open bracket is a circumflex (^). To include a close bracket in the set, make it the first character after the open bracket or the circumflex; any other position will end the set. The hyphen character - is also special; when placed between two other characters, it adds all intervening characters to the set. To include a hyphen, make it the last character before the final close bracket. For instance, [^]0-9-] means the set "everything except close bracket, zero through nine, and hyphen". The string ends with the appearance of a character not in the (or, with a circumflex, in) set or when the field width runs out.

[

匹配指定的一组接受字符中的非空字符序列;next 指针必须是指向 char 的指针,并且必须有足够的空间容纳字符串中的所有字符,加上一个终止空字节。前导空白的通常跳过被抑制。字符串将由特定集合中(或不在)中的字符组成;该集合由左括号 [ 字符和右括号 ] 字符之间的字符定义。如果左括号后的第一个字符是抑扬符号 (^),则该集合将排除这些字符。要在集合中包含右括号,请将其放在左括号或抑扬符之后的第一个字符;任何其他位置都将结束该组。连字符 - 也是特殊的;当放在另外两个字符之间时,它将所有中间字符添加到集合中。要包含连字符,请将其作为最后一个右括号之前的最后一个字符。例如,[^]0-9-] 表示集合“除了右括号、零到九和连字符之外的所有内容”。字符串以不在(或,带抑扬符,in)集合中的字符出现或字段宽度用完时结束。

回答by MLSC

ALSO: To read a string:

另外:要读取字符串:

scanf("%[^\n]\n", a);

// it means read until you meet '\n', then trash that '\n'

// 意思是一直读到遇到'\n',然后把那个'\n'扔掉

:)

:)

回答by Ashish Maurya

Just adding a bit further to above answer- If we want to remove some specific pattern, suppose numbers 0-9, from input stream then we will have to use getchar() for flushing buffer.

只是在上面的答案中进一步添加一点 - 如果我们想从输入流中删除一些特定的模式,假设数字 0-9,那么我们将不得不使用 getchar() 来刷新缓冲区。

scanf("%[^0-9\n]", str1);
while(getchar() != '\n'); // this approach is much better bcz it will
                         // remove any number of left characters in buffer.
scanf("%c", &ch);

So here if you pass ashish019 then only ashish will be copied to str and 019 would be left in buffer so for clearing that you need getchar() multiple times.

所以在这里,如果你通过 ashish019 那么只有 ashish 会被复制到 str 并且 019 会留在缓冲区中以便清除你需要多次 getchar() 。

回答by Abdus

Just use a getchar() after the scanf() function.

只需在 scanf() 函数之后使用 getchar() 即可。

回答by Murtaza Amravatiwala

use fflush(stdin)to clear the input buffer after reading each input.

用于fflush(stdin)在读取每个输入后清除输入缓冲区。