22

在 C 和 C++ 中,释放 NULL 指针将导致什么都不做。

尽管如此,我还是看到人们说如果您“释放内存两次”,可能会发生内存损坏。

这是真的?当您两次释放内存时,幕后发生了什么?

4

9 回答 9

24
int *p = malloc(sizeof(int));
//value of p is now lets say 0x12345678

*p = 2;
free(p); //memory pointer is freed, but still value of p is 0x12345678
         //now, if you free again, you get a crash or undefined behavior.

所以,在free第一次 ing 之后,你应该这样做p = NULL,所以如果(有机会)free(p)再次调用,什么都不会发生。

这就是为什么两次释放内存是未定义的:Why free crashing when called enough

于 2010-03-18T10:11:08.553 回答
19

释放内存不会将指针设置为空。指针仍然指向它曾经拥有的内存,但现在已将所有权转移回堆管理器。

堆管理器可能已经重新分配了你的过时指针指向的内存。

再次释放它与说 不一样free(NULL),并且会导致未定义的行为。

于 2010-03-18T10:12:05.290 回答
9

这是未定义的行为,可能导致堆损坏或其他严重后果。

free()对于空指针,只需检查内部的指针值并返回。该检查无助于两次释放块。

这就是通常发生的事情。堆实现获取地址并尝试通过修改自己的服务数据来“获取”该地址处的块的所有权。根据堆的实现,任何事情都可能发生。也许它可以工作并且没有任何反应,也许服务数据已损坏并且您遇到了堆损坏。

所以不要这样做。这是未定义的行为。任何不好的事情都可能发生。

于 2010-03-18T10:03:12.703 回答
4

是的,几乎总是导致崩溃的“未定义行为”。(虽然“未定义的行为”定义为“任何事情”,但各种类型的错误通常以完全可预测的方式表现。在 free() 的情况下,行为总是段错误或操作系统各自的“内存保护错误”特征。)

如果您 free() 指向除 NULL 或您 malloc'd 之外的任何其他内容的指针,则相同。

char x; char* p=&x; free(p); // 碰撞。

于 2010-03-18T10:05:03.367 回答
4

为了避免释放两次,我总是使用 MACRO 来释放内存:

#ifdef FREEIF
# undef FREEIF
#endif
#define FREEIF( _p )  \
if( _p )              \
{                     \
        free( _p );   \
        _p = NULL;    \
}

此宏设置 p = NULL 以避免悬空指针。

于 2010-03-18T12:43:15.073 回答
3

当您在指针上调用 free 时,您的指针不会被设置为 NULL。可用空间仅返回给池以再次分配。这里有一个例子来测试:

#include <stdio.h>
#include <stdlib.h>

int main(){
    int* ptr = (int*)malloc(sizeof(int));
    printf("Address before free: %p\n", ptr);
    free(ptr);
    printf("Address after free: %p\n", ptr);
    return 0;
}

该程序为我输出:

Address before free: 0x950a008
Address after free: 0x950a008

你可以看到,free 没有对指针做任何事情,只是告诉系统内存可以重用。

于 2010-03-18T10:20:37.720 回答
2

free() 释放 ptr 指向的内存空间,该内存空间必须由先前对 malloc()、calloc() 或 realloc() 的调用返回。否则,或者如果之前已经调用过 free(ptr),则会发生未定义的行为。如果 ptr 为 NULL,则不执行任何操作。

因此,您会得到未定义的行为,并且任何事情都可能发生。

于 2010-03-18T10:06:16.790 回答
1

1) 动态内存的处理不是由编译器完成的。有运行时库可以解决这个问题。例如。: glibc 提供了 malloc 和 free 等 API,它们在内部进行系统调用 (sys_brk) 来处理堆区域。

2) 两次释放相同的内存是指这样的情况:假设你有 char *cptr;

您使用以下方法分配内存: cptr = (char *) malloc (SIZE);

现在,当您不再需要此内存时,可以使用以下命令释放它:free(cptr);

现在这里发生的是 cptr 指向的内存可以免费使用。

假设在程序的稍后时间点您再次调用 free(cptr),那么这不是一个有效条件。这种两次释放相同内存的情况称为“两次释放内存”问题。

于 2010-03-18T10:11:34.047 回答
0

多次释放内存可能会产生不良后果。您可以运行这段代码来查看您的计算机可能发生的情况。

#include <stdio.h>      /* printf, scanf, NULL */
#include <stdlib.h>     /* malloc, free, rand */

int main ()


  {
  int i,n;
  char * buffer;

  printf ("How long do you want the string? ");
  scanf ("%d", &i);

  buffer = (char*) malloc (i+1);
  if (buffer==NULL) exit (1);

  for (n=0; n<i; n++)
          buffer[n]=rand()%26+'a';
  buffer[i]='\0';

  printf ("Random string: %s\n",buffer);
  free (buffer);
  free (buffer);

  return 0;
}

许多标准库(如 CSparse)使用处理内存问题的包装函数。我在这里复制了函数:

 /* wrapper for free */
    void *cs_free (void *p)
    {
        if (p) free (p) ;       /* free p if it is not already NULL */
        return (NULL) ;         /* return NULL to simplify the use of    

    }

这个函数可以处理内存问题。请注意,您必须注意 malloc 在某些情况下返回 NULL 的情况

于 2015-08-06T17:43:07.117 回答