Удалить [] вызывает повреждение кучи
Я прекрасно понимаю, что таких проблем не существует, но я искал часы и не мог понять, что я сделал не так, поэтому буду очень признателен за вашу помощь. (Я новичок в программировании)
Мне нужно создать своего рода менеджер словарей как часть моей домашней работы, но у меня, похоже, есть проблема с удалением слов. Я получаю сообщение об ошибке "... сработала точка останова".
Обычный ответ, который люди получают на эту проблему, состоит в том, что это - кучная коррупция, вызванная выходом за пределы, но я не могу видеть, и почему я вызвал это.
Я уже сделал что-то похожее с управлением информацией о шине, и оно работало отлично, так что я еще больше запутался... (Очевидно, я не сделал механизм точно таким же, но даже взглянув на свой предыдущий код, я не смог изолировать проблема)
Я добавил функции, которые, как мне кажется, вызывают беспокойство,
Функция добавления:
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;
будет работать просто отлично.