gets() 函数从第二次开始被跳过

gets() function gets skipped from the second time onwards

我在玩C,写了这段代码:

   1 #include<stdio.h>
   2 #define ASK_PROMPT printf("\nDo you want to continue(Y/N):");
   3 main()
   4 {
   5    char main[20], i;
   6    start:
   7    printf("Please enter your string:\n");
   8    gets(main);
   9    printf("\nstring entered was:\n \n%s\n", main);
   10   ASK_PROMPT;
   11   scanf("%c",&i);
   12       
   13   if(i=='Y'||i=='y')
   14       goto start;
   15   getch();
   16   return;
   17 }

当我执行此代码时,goto loop 无法正常工作。在对第 10 行提出的问题提供 yY 响应时,循环确实起作用并且第 7 行再次 executed/printed 但第 8 行被跳过(不等待提供输入).

我建议 不要 使用 gets。在使用 gets 时,如果输入的字符串大于 main[20] 的大小怎么办。 gets 不会阻止这种情况,它会导致 UB.

使用fgets-

fgets(main,20,stdin);

你的问题的原因是 scanf("%c",&i); 之后的 '\n' 留在 stdin 中导致 gets return 当它遇到 '\n'

为了避免 '\n' 你可以在 scanf 声明 -

之后这样做
int c;
while ( (c = getchar()) != EOF && c != '\n' );

修复

scanf("%c",&i); 更改为 scanf("%c%*c",&i);

问题

输入i后的\n是导致gets()不等待输入的原因。

良好做法

  • Stop 使用 gets()goto 等。相反,您可以使用 fgets()scanf() 等。切勿使用弃用的功能。
  • char 数组名称从 main 更改为其他名称,比如 m

感谢@Coolguy 对 scanf 使用的评论。

问题:

在输入 yEnter 以响应您的提示后,程序的输入流包含字符 'y''\n'(换行符)。 scanf 调用从输入流中删除 'y' 字符,将换行符留在原处。

gets 从输入流中读取,直到它看到一个换行符,然后将其丢弃;由于它首先看到的是前一个条目中的换行符,因此它 returns 无需阅读任何进一步的输入。

解决方法:

首先,不要使用gets。曾经。它在 1999 年的修订版中被弃用,并已从 2011 年的修订版中完全删除。使用它 在您的程序中引入一个 failure/security 漏洞点。将其替换为对 fgets 的调用,请注意,如果有空间,fgets 将尝试将换行符存储在目标缓冲区中。

其次,您需要使用输入流中的尾随换行符。 vish4071 给出的答案显示了一种方法 - 使用 scanf 读取输入后的字符(应该是换行符)并丢弃它:

scanf( " %c%*c", &i ); 

格式字符串中的前导空格告诉 scanf 跳过任何前导空格,%c 转换说明符告诉 scanf 从输入流中读取下一个字符并将其存储值转换为 i%*c 转换说明符告诉 scanf 从输入流中读取下一个字符并将其丢弃。

另一种选择是消耗输入直到看到换行符:

scanf( " %c", &i );
while ( getchar() != '\n' )  // repeatedly read characters from input stream
  ;                          // until we see a newline

另一种选择是将您的输入读取为另一个字符串:

char answer[3]; // space for y/n response plus newline plus 0 terminator
...
if ( fgets( answer, sizeof answer, stdin ) )
{
  if ( tolower( answer[0] ) == 'y' )
  {
    // do stuff
  }
}

您可能需要检查 answer 缓冲区中是否存在换行符;如果它不存在,那么用户输入的字符数超过了您的缓冲区大小可容纳的字符数,这可能会影响以后的读取,并且您需要在下一次读取操作之前清除该虚假输入:

if ( !strchr( answer, '\n' ) )
  while ( getchar() != '\n' )
    ;

对现有代码的最小修复,只需再次使用 gets(main)。如果代码要使用 ASK_PROMPT;,那么 ASK_PROMPT 的定义不需要尾随 ; .正如已经建议的那样,您可以使用 fgets() 代替 gets(),并使用适当的循环代替 start: 和 goto。

#include<stdio.h>
#define ASK_PROMPT printf("\nDo you want to continue(Y/N):")
int main()
{
    char main[20];
    start:
    printf("Please enter your string:\n");
    gets(main);
    printf("\nstring entered was:\n \n%s\n", main);
    ASK_PROMPT;
    gets(main);
    if(main[0]=='Y'||main[0]=='y')
        goto start;
    getch();
    return(0);
}