質問
次のC ++コードでは、 getline()
は最後の改行文字を消費するが、 t入力ストリームに送信します。
私がまだ理解していないのは、プログラムの出力です。入力" Test \ n"で"を取得する理由est \ n&quot ;?私の間違いは、不要なゴミを最後に追加するのではなく、文字列の first 文字にどのように影響しますか?また、プログラムの出力がデバッガーでの文字列の表示方法と矛盾するのはなぜですか(" Test \ n&quot ;、予想どおり)
#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;
}
解決
この結果、Windows Vista、Visual Studio 2005 SP2も複製しました。
一体何が起こっているのかがわかったら、この投稿を更新します。
編集:わかりました。問題(および人々が得ているさまざまな結果)は\ 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
だから&quot;テスト&quot;キャリッジリターン(行の先頭にカーソルを戻す)、ヌル文字(Tを上書きする)、最後にカーソルを新しい行に正しく置く\ nが出力されます。
\ rを削除するか、nec文字をチェックして、vecBufferから文字列の長さを直接取得する関数を記述する必要があります。
他のヒント
コンソールプロジェクトとしてビルドされたVisual Studio 2005 SP2(実際には&quot;バージョン8.0.50727.879&quot;と表示されます)を使用してコンパイルされたコードを使用して、Windows XP Pro Service Pack 2システムでTommyの問題を再現しました。
test.txtファイルに&quot; Test&quot;のみが含まれている場合CR、プログラムは&quot;を吐き出しますest&quot; (先頭のスペースに注意してください)実行時。
もし推測をしなければならなかった場合、このバージョンの実装にはバグがあり、Windowsの改行文字をUnixで扱う必要があるように(&quot;同じ行&quot;文字)、その後、最初の文字を消去して次のプロンプトまたは何かの一部を保持します。
更新: それで少し遊んだ後、私はそれが起こっていることは肯定的です。デバッガでstrResultを見ると、最後に10進数の13の値をコピーしたことがわかります。それはCRであり、Windowsランドでは '\ n'であり、それ以外の場所はすべて「行の先頭に戻る」ことです。代わりにコンストラクタを次のように変更した場合:
string strResult(vecBuffer.begin()、vecBuffer.begin()+ input.gcount()-1);
...(CRがコピーされないように)、&quot; Test&quot;を出力します。あなたが期待するように。
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で停止し、期待どおりの出力が得られます。
Windows XP Pro SP3(32ビット)上のVisual Studio 2005 SP2を使用してコードをテストしましたが、すべて正常に動作します。