5

私はC++でいくつかのファイル読み取り戦略を試していましたが、これに出くわしました。

ifstream ifsw1("c:\\trys\\str3.txt");
char ifsw1w[3];
do {
    ifsw1 >> ifsw1w;
    if (ifsw1.eof())
        break;
    cout << ifsw1w << flush << endl;
} while (1);
ifsw1.close();

ファイルの内容は

ファーストファーストファーストセカンド
セカンドファーストセカンドセカンド

出力を見ると、次のように出力されます。

ファーストファースト
ファーストセカンド
セカンドファースト

出力は次のようになると思いました。

モミ
stf
irs
tfi
....。

また、「secondsecond」が印刷されていないことがわかります。最後の読み取りがeofに達し、coutが実行されなかった可能性があると思います。しかし、最初の振る舞いは理解できません。

4

5 に答える 5

7

抽出演算子には ifsw1w 変数のサイズの概念がなく、(デフォルトでは) 空白、null、または eof に到達するまで文字を抽出します。これらは ifsw1w 変数の後のメモリ位置に格納されている可能性が高く、追加の変数が定義されている場合に悪いバグが発生する可能性があります。

目的の動作を得るには、使用できるはずです

ifsw1.width(3);

抽出する文字数を制限します。

于 2011-02-13T00:24:03.343 に答える
2

コードには未定義の動作があります。このようなことをすると:

char ifsw1w[3];

ifsw1 >> ifsw1w;

はバッファへのポインタoperator>>を受け取りますが、バッファの実際のサイズはわかりません。そのため、2 文字後に読み取りを停止する必要があることを知る方法はありません (3 ではなく 2 にする必要があることに注意してください。文字列を終了するには a のスペースが必要です)。'\0'

結論: データを読み取る方法を調べる場合、このコードはおそらく無視するのが最善です。このようなコードから学べることは、避けるべきいくつかのことだけです。ただし、発生する可能性のあるすべての問題を調査するよりも、いくつかの経験則に従う方が一般的には簡単です。

  1. std::string文字列を読み取るために使用します。
  2. 固定サイズのデータ​​には、固定サイズのバッファのみを使用してください。
  3. 固定バッファーを使用する場合は、そのサイズを渡して、読み取り量を制限します。
  4. ファイル内のすべてのデータを読み取りたい場合std::copy、多くのエラーを回避できます。

    std::vector<std::string> strings;   
    std::copy(std::istream_iterator<std::string>(myFile),
              std::istream_iterator<std::string>(),
              std::back_inserter(strings));
    
于 2011-02-13T00:35:47.070 に答える
2

メモリを破棄しています...定義した3文字を超えて読み取っています(スペースまたは新しい行が見つかるまで読み取っています...)。

char ごとに読み取り、言及した出力を実現します。

編集:イライラするのは正しいです、これも機能します(いくつかの修正があり、正確な結果が得られませんが、それが精神です):

char ifsw1w[4];
    do{
        ifsw1.width(4);
        ifsw1 >> ifsw1w;
        if(ifsw1.eof()) break;
        cout << ifsw1w << flush << endl;
    }while(1);
    ifsw1.close();
于 2011-02-13T00:24:56.280 に答える
2
  1. std::istream& operator>>(std::istream&, char *)安全に使用することは事実上不可能getsです。この点では同様です。バッファ サイズを指定する方法はありません。ストリームはバッファに書き込み、最後まで進みます。(上記の例は、未定義の動作を呼び出します)。を受け入れるオーバーロードを使用するか、 をstd::string使用しますstd::getline(std::istream&, std::string)

  2. チェックeof()が間違っています。fail()代わりに欲しい。ストリームがファイルの末尾にあるかどうかはまったく気にしません。情報の抽出に失敗したかどうかだけを気にします。

このような場合は、ファイル全体を文字列に読み込んで、その時点から文字列操作を使用する方がよいでしょう。stringstream を使用してそれを行うことができます。

#include <string> //For string
#include <sstream> //For stringstream
#include <iostream> //As before

std::ifstream myFile(...);
std::stringstream ss;
ss << myFile.rdbuf(); //Read the file into the stringstream.
std::string fileContents = ss.str(); //Now you have a string, no loops!
于 2011-02-13T00:25:29.847 に答える
1

空白を読み取るには、「noskipws」を使用できますが、空白はスキップされません。

ifsw1 >> noskipws >> ifsw1w;

ただし、3 文字だけを取得する場合は、get メソッドを使用することをお勧めします。

ifsw1.get(ifsw1w,3);
于 2011-02-13T00:22:15.460 に答える