Удалить [] вызывает повреждение кучи

Я прекрасно понимаю, что таких проблем не существует, но я искал часы и не мог понять, что я сделал не так, поэтому буду очень признателен за вашу помощь. (Я новичок в программировании)

Мне нужно создать своего рода менеджер словарей как часть моей домашней работы, но у меня, похоже, есть проблема с удалением слов. Я получаю сообщение об ошибке "... сработала точка останова".

Обычный ответ, который люди получают на эту проблему, состоит в том, что это - кучная коррупция, вызванная выходом за пределы, но я не могу видеть, и почему я вызвал это.

Я уже сделал что-то похожее с управлением информацией о шине, и оно работало отлично, так что я еще больше запутался... (Очевидно, я не сделал механизм точно таким же, но даже взглянув на свой предыдущий код, я не смог изолировать проблема)

Я добавил функции, которые, как мне кажется, вызывают беспокойство,

Функция добавления:

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.
}

РЕДАКТИРОВАТЬ: Любые части, которые являются чрезмерно неэффективными или явно неработающими, скорее всего, являются результатом того, что я возился с моим кодом, пытаясь выяснить это самостоятельно (например, 3 раза вызвал вызов strlen (еще раз спасибо за это, kfsone...) или забыв +1, чтобы '\0' пометил конец строки - на самом деле, нет, если мы пойдем по-видимому, вы не скажете мне мои ошибки @.@).

Что касается причины, по которой я имею дело с char вместо строк и векторов, пожалуйста, позвольте мне процитировать себя: "... как часть моей домашней работы". Я только начал программировать. Это, и я хочу понять основы, прежде чем перейти к использованию более удобных инструментов более высокого уровня.

4 ответа

Решение

Код сейчас работает.

Это было неправильно во всем. Я перепутал любую часть, касающуюся динамической памяти, пытаясь исправить это раньше.

Изначально я не заботился о том, чтобы 3 раза звонить в strlen, потому что это просто домашняя работа и очень маленькая программа, но я думаю, что лучше привыкнуть делать все правильно... Я также бросил копию, которую я, очевидно, не понимаю очень хорошо в пользу простого цикла.

// 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.

Изменить:

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

Для того, чтобы:

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

Это C++, почему вы не используете std::string вместо буферов символов?

Если вы должны использовать строки буфера char и безопасные формы strcpy_s, знайте, что длина буфера всегда должна быть размером целевого буфера, а не функции strlen. В вашем случае это немного понятно, так как вы создали буфер с функцией strlen. Но то, что вы должны сделать, это установить значение в переменную и затем использовать ее в любое время, когда вам нужен размер буфера.

Кроме того, и где я думаю, что ваша ошибка, вы пишете temp[i][strlen(word)] = '\0'; Но фактические индексы буфера изменяются от 0 до strlen(word)-1, поэтому вы пишете вне выделенной памяти.

У вашего кода есть несколько проблем.

Во-первых, если вы хотите разместить строку в стиле C в куче, используя new[], то вы должны обратить внимание на прекращение NUL персонаж.

Итак, если вы хотите сделать глубокую копию из строки word, то вы должны рассчитать достаточно места, учитывая strlen(word) + 1: +1 для прекращения NUL персонаж.
например:

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

Более того, следуя вашему коду с явным new[]с и delete[]с не легко.
В современном C++ вы можете использовать удобные классы надежных контейнеров, такие как std::vector и строковые классы, такие как std::stringвместо необработанных указателей и строк в стиле C

Вы можете просто сохранить список строк, используя std::vector<std::string>, а также vector::push_back() метод для добавления новых строк в вектор. Нет необходимости усложнять код new[], delete[], strcpy_s(), так далее.

И если вы хотите глубоко копировать строки, вы можете просто использовать простую естественную перегрузку operator= за std::stringи копировать конструкторы; например std::string temp = word; будет работать просто отлично.

Другие вопросы по тегам