从指针数组中删除元素 - C ++

时间:2015-11-04 05:31:09

标签: c++ arrays algorithm pointers

所以我有一组结构指针。它看起来像这样:

index                 [0   1   2   3   4]
value of structure     21  7   42  30  NULL

我试图删除存储在索引2(42)的值。我认为,因为每个 这个数组的元素是一个指向结构的指针,然后为了删除42, 我必须首先在arr [2]上调用delete,然后我会说arr [2] = arr [3] 然后delete在arr [3]上,然后arr [3] = arr [4]。 那不行,所以我决定在没有delete关键字的情况下尝试它,只做arr [2] = arr [3]和arr [3] = arr [4],它有效。 所以我的问题是,为什么我不必使用delete关键字来执行此操作。我想如果我只是将arr [2]设置为arr [3],那么arr [2]指向的结构将丢失,我会得到内存泄漏。那不是这样吗?

5 个答案:

答案 0 :(得分:2)

  

我认为既然这个数组的每个元素都是一个指向结构的指针,那么为了删除42,我必须首先在arr上调用delete [2]

是的,您可以在delete上使用arr[2]来释放arr[2]指向的内存。

  

然后我会说arr [2] = arr [3]

到目前为止一切顺利。

  

然后在arr [3]上删除

这就是问题所在。假设你有这样的代码:

int arr_cnt = 5;
int *arr[arr_cnt];
for(int i = 0; i < arr_cnt; ++i)
    arr[i] = new int(i+arr_cnt);  // using ints for simplicity, but concept is the same

您的数组arr现在看起来像这样:

idx   *arr[]     values in heap, due to using 'new' operator
    +-----+
0   | a---|----> 5
    +-----+
1   | b---|----> 6
    +-----+
2   | c---|----> 7
    +-----+
3   | d---|----> 8
    +-----+
4   | e---|----> 9
    +-----+

字母代表new返回的不同内存地址。

这意味着,要正确删除索引2处的元素,您需要:

  1. delete上使用arr[2]以避免内存泄漏,
  2. 使用仍然有效的其他地址覆盖arr[2] (在此步骤之前使用arr[2]会触发seg-fault)
  3. 将数组位置复制到arr[2](见下文)
  4. 减少数组的长度(例如arr_cnt--;
  5. 换句话说:

    delete arr[2];      // step 1, address 'c' no longer valid
    arr[2] = arr[4];    // step 2, arr[2] is now 'e', which points to 9 just like arr[4]
    arr[4] = NULL;      // step 3, arr[4] is now invalid
    --arr_cnt;          // step 4
    

    图表现在看起来像这样:

    idx   *arr[]     values in heap, due to using 'new' operator
        +-----+
    0   | a---|----> 5
        +-----+
    1   | b---|----> 6
        +-----+
    2   | e---|-----------+   // address 'e' used to be in arr[4]
        +-----+           |
    3   | d---|----> 8    |
        +-----+           |
    4   | nil |      9 <--+
        +-----+
    
      

    然后arr [3] = arr [4]。这不起作用

    如果您按照图表,您可能已经注意到,在两者上使用delete意味着您使两个条目无效。换句话说,如果我们跳过第二个图并尝试delete arr[2]; arr[2] = arr[3]; delete arr[3]逻辑,那么最终会得到:

    delete arr[2];
        +-----+
    0   | a---|----> 5
        +-----+
    1   | b---|----> 6
        +-----+
    2   | c---|----> ?  // invalidated
        +-----+
    3   | d---|----> 8
        +-----+
    4   | e---|----> 9
        +-----+
    
    arr[2] = arr[3];
        +-----+
    0   | a---|----> 5
        +-----+
    1   | b---|----> 6
        +-----+
    2   | d---|-+
        +-----+ |
    3   | d---|-+--> 8  // both have the same address, so point to the same place
        +-----+
    4   | e---|----> 9
        +-----+
    
    delete arr[3];
        +-----+
    0   | a---|----> 5
        +-----+
    1   | b---|----> 6
        +-----+
    2   | d---|-+
        +-----+ |
    3   | d---|-+--> ?  // both invalid now, but not set to null
        +-----+
    4   | e---|----> 9
        +-----+
    
      

    所以我决定尝试不使用delete关键字,只需要执行arr [2] = arr [3]和arr [3] = arr [4],它就可以了。

    但现在你有内存泄漏。您在C ++中每delete总是new,就像C中每free malloc一样。

      

    所以我的问题是,为什么我不必使用delete关键字来执行此操作。

    必须使用它。问题是你的失效比你想象的要多,最后还是尝试使用已经解除分配的内存。当程序试图访问这样的内存时,会导致分段错误。我不记得Windows会显示的确切消息,但它可能是某种未处理的异常消息。 (分段错误往往是GNU / Linux术语。)

      

    我在想如果我只是将arr [2]设置为arr [3],那么arr [2]指向的结构就会丢失,我会得到内存泄漏。那不是这样吗?

    你在这里是对的。问题不在于您对new / delete关系的理解,而是您所描述的分配是副本这一事实,并且您最终删除的内容超出预期。< / p>

答案 1 :(得分:0)

检查以确保您确实拥有一组结构指针。此外,如果在删除索引2处的元素后确实有一个结构指针数组,请不要在3或之后的索引上调用delete。只是arr [2] = arr [3]; arr [3] = arr [4];它不是内存泄漏,因为您只是复制指向结构的指针而不是实际结构。

struct A
    {
    };


//This is an array of A structures
A * array1;

//This is an array of pointers to A structures
A** array2;

答案 2 :(得分:0)

  

我必须首先在arr [2]上调用delete,然后我会说arr [2] = arr [3]然后在arr [3]上删除,然后arr [3] = arr [4]。< / p>

您只需删除arr[2]并将所有项目移至左侧,而不删除它们。如果您将delete应用于所有后续对象,那么您将全部松开它们。

当然,您可以简单地移动数组而不删除arr[2],但这会导致内存泄漏。该物件不会被处置。

答案 3 :(得分:0)

您遇到的问题是删除了不应删除的指针。

在索引2处删除旧指针并将索引3分配给索引2后,您有两个指向同一对象的指针:在索引2和3处。删除指向的对象to by index 3删除两个指针指向的对象,使索引2中的指针无效。

问题的解决方案(除了切换到我推荐的std::vector之外)是删除索引2中的第一个对象,向下移动较高索引的值(例如array[2] = array[3])和将最后一个指针设置为nullptr。不再需要删除。

答案 4 :(得分:0)

最好的方法是使用链接列表。

请按照以下链接。

http://www.c4learn.com/data-structure/delete-node-from-first-postion-in-singly-linked-list/