0

如果我的 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

仅 while 循环:

xxxxxxxx

谢谢。

4

2 回答 2

1

正如已经诊断的那样,您的代码“对我有用”。这是我为它创建的 SSCCE。如果不带参数调用,它将使用while循环。如果使用任何参数调用,它将使用for循环。无论哪种方式,它都适合我。请注意,代码不fgets()直接使用 from 的返回值;它在这样做之前检查输入操作是否成功。它还呼应了它正在做的事情和正在阅读的内容。

#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:
于 2013-03-22T14:49:16.510 回答
1

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

您可以通过以下两种方式之一来做到这一点:

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

2)使用 fseek (如KiriliKirov所说)指向 for 循环开始读取的相同位置。要做到这一点,您必须使用以下函数获取当前位置(for 循环开始读取的位置)ftell()

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()将与流关联的位置指示器设置为新位置

于 2013-03-22T10:19:25.240 回答