delete []导致堆损坏

时间:2014-01-14 22:01:02

标签: c++ heap delete-operator heap-corruption

我很清楚这样有无数问题,但我搜索了几个小时,无法理解我做错了什么,所以我非常感谢你的帮助。 (我是编程新手)

我需要创建一个字典管理器作为我作业的一部分,但我似乎有删除单词的问题。 我收到一条错误消息“...触发断点”。

人们解决这个问题的常见答案是,这是由于超出范围而导致的堆损坏,但我无法看到是否以及如何导致此问题。

我已经使用公交信息管理做了类似的事情,它完美地工作,这让我更加困惑...(显然,我没有使机制完全相同,但即使看了我之前的代码,我也无法' t隔离问题)

我添加了我认为值得关注的功能,

添加功能:

void Add_Word(char**& dictionary, int& dictionary_size, char word[])
{
    char** temp = new char*[dictionary_size + 1];   // Create a new array of appropriate size.

    int i;
    for (i = 0; i < dictionary_size; i++)
    {
        temp[i] = dictionary[i];    // Copy head pointers addresses for all existing items.
    }
    temp[i] = new char[strlen(word)];   // Add the space for the new word,
    temp[i][strlen(word)] = '\0';   // mark its end

    strcpy_s(temp[i], strlen(word) + 1, word);  // then copy it.
    // I'm really not so sure about what I should put in the buffer length but
    // strlen(word) + 1 seemed to work... I know... not good, but strlen(word) alone caused a problem.

    if (dictionary_size > 0)
        delete []dictionary;    // Delete previous head pointers array if there are any and
    dictionary = temp;  // reset the main pointer to the address of the new one.

    dictionary_size++;  // Finally, increase dictionary_size.
}

删除功能:

void Delete_Word(char**& dictionary, int& dictionary_size, char* word)
{
    // !!! This is where the crash thingy happens.
    delete[] Search_For_Word(dictionary, dictionary_size, word);    // Delete the word from the dictionary.
    // Search_For_Word returns a pointer to the word it receives, from the dictionary.

    char** temp = new char*[dictionary_size - 1];   // Create a new array of appropriate size.

    int i;
    for (i = 0; i < dictionary_size; i++)
    {
        if (dictionary[i][0])
            temp[i] = dictionary[i];    // Copy the head pointers of the existing
           // items to the new array except for the deleted word.
    }

    delete[] dictionary;    // Delete previous head pointers array and
    dictionary = temp;  // reset the main pointer to the address of the new one.

    dictionary_size--;  // Finally, decrease dictionary_size.
}
编辑:任何效率过低或明显损坏的部分很可能是因为我弄乱了我的代码试图自己解决这个问题(例如调用strlen提到的3次(再次感谢kfsone)。 ..),或忘记为'\ 0'标记字符串结尾的+1 - 实际上,不,如果我们显然你不会告诉我我的错误@。@)。

至于我处理char而不是字符串和向量的原因,请允许我自己引用:“......作为功课”的一部分。我刚刚开始编程。那个,我想先了解基础知识,然后继续使用更舒适的高级工具。

4 个答案:

答案 0 :(得分:4)

变化:

temp[i] = new char[strlen(word)]

要:

temp[i] = new char[strlen(word)+1]

答案 1 :(得分:3)

这是C ++,你为什么不使用std :: string而不是char buffers?

如果必须使用char缓冲区字符串,并且strcpy_s的安全形式知道缓冲区长度必须始终是目标缓冲区的大小,则不要使用strlen函数。在您的情况下,由于您使用strlen函数创建了缓冲区,因此它有点容易理解。但是你应该做的是将值设置为变量,然后在需要缓冲区大小时使用它。

此外,我认为你的错误在哪里,你正在写temp [i] [strlen(word)] ='\ 0';但是缓冲区的实际索引从0到strlen(word)-1,所以你要在分配的内存之外写入。

答案 2 :(得分:3)

您的代码有几个问题。

首先,如果要使用new[]在堆上分配C样式的字符串,则必须注意终止NUL字符。

因此,如果您想要从字符串word执行深层复制,那么您必须计算足够的空间,考虑strlen(word) + 1+1用于终止NUL }字符 e.g:

// Original code (wrong):
//
//     temp[i] = new char[strlen(word)];
//
// New code:
temp[i] = new char[strlen(word) + 1]; // consider terminating NUL (+1)

此外,使用明确new[]delete[]的代码并非易事 在 modern C ++ 中,您可能希望使用方便的健壮容器类(如std::vector)和字符串类(如std::string),而不是原始的C样式指针和字符串。

您可以使用std::vector<std::string>vector::push_back()方法存储字符串列表,以便向矢量添加新字符串。无需使用new[]delete[]strcpy_s()等复杂代码。

如果你想深度复制字符串,你可以使用operator=的{​​{1}}的简单自然重载,并复制构造函数;例如std::string可以正常使用。

答案 3 :(得分:0)

代码正在运行。

一切都错了。 在尝试修复动态内存之前,我几乎把任何关于动态内存的部分搞砸了。

我最初并不关心为strlen打三次电话,因为它只是作业和一个非常小的程序,但我想最好习惯以正确的方式做事...... 我也放弃了我显然不太了解的副本,支持简单的for循环。

// Add function. The rest is cut.
    int word_length = strlen(word);

    temp[i] = new char[word_length + 1];    // Added +1 here.
    temp[i][word_length] = '\0';    /* This was correct after all.
    the word_length index is the correct ending.*/

    for (int j = 0; j < word_length; j++)   // copy replaced by for loop.
        temp[i][j] = word[j];
    // cut
}

void Delete_Word(char**& dictionary, int& dictionary_size, char* word)
{
    delete[] Search_For_Word(dictionary, dictionary_size, word);
   // There was a -1 mistake here I made in order to try and fix the thing earlier.
// No need for more, it works perfectly now.