C ++ istream :: read导致未定义的行为

时间:2014-09-26 14:26:12

标签: c++ binaryfiles binary-data

我使用以下代码将n字符从二进制文件复制到char*变量:

 std::ifstream is ("write.abc", std::ifstream::binary);
  if (is) {
    // get length of file:
    is.seekg (0, is.end);
    int length = is.tellg();
    is.seekg (0, is.beg);

    char * buffer = new char [length];

    std::cout << "Reading " << length << " characters... ";
    // read data as a block:
    is.read (buffer,length);
    std::cout << "length of buffer: "<<strlen(buffer) <<endl;
    std::cout << "Content of buffer: "<<buffer <<endl;
.......

我的文件内容:

enter image description here

这是编译的结果: enter image description here

我的问题如下:我等着:

  

缓冲区长度:13

     

缓冲内容:abcdefghjklmn

有人可以帮我解释一下结果吗?

2 个答案:

答案 0 :(得分:8)

您的缓冲区未终止 - 您需要分配一个额外的字符并将其设置为'\0',否则它只是一个未终止的C字符串,因此strlen很可能会返回无效值,并尝试打印字符串通常会产生垃圾。

char * buffer = new char [length + 1]; // <<< allocate space for `length`
                                       //     characters + terminator

std::cout << "Reading " << length << " characters... ";
// read data as a block:
is.read (buffer,length);
buffer[length] = '\0'; // <<< terminate C-style string

请注意,使用正确的C ++风格的std::string而不是旧式的C风格char *字符串可以避免这个和其他常见问题,并且通常更简单,更强大。如果您正在阅读二进制数据而不是文本,请考虑使用std::vector<unsigned char>

答案 1 :(得分:1)

请注意,这不是回答问题。这是评论的后续内容

一种解决方案是将缓冲区“存储”为[begin, end)范围而不是空终止的C字符串。这比null终止字符串有一个很大的优势 - 它可以与 STL算法一起使用,而无需调用strlen(...)来查找end元素。

举几个例子:

std::stringstream is("some text\n");

if (is)
{
    // get length of file:
    is.seekg (0, is.end);
    auto length = is.tellg();
    is.seekg (0, is.beg);

    char* begin = new char [length];
    char* end = begin + length;

    std::cout<<"Reading "<<length<<" characters...\n";
    // read data as a block:
    is.read (begin,length);

    //print the data:
    std::copy(begin, end, std::ostream_iterator<char>(std::cout));

    //print the data backwards:
    std::copy(std::reverse_iterator<char*>(end), std::reverse_iterator<char*>(begin), std::ostream_iterator<char>(std::cout));
    std::cout<<std::endl;

    //create string from data:
    std::string str(begin, end);
    std::cout<<str;

    //sum the characters
    auto sum = std::accumulate(begin, end, 0);
    std::cout<<sum<<std::endl;

    //make them uppercase
    std::transform(begin, end, begin, toupper);
    std::copy(begin, end, std::ostream_iterator<char>(std::cout));
}