为什么我的弦的开头消失了?

时间:2009-06-24 16:59:08

标签: c++ string vector cout

在下面的C ++代码中,我意识到gcount()返回的数字比我想要的大,因为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 个答案:

答案 0 :(得分:12)

我还复制了这个结果,Windows Vista,Visual Studio 2005 SP2。

当我弄清楚发生了什么事时,我会更新这篇文章。

编辑:好的,我们去吧。问题(以及人们得到的不同结果)来自\ r \ n。如果您调用input.getline并将结果放入vecBuffer,会发生什么。 getline函数剥离\ n,但将\ r留在原位。

然后将vecBuffer转换为字符串变量,但是使用输入中的gcount函数,这意味着你会得到一个char太多,因为输入变量仍包含\ n,而vecBuffer不包含。

结果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

然后打印“Test”,然后是回车符(将光标放回到行的开头),空字符(覆盖T),最后是\ n,它正确地将光标放在上面新线。

所以你要么必须删除\ r,要么写一个直接从vecBuffer获取字符串长度的函数,检查空字符。

答案 1 :(得分:6)

我在Windows XP Pro Service Pack 2系统上复制了Tommy的问题,使用Visual Studio 2005 SP2编译的代码(实际上,它说“版本8.0.50727.879”),作为控制台项目构建。

如果我的test.txt文件只包含“Test”和CR,程序会在运行时吐出“est”(注意前导空格)。

如果我不得不采取疯狂的猜测,我会说这个版本的实现有一个错误,它处理Windows换行符,就像它应该在Unix中处理(作为“前面的相同的行“字符”,然后它会清除第一个字符以保存下一个提示的一部分。


<强>更新 在玩了一下后,我很肯定这是正在发生的事情。如果你在调试器中查看strResult,你会看到它在末尾复制了十进制13的值。那是CR,在Windows-land中是'\ n',而在其他任何地方都是“回到行的开头”。如果我将构造函数更改为:

string strResult(vecBuffer.begin(),vecBuffer.begin()+ input.gcount() - 1);

...(以便不复制CR)然后它会像你期望的那样打印出“测试”。

答案 2 :(得分:2)

我很确定T实际上已经被写入然后被覆盖了。在rxvt窗口(cygwin)中运行相同的程序会产生预期的输出。你可以做几件事。如果你在打开时摆脱了ios :: binary,它将自动转换为\ n \ n到\ n,并且事情会像你期望的那样工作。

您还可以在二进制编辑器中打开文本文件,方法是单击打开文件对话框打开按钮上的小向下箭头,然后选择打开,使用...-&gt;二进制编辑器。这将让你查看你的文件并确认它确实有\ r \ n而不仅仅是\ n。

修改 我将输出重定向到一个文件,它正在写出来:

Test\r\0\r\n

你得到\ 0的原因是gcount返回6(从流中删除了6个字符)但是最后的分隔符没有复制到缓冲区,而是'\ 0'。当你构造字符串时,你实际上是在告诉它包含'\ 0'。 std :: string对嵌入式0没有问题,并按要求输出。有些shell显然输出一个空白字符并覆盖T,而其他shell则没有做任何事情,输出看起来没问题,但仍然可能是错误的,因为它有嵌入式'\ 0'

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

将最后一行更改为此位将在\ 0上停止,并且还会获得预期的输出。

答案 3 :(得分:1)

我在Windows XP Pro SP3(32位)上使用Visual Studio 2005 SP2测试了您的代码,一切正常。