C++ C++;:从动态结构数组中删除元素并移动其他元素

C++ C++;:从动态结构数组中删除元素并移动其他元素,c++,malloc,free,delete-operator,C++,Malloc,Free,Delete Operator,我有一个结构数组。我试图从该数组中删除一个元素列表,并将其他元素向左移动。在移动元素之后,我尝试删除/释放数组末尾不再需要的内存。我有以下代码: #include <iostream> #include<stdio.h> #include<stdlib.h> void removeelement(int*); void displayelements(); typedef struct { int n; }element; element** arra

我有一个结构数组。我试图从该数组中删除一个元素列表,并将其他元素向左移动。在移动元素之后,我尝试删除/释放数组末尾不再需要的内存。我有以下代码:

#include <iostream>
#include<stdio.h>
#include<stdlib.h>
void removeelement(int*);
void displayelements();

typedef struct {
   int n;
}element;
element** array;

int numofelements=5;

int main() {
   array = (element**)malloc(5*sizeof(element*));
   for(int i=0;i<5;i++){
       array[i] = new element;
       array[i]->n=i;
   }
   int removelist[3] = {1,3,4};
   removeelement(removelist);
   displayelements();
   return 0;
}
void removeelement(int* removelist){
    for(int i=0;i<3;i++){
        int index = removelist[i];
        int j;
        for(j=index;j<numofelements-2;j++){
            array[j] = array[j+1];
        }
        delete [] array[j+1];
        numofelements--;
    }
}
void displayelements(){
    int i=0;
    while(i<numofelements){
        printf("%d\n",array[i]->n);
        i++;
    }
}
我不明白这是什么原因。正如许多人在其他论坛中建议的那样,我正在使用“new”操作符创建一个新的动态元素

编辑:

我做了以下修改:


我为(j=index;j更改了
,您在
new[]
表达式未返回的指针上使用了
delete[]
表达式。因此程序的行为未定义

使用
new
分配的任何内容都必须重新分配
delete
delete[]
将不起作用


即使使用了正确的表达式,也存在另一个错误:

int numofelements=5;

//...
for(int i=0;i<3;i++){
    int index = removelist[i];
    int j;
    for(j=index;j<numofelements-2;j++){
        array[j] = array[j+1];
    }
    delete [] array[j+1];
    numofelements--;
}
int numofelements=5;
//...
对于(int i=0;i这一行:

delete [] array[j+1];
删除“数组[j+1]”指向的元素数组。但“数组[j+1]”已由此行初始化:

array[i] = new element;
它只分配单个元素,而不是元素数组,因此删除操作也应仅删除单个元素。例如:

delete array[j+1];
然而,主要的问题是删除了错误的元素。为了了解原因,让我们假设初始化“array”的循环将其指针分配给五个“element”结构,我们称之为A、B、C、D和E

在调用removeelements()之前,“array”包含以下指针:

array[0] -> A
array[1] -> B
array[2] -> C
array[3] -> D
array[4] -> E
“numofelements”是5

在removeelements()内部,要删除的第一个元素是1,内部循环如下所示:

for(j=1;j<3;j++){
    array[j] = array[j+1];
}
for(j=3;j<2;j++){
    array[j] = array[j+1];
}
for(j=4;j<1;j++){
    array[j] = array[j+1];
}
此时“j”包含3,因此“delete array[j+1]”将删除“array[4]”指向的元素,即“E”

然后将“numofelements”减为4

要删除的第二个元素是3。因为“numofelements”现在是4,所以内部循环如下所示:

for(j=1;j<3;j++){
    array[j] = array[j+1];
}
for(j=3;j<2;j++){
    array[j] = array[j+1];
}
for(j=4;j<1;j++){
    array[j] = array[j+1];
}

for(j=3;j除了内存管理中的明显错误外,如果您首先对
removelist
数组进行排序,然后从最后一个条目到第一个条目在该数组中向后工作,通常可以简化该方法

这样做会改变
数组
调整大小的方式,因为您会对不再受影响的条目进行调整大小(移动元素)。在当前代码中,您正在移动条目,并且在循环的后续迭代中,您需要使用“无效”重新访问这些移动的条目
removelist
要删除的索引集

请参阅mayaknife和User207933的答案,以说明删除每个项目后无效条目的问题(在
removelist
数组中从最低条目到最高条目)如前所述,即使使用
std::vector
也不会对您有所帮助,因为此问题指出了用于删除元素的基本逻辑中的缺陷

如果要在
removelist
数组中反向工作,那么您可以在当前代码中解决这个问题(我说“可能已经解决了”,因为这没有经过充分测试,但它或多或少说明了所提出的观点):


注意反向迭代器
rbegin()
rend()的用法,因此模仿了 ReVelistist容器的向后遍历。

你似乎对C++有很多误解。你应该退一步,从一本好书中系统地学习语言。很多人建议使用<代码>新< /代码>不喜欢你。张贴模糊评论有什么用?有人能确切地告诉我我做错了什么吗?主要是,
delete[]
意味着
new[]
,不是
new
。而是改为使用。
new
不应该被使用,尤其是初学者。你真正应该做的是标记要删除的元素,然后删除标记的元素。你不应该在删除每个元素的同时移动数组,因为这会使
removelist
条目变为no在每次迭代中不再指向有效条目。是的,您的许多代码可能使用了
vector
,但主要问题是您的删除逻辑,无论您使用的是
new
还是
vector
。虽然
array[4]
被复制到
array[3]
,但这是
array[4]
被删除了两次。@O'Neil谢谢你指出。我读错了程序。如果
removelist[1]
小于3,我描述的场景就会发生。
void removeelement(int* removelist)
{
    for(int i = 2; i >= 0 ; --i)
    {
        int index = removelist[i];
        array* elementToDelete = array[index];
        for(j=index; j < numofelements -2; j++)
        {
            array[j] = array[j+1];
        }
        delete [] elementToDelete;
        numofelements--;
    }
}
#include <vector>
#include <algorithm>
#include <iostream>
#include <array>

struct element {
   int n;
};

int main() 
{
    std::vector<element> arr(5);

    for (int i = 0; i < 5; ++i)
       arr[i].n = i;

    std::array<int, 3> removelist = {1,3,4};
    // sort the list 
    std::sort(removelist.begin(), removelist.end());

    // work backwards, erasing each element
    std::for_each(removelist.rbegin(), removelist.rend(),[&](int n){arr.erase(arr.begin() + n);});

    // output results
    for( auto& v : arr)
       std::cout << v.n << '\n';
}