这个内存损坏是如何在c ++中发生的?

时间:2014-07-22 16:19:48

标签: c++ memory-leaks stdvector

我不确定我明白下面的错误是什么

const char* packs[] = {"zero","one","two","three","four",..."twelve"} //abbreviated for post

struct packinfo {
    char* data;
    int   len;
};

std::vector<packinfo> k;
k.reserve(10000);

for (int i = 0; i < 10; ++i) {
    const char* data = packs[i];
    packinfo tobuf;
    tobuf.data = new char[strlen(data)];
    tobuf.len = strlen(data);
    memcpy(tobuf.data, data, strlen(data));
    k.push_back(tobuf);
}

for (int i = 0; i < k.size(); ++i)
    std::cout << "k[" << i << "]: " << k[i].data << ", ";
std::cout << std::endl;

for (int i = 0; i < k.size(); ++i) {
    packinfo& pack = k[i];
    bool foo = (i < 5);
    if (foo) std::cout << "inspecting k[" << i << "]: " << k[i].data << std::endl;
    delete pack.data;
    if (!foo) {
        k.erase(k.begin(), k.begin() + i);
        packinfo tobuf;
        const char* data = packs[10];
        tobuf.data = new char[strlen(data)];
        tobuf.len = strlen(data);
        memcpy(tobuf.data, data, strlen(data));
        break; //intentionally forgot to push_back
    }
}

for (int i = 0; i < k.size(); ++i)
    std::cout << "k[" << i << "]: " << k[i].data << ", ";
std::cout << std::endl

运行上述内容的输出如下:

k[0]: zero, k[1]: one, ... , k[9]: nine, //all as expected
inspecting k[0]: zero
inspecting k[1]: one
...
inspecting k[4]: four
k[0]: ten^], k[1]: six, k[2] seven, k[3]: eight, k[4]L nine, //gargabe crept in

垃圾如何蔓延到载体的开头?

2 个答案:

答案 0 :(得分:3)

strlen为您提供以空终止字符串的字符长度,而不计算nul-termination字符。因此,您正在动态分配一个太短而无法容纳目标字符串的数据缓冲区:

tobuf.data = new char[strlen(data)]; // too short by 1

当你使用memcpy填充它时,字符串的空终止没有空间,如果有的话你也不会复制它,因为数组太短了:

memcpy(tobuf.data, data, strlen(data)); // tobuf.data is not nul-terminated

当你试图读取它就好像它是一个以空字符串结尾的字符串时,你就会超出界限。

立即修复将使用strlen(data) +1,但您真正应该做的是将packinfo替换为std::string来避免整个问题。

std::vector<std::string> k;
k.reserve(10000);

答案 1 :(得分:1)

问题在于以下几点:

tobuf.data = new char[strlen(data)];
tobuf.len = strlen(data);
memcpy(tobuf.data, data, strlen(data));

在哪里为字符串终止符添加空间?

C ++有std::string类,你应该真正使用它,因为它可以帮助你解决这些问题。