124

次のC++コードは、ifstreamオブジェクトを使用して、 EOFに達するまでテキストファイル(1行に1つの数値)から整数を読み取ります。最後の行の整数を2回読み取るのはなぜですか?これを修正する方法は?

コード:

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    ifstream iFile("input.txt");    // input.txt has integers, one per line

    while (!iFile.eof())
    {
        int x;
        iFile >> x;
        cerr << x << endl;
    }

    return 0;
}

input.txt

10  
20  
30

出力

10  
20  
30  
30

:コードスニペットを小さく保つために、すべてのエラーチェックコードをスキップしました。上記の動作は、Windows(Visual C ++)、cygwin(gcc)、およびLinux(gcc)で見られます。

4

7 に答える 7

132

一連のイベントを厳密に追跡してください。

  • グラブ10
  • 20をつかむ
  • グラブ30
  • EOFを取得します

最後から2番目の反復を見てください。30を取得し、EOFをチェックするために続行しました。EOFマークがまだ読み取られていないため、EOFに到達していません(「2値的に」言えば、その概念上の位置は30行の直後です)。したがって、次の反復に進みます。xは前の反復からまだ30です。これで、ストリームから読み取り、EOFを取得します。xは30のままで、ios::eofbitが発生します。stderr x(前の反復と同じように30)に出力します。次に、ループ状態でEOFをチェックします。今回は、ループから外れています。

これを試して:

while (true) {
    int x;
    iFile >> x;
    if( iFile.eof() ) break;
    cerr << x << endl;
}

ちなみに、コードには別のバグがあります。空のファイルで実行しようとしたことがありますか?あなたが得る振る舞いはまったく同じ理由によるものです。

于 2008-08-22T02:50:56.403 に答える
38

私はこの例が好きです。今のところ、whileブロック内に追加できるチェックを省略しています。

ifstream iFile("input.txt");        // input.txt has integers, one per line
int x;

while (iFile >> x) 
{
    cerr << x << endl;
}

それがどれほど安全かわからない...

于 2008-08-22T02:59:25.477 に答える
15

これには別のアプローチがあります。

#include <iterator>
#include <algorithm>

// ...

    copy(istream_iterator<int>(iFile), istream_iterator<int>(),
         ostream_iterator<int>(cerr, "\n"));
于 2008-08-22T04:46:33.503 に答える
6

元のコードをあまり変更しないと、次のようになる可能性があります。

while (!iFile.eof())
{  
    int x;
    iFile >> x;
    if (!iFile.eof()) break;
    cerr << x << endl;
}

しかし、私は一般的に上記の他の2つの解決策を好みます。

于 2013-02-12T16:17:56.190 に答える
5

EOF パターンには、EOF チェック プロセスを「ブートストラップ」するための主要な読み取りが必要です。空のファイルには、最初の読み取りまで EOF が設定されていないことを考慮してください。プライム読み取りは、このインスタンスで EOF をキャッチし、適切にループを完全にスキップします。

ここで覚えておく必要があるのは、ファイルの使用可能なデータを超えて最初に読み取ろうとするまで、EOF を取得しないことです。正確な量のデータを読み取っても、EOF のフラグは立てられません。

ファイルが空の場合、指定されたコードが出力されることを指摘する必要があります。これは、EOF がループに入ったときに値が x に設定されるのを防いでいるためです。

  • 0

したがって、主要な読み取りを追加し、ループの読み取りを最後に移動します。

int x;

iFile >> x; // prime read here
while (!iFile.eof()) {
    cerr << x << endl;
    iFile >> x;
}
于 2014-12-03T13:56:26.360 に答える
2

最後の行の終わりには改行文字がありますが、これは >> 演算子によって読み取られず、ファイルの終わりではありません。実験を行い、新しい行 (ファイルの最後の文字) を削除してください。重複は発生しません。柔軟なコードを作成し、不要な影響を回避するには、他のユーザーから提供されたソリューションを適用するだけです。

于 2014-12-20T22:53:39.747 に答える