EOF までテキスト ファイルから読み取り、最後の行を繰り返す [重複]
質問
この質問にはすでに答えがあります:
次の 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;
}
最後の行の終わりには改行文字がありますが、これは >> 演算子では読み取れず、ファイルの終わりではありません。実験を行って新しい行 (ファイルの最後の文字) を削除してください。重複は発生しません。柔軟なコードを使用して不要な影響を回避するには、他のユーザーが提供した解決策を適用するだけです。