6

gcount()次の C++ コードでは、 が必要以上に大きな数値を返していることに気付きました。これgetline()は、 が最後の改行文字を消費するが、それを入力ストリームに送信しないためです。

しかし、私がまだ理解していないのは、プログラムの出力です。「Test\n」と入力すると、「est\n」と表示されるのはなぜですか? 私の間違いが、文字列の末尾に不要なゴミを追加するのではなく、文字列の最初の文字に影響を与えるのはなぜですか? そして、プログラムの出力が、デバッガーでの文字列の表示方法と一致しないのはなぜですか (予想どおり、"Test\n")。

#include <fstream>
#include <vector>
#include <string>
#include <iostream>

using namespace std;

int main()
{
    const int bufferSize = 1024;
    ifstream input( "test.txt", ios::in | ios::binary );

    vector<char> vecBuffer( bufferSize );
    input.getline( &vecBuffer[0], bufferSize );
    string strResult( vecBuffer.begin(), vecBuffer.begin() + input.gcount() );
    cout << strResult << "\n";

    return 0;
}
4

4 に答える 4

12

この結果、Windows Vista、Visual Studio2005SP2も複製しました。

一体何が起こっているのかがわかったら、この投稿を更新します。

編集:さて、そこに行きます。問題(および人々が得ているさまざまな結果)は\rからのものです。何が起こるかというと、呼び出しinput.getlineて結果をvecBufferに入れます。getline関数は\nを取り除きますが、\rはそのままにします。

次に、vecBufferを文字列変数に転送しますが、入力からgcount関数を使用します。つまり、入力変数には\ nが含まれ、vecBufferには含まれないため、1文字が多すぎます。

結果のstrResultは次のとおりです。

-       strResult   "Test"
        [0] 84 'T'  char
        [1] 101 'e' char
        [2] 115 's' char
        [3] 116 't' char
        [4] 13 '␍'  char
        [5] 0   char

したがって、「テスト」が出力され、その後にキャリッジリターン(カーソルを行の先頭に戻す)、ヌル文字(Tを上書きする)、最後に\ nが続き、カーソルが新しい行に正しく配置されます。 。

したがって、\ rを削除するか、vecBufferから直接文字列の長さを取得してヌル文字をチェックする関数を作成する必要があります。

于 2009-06-24T18:29:38.540 に答える
6

Windows XP Pro Service Pack 2システムでのTommyの問題を、コンソールプロジェクトとしてビルドされたVisual Studio 2005 SP2(実際には「バージョン8.0.50727.879」と表示されています)を使用してコンパイルされたコードで複製しました。

test.txtファイルに「Test」とCRだけが含まれている場合、プログラムは実行時に「est」(先頭のスペースに注意)を吐き出します。

私が大げさな推測をしなければならないとしたら、このバージョンの実装には、Windowsの改行文字をUnixで処理されるように(「同じ行の先頭に移動」として)処理するというバグがあると言えます。文字)、次に最初の文字を消去して、次のプロンプトなどの一部を保持します。


更新: 少し遊んだ後、私はそれが起こっていることを確信しています。デバッガーでstrResultを見ると、最後に10進数の13の値をコピーしたことがわかります。これはCRであり、Windowsでは「\ n」であり、それ以外の場所では「行の先頭に戻る」です。代わりに、コンストラクターを次のように変更した場合:

文字列strResult(vecBuffer.begin()、vecBuffer.begin()+ input.gcount()-1);

...(CRがコピーされないように)次に、期待どおりに「テスト」が出力されます。

于 2009-06-24T18:20:07.103 に答える
2

T が実際に書き込まれてから上書きされていると確信しています。rxvt ウィンドウ (cygwin) で同じプログラムを実行すると、期待どおりの出力が得られます。いくつかのことができます。開いている ios::binary を取り除くと、\r\n が \n に自動変換され、期待どおりに動作します。

また、ファイルを開くダイアログの開くボタンの小さな下向き矢印をクリックし、[次で開く...] -> [バイナリ エディタ] を選択して、バイナリ エディタでテキスト ファイルを開くこともできます。これにより、ファイルを調べて、\n だけでなく \r\n が実際に含まれていることを確認できます。

編集: 出力をファイルにリダイレクトしましたが、書き出されています:

Test\r\0\r\n

\0 を取得する理由は、gcount が 6 (ストリームから 6 文字が削除された) を返しますが、最後の区切り文字がバッファーにコピーされず、代わりに '\0' であるためです。文字列を作成するとき、実際には「\0」を含めるように指示しています。std::string は埋め込まれた 0 に問題はなく、要求どおりに出力します。一部のシェルは明らかに空白文字を出力して T を上書きしていますが、他のシェルは何もせず、出力は問題ないように見えますが、'\0' が埋め込まれているため、おそらく間違っています。

cout << strResult.c_str() << "\n";

最後の行をこれに変更すると、\0 で停止し、期待どおりの出力が得られます。

于 2009-06-24T19:14:59.033 に答える