【问题标题】:fgets doesn't wait for the keyboard inputfgets 不等待键盘输入
【发布时间】:2013-09-29 01:51:57
【问题描述】:

我想从用户的键盘输入中读取两个字符串,这是我尝试过的代码:

char nomFichier[50], emp[100], empEtNomFichier[150];
printf("\nDonner le nom du fichier : ");
fgets(nomFichier, sizeof nomFichier, stdin);
printf("\nDonner l'emplacement du fichier : ");
fgets(emp, sizeof emp, stdin)
sprintf(empEtNomFichier, "%s/%s", emp, nomFichier);

问题是当我运行这段代码时,程序不会等待键盘输入第一个fgets(),这就是程序的外观:

Donner le nom du fichier : 
Donner l'emplacement du fichier : /home/ee/Desktop
/home/ee/Desktop

【问题讨论】:

  • 您能发布最短的可编译示例来演示该问题吗?
  • @PaulGriffiths,请查看我对帖子所做的修改
  • “可编译”是指将它包含在 main() 函数中,#include 正确的标题等等,可以复制和编译的东西,当你遇到问题时你编译并运行它。您当前的代码中可能还有其他原因导致它,创建一个可编译的示例将有助于消除这种可能性。例如,如果我只是将您的代码放入 main() 函数中,我将无法重现您的问题。

标签: c


【解决方案1】:

问题实际上是 fgets() 将终止换行符读入字符串。除非缓冲区填满,或者遇到没有换行符的 EOF,否则返回字符串中的最后一个字符将是 '\n'。

通过以下方式摆脱它:

n = strlen(nomFichier);
if (n>0 && nomFichier[n-1]=='\n') { nomFichier[n-1] = 0; }

...并对 if 块中的 emp 字符串执行相同的操作。还有一些方法可以将 strtok 与 '\n' 用作分隔符,或将 sscanf 与 "%xx[^\n]%*c" 格式一起使用,而且我相信其他人有不同的喜欢的解决方案。 (“xx”是该scanf格式的最大字符串长度,十进制。)

顺便说一句,另一个问题不能通过 fflush 便携式解决,因为 fflush 不一定做任何事情。例如,GNU C 实现将 fflush(stdin) 视为无操作。

问题很可能是由于先前的 scanf() 读取了一个值,但没有读取换行符。在面向标记的输入 (scanf/fscanf) 和面向行的输入 (fgets) 之间切换的程序必须准备好处理剩余的行。

最快的解决方法是:

scanf("%*[^\n]%*c"); /* discard up to and including the next '\n' character */

...或更直接的:

int c;
while ( (c = getchar()) != EOF && c != '\n') { }

无论哪种方式,我都会把它放在一个静态函数中,让优化器决定是否内联它。

每次从 scanf() 切换到 fgets() 输入时都需要这样做。

【讨论】:

  • 感谢投反对票的人。它不仅提醒我要回到这一点,而且还让我的回文数少得可怜。
【解决方案2】:

试试:

char nomFichier[50], emp[100], empEtNomFichier[150];
printf("\nDonner le nom du fichier : ");
fflush(stdout);
fgets(nomFichier, sizeof nomFichier, stdin);
printf("\nDonner l'emplacement du fichier : ");
fflush(stdout);
fgets(emp, sizeof emp, stdin)
sprintf(empEtNomFichier, "%s/%s", emp, nomFichier);

stdout 是行缓冲的,所以它不会在没有 \n 字符的情况下输出 - 试试 fflush();

或者试试:

char buf[256]={0x0};
setvbuf(stdout, buf, _IONBF, 256);

【讨论】:

  • 一开始我也是这么想的,但他的问题是输出的东西似乎太多了,而不是太少了。无论如何,他说他试过这个,但没有用。
  • 好吧 - 我错过了他尝试 fflush() 的地方。但这是一种解决方案。另一种是使用 setvbuf() 将标准输出更改为无缓冲 - 这不是一个好主意。我会添加它。
  • 是的,我删除了那个答案和 cmets。我不确定他是否在未显示的代码中做其他事情,这会扰乱缓冲。
【解决方案3】:

其他答案都不适合我。我能够像这样得到我正在寻找的行为:

只需创建一个一次性变量并在 fgets() 之前将换行符读入其中:

// . . . code above that leaves a \n in the stdin
char str[20];
char c;
printf("Prompt: ");
scanf("%c", &c);
fgets(str, 20, stdin);
printf("str = %s\n", str);

但是,正如下面的评论所指出的,这不是一个干净的“修复”。

【讨论】:

  • 代码如何知道 scanf("%c", &c); 读取的是 newline 而不是其他字符?之前的阅读可能由于各种原因而停止,而且肯定不是在'\n'。此外,假设在printf("Prompt: "); 时间没有待处理的输入,那么如果输入只是"\n"scanf("%c", &c); 将读取用于fgets(str, 20, stdin); 的换行符。
  • @chux-ReinstateMonica 是的。我完全同意XD。我的回答与其说是解决方案,不如说是临时破解。我会回去编辑它以使其清楚。我只是想分享一些东西,可以帮助那些需要在为学校或其他东西上交之前快速修补这个奇怪的东西的人。
  • 如果您担心丢弃不是换行符的字符,您可以在删除之前检查一下吗?
  • "你不能在删除之前检查一下吗?" --> 是的。 IMO,与其消耗前一个输入函数的剩余部分(即'\n'),不如让前一个输入函数读取整行。使用scanf(),它可能,但更简洁地避开scanf(),而只使用fgets()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-06
  • 2017-03-13
  • 1970-01-01
  • 2017-07-07
  • 2015-04-12
  • 2022-11-10
相关资源
最近更新 更多