fgets()不按我的预期工作

4

有没有人能告诉我为什么这段代码不起作用?当我运行它时,它只会打印出“输入有关Trail 1的信息”,并且没有任何输入就跳过了下一步。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 15

void readingArrays(int numberOfTrails,char arr[MAX][20]);

char array[MAX][20];

int main(void)
{
    int numberOfTrails;
    printf("Enter the number of trails\n");
    scanf("%d",&numberOfTrails);

    readingArrays(numberOfTrails,array);

    return 0;
}

void readingArrays(int numberOfTrails,char arr[numberOfTrails][20])
{
    for(int i=0;i<numberOfTrails;i++)
    {
        printf("Enter info about trails %d\n",i+1);
        fgets(arr[i],4,stdin);
        //getchar();
        //strtok(arr[i], "\n");
        printf("%s\n",arr[i]);
    }
}

4
如果在循环的第一次运行中出现问题,那么可能是因为之前的一行留下了一个换行符。请发布一个最小、完整、可验证的示例,以便我们查看周围的代码。 - R Sahu
"stdin"是否已声明并打开? - Ohmless
如果我使用 getchar(),它通常会打印 "Enter info...",但是仅在第二步之后才开始打印输入,并且删除输入的第一个字符。因此,无论我写什么,它只会在另一个步骤中打印出来。 - Levan
https://dev59.com/307Sa4cB1Zd3GeqPzwTJ - nnn
你想读取一行文本,但只需要读取一个数字。 - David Schwartz
1
Uila,stdin与stderr和stdout一起在stdio.h中声明。 - Ray
3个回答

2
Perl语言提供了chomp函数,可以从输入的行中删除换行符。我发现这是一个非常实用的函数,值得掌握。
char*
chomp(char* p)
{
    if(!p) return p;
    size_t len=strlen(p);
    //if(len<=0) return(p);
    if(len>0) len--;
    if(p[len]=='\n') p[len--]='\0';
    if(len>=0) if(p[len]=='\r') p[len--]='\0';
    return(p);
}

因此,声明一个变量用于读取一行,并只使用gets来解析该行。更加清晰。请注意,您的数组是一个char[20]的MAX数组,您可能会输入一个远大于这个长度的行。从整行中读取,然后提取所需的部分可能更有效。
char array[MAX][20];
int ndx;
char line[100];
for( ndx=0; fgets(line,sizeof(line)-1),stdin); ++ndx ) {
    chomp(line);
    strncpy(array[ndx],line,sizeof(array[ndx])-1);
    //combine both into one line:
    //strncpy(array[ndx],chomp(line),sizeof(array[ndx])-1);
    /*NULL termination of array[ndx] left as exercise for reader*/
}

注意:最好使用 size_t len,因为这是 strlen() 返回的类型。不要使用 chomp(),考虑使用 https://dev59.com/M3E85IYBdhLWcg3wnU0d#28462221 - chux - Reinstate Monica

2

问题

主函数中的scanf函数读取整数,但是在输入流中留下了换行符\n。当readingArrays的第一次循环迭代到来时,fgets看到这个换行符,就会认为你已经输入了你的trail信息并按下了回车键。它会打印空字符串和换行符,并继续进行下一次迭代。

解决方案

一个解决方案是告诉scanf在数字后面添加一个空格,以读取并忽略空格。

因此,要从stdin获取numberOfTrails,你可以这样做:

scanf("%d ",&numberOfTrails);

感谢@Ray指出了这个解决方案!

2
scanf("%d%*c",&numberOfTrails); - David C. Rankin
你说得对,我忘记了scanf中的*修饰符。谢谢。 - AlexPogue
如果您正在使用scanf,则无需手动处理空格。 输入的空格字符(由isspace函数指定)将被跳过,除非规范包括[、c或n说明符。 (C99 7.19.6.2 / 8)此外,scanf格式说明符中的空格意味着“读取并丢弃空格,直到下一个非空格字符”。因此,如果您有一个fscanf,然后是一个fgets,fscanf(stdin,“%d ”,&n); fgets(buf,BUFSIZ,stdin);将导致fscanf在调用fgets之前消耗尾随空格(包括换行符)。 - Ray
请注意,7.19.6.2/8 引用的是在 %d 读取之前的空格。因此,即使数字位于不同的行上,scanf("%d%d", &a, &b) 也可以工作。但由于在您的情况下第二个读取不是由 scanf 完成的,所以您需要在 %d 后面加上空格,以强制它在读取数字并丢弃尾随空格后继续读取。 - Ray
你能否编辑答案,删除声称它不起作用的部分?(或者更好的方法是,编辑示例以使用scanf(“%d”),使其起作用。) - Ray
显示剩余4条评论

0

1)在scanf()后添加此行代码:getchar()

2)将fgets(...)的4改为19。

程序将正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接