为什么fgets不会在while循环中读取整行但是在for循环中工作?

时间:2013-03-22 10:16:19

标签: c linux fgets

如果我的fgets在while循环中,它只返回字符串的一半。如果它在for循环中,则返回整个字符串..任何想法为什么?

以下代码:

    FILE *fp; // File pointer
    char filename[] = "results.tsv";
    fp = fopen(filename, "r"); // Open file argv[1] for READ


    char s[4096];

    int num = atoi(fgets(s, sizeof(s), fp)); // Get first line (number of units in file)

    int i;
    for(i = 0; i < num; i++)
    {
        printf("%s", fgets(s, sizeof(s), fp)); // Prints everything
    }


    while (fgets(s, sizeof(s), fp) != NULL) // Loop until no more lines
    {
        printf("%s\n", s); // Only prints the x's
    }

    fclose(fp); // Close file

文件内容:

1
xxxxxxxx       yyyy       eee

大空格是标签(\ t)。

如果我运行它,我会得到:

仅限循环:

xxxxxxxx       yyyy       eee

仅限循环:

xxxxxxxx

感谢。

2 个答案:

答案 0 :(得分:1)

在开始使用while循环读取之前,必须使从流(文件)读取的位置从for循环开始读取的相同位置开始

您可以使用以下两种方式之一来完成:

1)关闭文件并重新打开并在启动while循环之前读取第一行

2)使用fseek(如 KiriliKirov 所述)指向for循环开始读取的相同位置。要使用ftell()函数获取当前位置(for循环开始读取的位置):

int num = atoi(fgets(s, sizeof(s), fp));
long int start_read = ftell (fp); // get the current postion //add this line in your code

.....

fseek ( fp , start_read , SEEK_SET ); // add this line in your code
while (fgets(s, sizeof(s), fp) != NULL)

第二个解决方案将避免关闭并重新打开文件并读取第一行。

ftell()返回流的位置指示符的当前值。

fseek()将与流关联的位置指示器设置为新位置

答案 1 :(得分:1)

已经诊断出,您的代码“适合我”。这是我为它创建的SSCCE。如果不带参数调用,则使用while循环。如果使用任何参数调用,它将使用for循环。无论哪种方式,它对我来说都是正常的。请注意,代码不直接使用fgets()的返回值;在执行此操作之前,它会检查输入操作是否成功。它还回应它正在做什么和阅读它。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    FILE *fp;
    char filename[] = "results.tsv";

    if ((fp = fopen(filename, "r")) == 0)
    {
        fprintf(stderr, "%s: failed to open file %s\n", argv[0], filename);
        exit(1);
    }

    char s[4096];

    if (fgets(s, sizeof(s), fp) == 0)
    {
        fprintf(stderr, "Premature EOF\n");
        exit(1);
    }

    int num = atoi(s);
    printf("Num lines: %d\n", num);

    if (argc > 1)
    {
        printf("For loop:\n");
        for (int i = 0; i < num; i++)
        {
            if (fgets(s, sizeof(s), fp) == 0)
            {
                fprintf(stderr, "Premature EOF\n");
                exit(1);
            }
            printf("%d: %s", i+1, s);
        }
    }
    else
    {
        int i = 0;
        while (fgets(s, sizeof(s), fp) != NULL)
        {
            printf("While loop:\n");
            printf("%d: %s", ++i, s);
        }
    }

    fclose(fp);

    return 0;
}

如果您使用此代码并且系统上的代码失败,那么您可以提交您的证据。除此之外,您应该确定您正在使用的平台,并且您应该在文件results.tsv中提供数据的十六进制转储(或等效)。例如,我使用的数据文件包含字节:

0x0000: 31 0A 78 78 78 78 78 78 78 78 09 79 79 79 79 09   1.xxxxxxxx.yyyy.
0x0010: 65 65 65 65 0A                                    eeee.
0x0015: