103

背景:我正试图将我的头包裹在指针上,我们几周前在学校看到它们,今天在练习时我遇到了一个傻子?问题,这对您来说可能非常简单,但我几乎没有编程经验。

我在 SO 中看到了很多关于删除指针的问题,但它们似乎都与删除一个类而不是一个“简单”指针(或任何适当的术语)有关,这是我正在尝试的代码跑:

#include <iostream>;

using namespace std;

int main() {
  int myVar,
      *myPointer;

  myVar = 8;
  myPointer = &myVar;

  cout << "delete-ing pointers " << endl;
  cout << "Memory address: " << myPointer << endl;

  // Seems I can't *just* delete it, as it triggers an error 
  delete myPointer;
  cout << "myPointer: " << myPointer << endl;
  // Error: a.out(14399) malloc: *** error for object 0x7fff61e537f4:
  // pointer being freed was not allocated
  // *** set a breakpoint in malloc_error_break to debug
  // Abort trap: 6

  // Using the new keyword befor deleting it works, but
  // does it really frees up the space? 
  myPointer = new int;
  delete myPointer;
  cout << "myPointer: " << myPointer << endl;
  // myPointer continues to store a memory address.

  // Using NULL before deleting it, seems to work. 
  myPointer = NULL;
  delete myPointer;
  cout << "myPointer: " << myPointer << endl;
  // myPointer returns 0.

}

所以我的问题是:

  1. 为什么第一个案例不起作用?使用和删除指针似乎是最直接的用法?该错误表示未分配内存,但“cout”返回了一个地址。
  2. 在第二个示例中,错误没有被触发,但是对 myPointer 的值进行 cout仍然返回内存地址?
  3. #3真的有用吗?似乎对我有用,指针不再存储地址,这是删除指针的正确方法吗?

很抱歉这个问题很长,想让这个尽可能清楚,也重申一下,我没有什么编程经验,所以如果有人可以用外行的术语回答这个问题,将不胜感激!

4

6 回答 6

189

1 & 2

myVar = 8; //not dynamically allocated. Can't call delete on it.
myPointer = new int; //dynamically allocated, can call delete on it.

第一个变量是在堆栈上分配的。您只能在使用new运算符动态(在堆上)分配的内存上调用 delete。

3.

  myPointer = NULL;
  delete myPointer;

以上什么也没。您没有释放任何东西,因为指针指向 NULL。


不应执行以下操作:

myPointer = new int;
myPointer = NULL; //leaked memory, no pointer to above int
delete myPointer; //no point at all

您将其指向 NULL,留下泄漏的内存(您分配的新 int)。你应该释放你指向的内存。无法再访问分配new int的内存,因此内存泄漏。


正确的方法:

myPointer = new int;
delete myPointer; //freed memory
myPointer = NULL; //pointed dangling ptr to NULL

更好的方法:

如果您使用的是 C++,请不要使用原始指针。改用智能指针,它可以为您处理这些事情,而且开销很小。C++11 带有几个.

于 2012-11-04T22:06:52.383 回答
27

我相信你还没有完全理解指针是如何工作的。
当您有一个指向某个内存的指针时,您必须了解三件不同的事情:
- 指针(内存)“指向什么”
- 这个内存地址
- 并非所有指针都需要删除它们的内存:您只需需要删除动态分配的内存(使用的new运算符)。

想象:

int *ptr = new int; 
// ptr has the address of the memory.
// at this point, the actual memory doesn't have anything.
*ptr = 8;
// you're assigning the integer 8 into that memory.
delete ptr;
// you are only deleting the memory.
// at this point the pointer still has the same memory address (as you could
//   notice from your 2nd test) but what inside that memory is gone!

当你做了

ptr = NULL;
// you didn't delete the memory
// you're only saying that this pointer is now pointing to "nowhere".
// the memory that was pointed by this pointer is now lost.

C++ 允许您尝试指向delete一个指针,null但它实际上并没有做任何事情,只是没有给出任何错误。

于 2012-11-05T00:00:39.987 回答
13

指针类似于普通变量,因为您不需要删除它们。它们在函数执行结束和/或程序结束时从内存中删除。

但是,您可以使用指针来分配内存“块”,例如:

int *some_integers = new int[20000]

这将为 20000 个整数分配内存空间。很有用,因为堆栈的大小有限,您可能想在没有堆栈溢出错误的情况下处理大量“整数”。

每当您调用 new 时,您都应该在程序结束时“删除”,否则您会发生内存泄漏,并且某些分配的内存空间将永远不会返回给其他程序使用。去做这个:

delete [] some_integers;

希望有帮助。

于 2012-11-04T22:15:35.513 回答
8

C++ 中有一条规则,每一个new都有一个delete

  1. 为什么第一个案例不起作用?使用和删除指针似乎是最直接的用法?该错误表示未分配内存,但“cout”返回了一个地址。

new 永远不会被调用。所以 cout 打印的地址是 myVar 的内存位置的地址,或者在这种情况下分配给 myPointer 的值。通过写作:

myPointer = &myVar;

你说:

myPointer = myVar 中数据的存储地址

  1. 在第二个示例中,错误没有被触发,但是对 myPointer 的值进行 cout 仍然返回内存地址?

它返回一个地址,该地址指向已删除的内存位置。因为首先创建指针并将其值分配给 myPointer,然后删除它,然后打印它。因此,除非您为 myPointer 分配另一个值,否则删除的地址将保留。

  1. #3真的有用吗?似乎对我有用,指针不再存储地址,这是删除指针的正确方法吗?

NULL 等于 0,你删除 0,所以你什么也不删除。它打印 0 的逻辑是因为您这样做了:

myPointer = NULL;

这等于:

myPointer = 0;
于 2012-11-04T22:08:29.073 回答
4
  1. 您正在尝试删除分配在堆栈上的变量。你不可以做这个
  2. 删除指针实际上并不会破坏指针,只是将占用的内存返回给操作系统。您可以访问它,直到内存用于另一个变量或以其他方式操作。因此,最好在删除后将指针设置为 NULL (0)。
  3. 删除 NULL 指针不会删除任何内容。
于 2012-11-04T22:11:40.417 回答
2
int value, *ptr;

value = 8;
ptr = &value;
// ptr points to value, which lives on a stack frame.
// you are not responsible for managing its lifetime.

ptr = new int;
delete ptr;
// yes this is the normal way to manage the lifetime of
// dynamically allocated memory, you new'ed it, you delete it.

ptr = nullptr;
delete ptr;
// this is illogical, essentially you are saying delete nothing.
于 2012-11-04T22:15:46.150 回答