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)です。

実行すると、次のようになります。

Forループのみ:

xxxxxxxx       yyyy       eee

Whileループのみ:

xxxxxxxx

ありがとう。

4

2 に答える 2

1

whileループで読み取りを開始する前に、ストリーム(ファイル)からの読み取り位置を、forループが読み取りを開始するのと同じ位置から開始する必要があります。

次の2つの方法のいずれかでそれを行うことができます。

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)

2番目の解決策は、ファイルを閉じて再度開くことと、最初の行の読み取りを回避します。

ftell()ストリームの位置インジケーターの現在の値を返します。

fseek()ストリームに関連付けられている位置インジケーターを新しい位置に設定します

于 2013-03-22T10:19:25.240 に答える
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;
}

このコードを使用してもシステムで失敗した場合は、証拠を提出できます。特に、作業しているプラ​​ットフォームを特定し、ファイル内のデータの16進ダンプ(または同等のもの)を提供する必要があります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 に答える