EOF までテキスト ファイルから読み取り、最後の行を繰り返す [重複]

StackOverflow https://stackoverflow.com/questions/21647

  •  09-06-2019
  •  | 
  •  

質問

次の C++ コードは イフストリーム テキスト ファイル (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) で見られます。

役に立ちましたか?

解決

一連の出来事を注意深く追跡してください。

  • 10を掴む
  • グラブ20
  • 30を掴む
  • EOFを取得

最後から 2 番目の反復を見てください。30 を取得し、EOF のチェックを続けました。EOF マークがまだ読み取られていないため、EOF に到達していません (「バイナリ的に」言えば、概念的な位置は 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;
}

ところで、コードには別のバグがあります。空のファイルで実行しようとしたことがありますか?得られる動作もまったく同じ理由によるものです。

他のヒント

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

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

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

どれくらい安全なのかは分かりませんが…

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

#include <iterator>
#include <algorithm>

// ...

    copy(istream_iterator<int>(iFile), istream_iterator<int>(),
         ostream_iterator<int>(cerr, "\n"));

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

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

ファイルが空の場合は、EOF によりループの開始時に値が x に設定されるのを防ぐため、指定されたコードが出力されることを指摘しておきます。

  • 0

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

int x;

iFile >> x; // prime read here
while (!iFile.eof()) {
    cerr << x << endl;
    iFile >> x;
}

元のコードをあまり変更しなければ、次のようになります。

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

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

int x;
ifile >> x

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top