[英]fgets() doesn't work as expected in C
给出以下代码:
#include <stdio.h>
int main()
{
int testcase;
char arr[30];
int f,F,m;
scanf("%d",&testcase);
while(testcase--)
{
printf("Enter the string\n");
fgets(arr,20,stdin);
printf("Enter a character\n");
F=getchar();
while((f=getchar())!=EOF && f!='\n')
;
putchar(F);
printf("\n");
printf("Enter a number\n");
scanf("%d",&m);
}
return 0;
}
我希望用户输入一个字符串,一个字符和一个数字,直到测试用例变为零为止。
我的疑问/问题:
1.用户无法输入字符串。 似乎fgets
无法正常工作。 为什么?
2.如果我使用scanf
而不是fgets
,则getchar
无法正常工作,即我在其中输入的任何字符都只是putchar
作为新行。 为什么?
谢谢您的帮助。
混合函数fgets()
, scanf()
和getchar()
容易出错。 scanf()
函数通常在输入流中留下一个\\n
字符,而fgets()
通常不这样做,这意味着对I / O函数的下一个调用可能或可能不需要处理上一个调用留下的内容在输入流中。
更好的解决方案是对所有用户输入使用一种样式的I / O功能。 与sscanf()
结合使用的fgets()
可以很好地实现此目的。 应该检查函数的返回值,并且在发生错误的情况下fgets()
将返回空指针。 sscanf()
返回成功分配的数量,可用于验证输入是否如预期的那样。
这是发布代码的修改版本。 fgets()
将输入存储在慷慨分配的缓冲区中; 请注意,如果有足够的空间,此函数最多可以存储\\n
字符(包括\\n
字符)的输入。 如果预期输入字符串不包含空格,则可以使用sscanf()
提取字符串,而无需担心换行符; 类似地,使用sscanf()
提取字符或数字输入可减轻代码对\\n
进一步处理的负担。
#include <stdio.h>
int main(void)
{
int testcase;
char arr[30];
char F;
int m;
char buffer[1000];
do {
puts("Enter number of test cases:");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
} while (sscanf(buffer, "%d", &testcase) != 1 || testcase < 0);
while(testcase--)
{
puts("Enter the string");
/* if string should not contain spaces... */
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
sscanf(buffer, "%29s", arr);
printf("You entered: %s\n", arr);
putchar('\n');
puts("Enter a character");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
sscanf(buffer, "%c", &F);
printf("You entered: %c\n", F);
putchar('\n');
do {
puts("Enter a number");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
} while (sscanf(buffer, "%d", &m) != 1);
printf("You entered: %d\n", m);
putchar('\n');
}
return 0;
}
另一方面,如果输入字符串可能包含空格,则fgets()
可以将输入直接读取到arr
,但是存储的字符串将包含\\n
字符,应该将其删除。 一种方法是使用strcspn()
函数找到\\n
的索引:
#include <string.h> // for strcspn()
/* ... */
puts("Enter the string");
/* or, if string may contain spaces */
if (fgets(arr, sizeof arr, stdin) == NULL) {
/* handle error */
}
/* replace newline */
arr[strcspn(arr, "\r\n")] = '\0';
printf("You entered: %s\n", arr);
putchar('\n');
/* ... */
请注意,在将%s
与scanf()
函数一起使用时,应始终指定最大宽度,以避免缓冲区溢出。 在这里,当读入arr
时它是%29s
,因为arr
可以容纳30个char
,并且必须为空终止符( \\0
)保留空间。 检查sscanf()
返回值以查看用户输入是否无效,在这种情况下,将再次要求输入。 如果测试用例的数量小于0,则必须再次输入。
一个简单的技巧是编写一个函数来解释换行符。 在每个scanf之后调用clear()
void clear (void){
int c = 0;
while ((c = getchar()) != '\n' && c != EOF);
}
请参阅此问题以获取进一步的说明: C:多个scanf,当我为一个scanf输入一个值时,它将跳过第二个scanf
最终得到了解决方案,我们如何才能安全地同时使用scanf和fgets。
#include <stdio.h>
int main()
{
int testcase,f,F,m;
char arr[30];
scanf("%d",&testcase);
while((f=getchar())!=EOF && f!='\n')
;
while(testcase--)
{
printf("Enter the string\n");
fgets(arr,30,stdin);
printf("Enter a character\n");
F=getchar();
while((f=getchar())!=EOF && f!='\n')
;
putchar(F);
printf("\n");
printf("Enter a number\n");
scanf("%d",&m);
while((f=getchar())!=EOF && f!='\n')
;
}
}
我们需要确保在fgets读取任何内容之前,请使用简单的while循环清空缓冲区。
感谢所有人的帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.