【问题标题】:C++ Pointers and Dynamic Arrays and Delete OperatorC++ 指针和动态数组以及删除运算符
【发布时间】:2016-10-20 11:19:24
【问题描述】:

好的,我将列出两个程序。两者都是使用指针和 new 运算符的动态数组。但似乎不喜欢删除运算符。

#include <iostream>
int main()
{
  int *p;
  p = new int[5];

  for (int i = 0; i < 5; i++)
  {
    p[i] = 25 + (i * 10);
    std::cout << p[i] << " ";
  }
  std::cout << std::endl;

  delete [] p;
  p = NULL;

  return 0;
}

这是第一个程序。它喜欢删除操作符就好了。现在不喜欢删除操作符的程序:

#include <iostream>
int main()
{
  int x;
  int *p;
  p = new int[5];

  *p = 4;

  for (int i = 0; i < 5; i++)
  {
    std::cout << *p << " ";
    x = *p;
    p++;
    *p = x + 1;
  }
  std::cout << std::endl;

  delete [] p;
  p = NULL;

  return 0;
}

这个程序编译得很好。但是在执行过程中,它会抛出一个错误 - free(): invalid pointer: 0xfdb038 .. 或任何用于该特定执行的内存地址。所以,问题是: 为什么第二种情况不能使用delete操作符? 我不想有内存泄漏;我不希望指针悬空。 如果我只是说p = NULL;,那么p = 0,但我相信指针仍然悬空?,但我不确定。提前致谢。

【问题讨论】:

  • 因为在第二种情况下,您更改了p 指针并且它没有指向删除之前开始的数组。

标签: c++ pointers dynamic-arrays delete-operator


【解决方案1】:

看第二段代码中的这个循环:

for (int i = 0; i < 5; i++)
{
  std::cout << *p << " ";
  x = *p;
  p++;
  *p = x + 1;   // <--- Here
}

请注意,在这一行中,您写入了p 当前指向的内存地址。由于您总是递增p 然后写入它,因此您最终会注销您为p 分配的区域的末尾。 (如果我们将pOrig 想象为指向p 最初指向的位置的指针,那么它会写入pOrig[1]pOrig[2]pOrig[3]pOrig[4]pOrig[5],并且最后一次写入是通过区域的尽头)。这会导致未定义的行为,这意味着实际上任何事情都可能发生。这是个坏消息。

此外,delete[] 假定您传入一个指向您分配的数组的第一个元素的指针。由于您在该循环中已将 p 增加了很多次,因此您试图 delete[] 一个不在分配数组基数的指针,因此出现了问题。

要解决此问题,请不要在增加 p 后写入它,并存储指向使用 new[] 分配的原始数组的指针,以便您可以释放它而不是修改后的指针 p

【讨论】:

    【解决方案2】:

    你必须delete 你从new 得到的指针。但是,在您的第二个代码中,您执行了 p++ 更改了指针。因此,您尝试 delete 一个您没有从 newdelete 获得的指针崩溃。

    要修复此类错误,切勿使用new。而是使用std::vector&lt;int&gt; p;。因为你永远不需要new,所以你不能忘记delete

    【讨论】:

    • @EdgarRokyan 这有什么奇怪的?您会注意到在现代 C++ 中找不到手动内存管理。没有必要让自己接受这种容易出错、过时且不必要的做法。
    • @EdgarRokyan 实际上现代 C++ 中有一种趋势是避免显式的 newdelete 运算符。例如,将make_sharedmake_unique 与智能指针类型结合使用。
    • @templatetypedef 我的意思是你不能避免显式地使用 new/delete 因为许多 C 库,例如,它们处理数组和原始指针。因此,学习如何适当地使用 new/delete 而不是忽略它们要好得多。在这种情况下,“从不使用新的”这句话对我来说看起来很奇怪。除了上述建议并没有直接回答问题。
    • @EdgarRokyan C 不使用newdelete,因此您永远需要 newdelete 使用C 库。您只需使用 std::vector 并将指向数据的指针传递给 C 库。第一段直接回答了这个问题,第二段是笼统的,我不明白它是怎么不回答的。
    • @templatetypedef 如果 C 库需要预先分配的缓冲区来填充怎么办?您是否声称创建向量并使用指向其缓冲区的指针而不是简单地使用 new 和 delete 更好?
    【解决方案3】:

    问题正在将p 更改为p++。 您应该始终存储(删除)原始指针。像这样:

    #include <iostream>
    int main()
    {
      int *original = new int[5];
      int *p = original;
    
      for (int i = 0; i < 5; i++)
      {
        std::cout << *p << " ";
        int x = *p;
        p++;
        *p = x + 1;
      }
      std::cout << std::endl;
    
      delete [] original;    
      return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2016-11-02
      • 2012-05-21
      • 1970-01-01
      • 2012-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-18
      相关资源
      最近更新 更多