删除字符串后C++检测到堆损坏

Heap corruption detected in C++ after removing strings

本文关键字:损坏 检测 C++ 字符串 删除      更新时间:2023-10-16

运行此代码时,出现错误

,如下图所示。我试过在 GCC 编译器上运行它,它工作正常。但是当在Windows上的Visual Studio上运行它时,出现了此错误:

调试错误!

程序:C:\Users\yudab\source\repos\Project2\Debug\Project2.exe

检测到堆损坏:在0x014FD2E0的正常块 (#153( 之后。

CRT 检测到应用程序在堆缓冲区结束后写入内存。

经过一些测试,似乎只有在尝试删除第二个单词后才会出现错误。

#include <cstring>
#include <string>
#pragma warning(disable : 4996)
#include <iostream>
using namespace std;
void delStr(char**& lexicon, int& lexSize, char word[]);
void printAll(char** lexicon, int lexSize);
void retract2dArr(char**& arr, int& size);
int main() {                    
char** lexicon = new char* [3]; 
lexicon[0] = new char[6]{ "hello" };
lexicon[1] = new char[5]{ "test" };
lexicon[2] = new char[6]{ "world" };
int size = 3;
char removeTest[5] = { "test" }; //The first word I want to remove from the list
char removeWorld[6] = { "world" }; //The second word I want to remove from the list
printAll(lexicon, size); //First prints the entire list
delStr(lexicon, size, removeTest); //Removes the first word
delStr(lexicon, size, removeWorld); //Removes the second word
printAll(lexicon, size); //Prints the list after deleting the words

return 0;
}
void delStr(char**& lexicon, int& lexSize, char word[]) {
bool toDelete = false;
for (int i = 0; i < lexSize; i++) {
if (strcmp(lexicon[i], word) == 0) {
toDelete = true;
for (; i < lexSize - 1; i++) {
strcpy(lexicon[i], lexicon[i + 1]);
}
}
}
if (toDelete == true) {
delete[] lexicon[lexSize - 1];
retract2dArr(lexicon, lexSize);
}
return;
}
void printAll(char** lexicon, int lexSize) {
for (int i = 0; i < lexSize; i++) {
cout << lexicon[i];
if (i != lexSize - 1) {
cout << " ";
}
}
cout << endl;
return;
}

void retract2dArr(char**& arr, int& size) {
size--;
char** newArr = new char* [size];
for (int i = 0; i < size; i++) {
*(newArr + i) = *(arr + i);
}
printAll(newArr, size);
delete[] arr;
arr = newArr;
return;
}

你不能strcpy一个stringanother

if (strcmp(lexicon[i], word) == 0) {
toDelete = true;
for (; i < lexSize - 1; i++) {
strcpy(lexicon[i], lexicon[i + 1]);
}
}

因为每个字符串length会有所不同。

例:

lexicon[0] = new char[6]{ "hello" };
lexicon[1] = new char[5]{ "test" };  // length is 4
lexicon[2] = new char[6]{ "world" }; // length is 5

第3 个字符串不适合第 2 个字符串,它会导致越界访问。

正如基兰·比拉达(kiran Biradar(指出的那样,strcpy是这里的罪魁祸首。尽管与其将词典中的每个单词复制到为前一个单词分配的内存中,不如简单地将指针移回lexicon数组中。

为您的delStr函数尝试这样的事情:

void delStr(char**& lexicon, int& lexSize, char word[]) {
for (int i = 0; i < lexSize; i++) {
if (strcmp(lexicon[i], word) == 0) {
delete[] lexicon[i];
for (; i < lexSize - 1; i++) {
lexicon[i] = lexicon[i + 1];
}
retract2dArr(lexicon, lexSize);
}
}
}

附言您不需要使用toDelete标志,您可以在第一个if内调用retract2dArr函数。