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 行提出的问题提供 y
或 Y
响应时,循环确实起作用并且第 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);
}
我在玩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 行提出的问题提供 y
或 Y
响应时,循环确实起作用并且第 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);
}