scanf:“%[^ \ n]”跳过第二个输入,但“%[^ \ n]”不跳过。为什么?

时间:2011-05-21 16:37:57

标签: c scanf

请考虑以下代码:

#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;
}

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

原因是什么。

6 个答案:

答案 0 :(得分:40)

在阅读完所需内容之后,您只需要“消费”'\n'字符。使用以下格式指令:

"%[^\n]%*c"

哪个会将新行中的所有内容读入您传入的字符串中,然后将使用单个字符(换行符)而不将其分配给任何内容('*'是'赋值抑制')。

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

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

更新您的示例:

  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");

答案 1 :(得分:7)

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

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

  

[

     

匹配非空的序列   来自指定集合的​​字符   接受的人物;下一个指针   必须是指向char的指针,并且那里   必须有足够的空间容纳所有人   字符串中的字符加上a   终止空字节。通常的跳过   领先的白色空间受到抑制。   字符串由。组成   特定字符(或不存在)   组;该集由定义   开括号之间的字符[   字符和一个小括号]   字符。该集不包括那些   字符,如果第一个字符   打开支架后是一个旋风   (^)。要包括一个紧密的括号   设置,使其成为之后的第一个角色   开口支架或旋风;   任何其他位置将结束该集。   连字符 - 也是   特别;放在另外两个之间   字符,它增加了所有干预   集合中的字符。包括一个   连字符,使它成为最后一个字符   在最后的紧密支架之前。对于   实例,[^] 0-9-]表示集合   “除了近括号外的一切,零   通过九,和连字符“。字符串   以a的外观结束   字符不在(或,与...   旋转,in)设置或当场   宽度耗尽。

答案 2 :(得分:3)

ALSO: 要读取字符串:

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

//这意味着在您遇到&#39; \ n&#39;之前阅读,然后删除&#39; \ n&#39;

:)

答案 3 :(得分:1)

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

答案 4 :(得分:0)

再加上上述答案 - 如果我们想要删除一些特定的模式,假设数字0-9,从输入流,那么我们将不得不使用getchar()来刷新缓冲区。

Merge the SID objects and drag in the final table.

Drag Contact Date & Contact Type objects in the final table.

Create detail variable for Contact date as "V Contact Date" and for Incident date as "V Incident Date".

Right click on the table->Format table-> checked the checkbox "Show rows with empty dimensions"

Drag below formula for calculated column and see.

=Sum(If([V Incident Date]<=RelativeDate([ V Contact Date];7) And ([V Incident Date]>=[ V Contact Date])) Then 1 Else 0)

所以这里如果你传递ashish019然后只有ashish将被复制到str而019将被留在缓冲区中,以便清除你需要多次getchar()。

答案 5 :(得分:-3)

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