C语言中如何检查指针是否已被释放?

发布于 2024-12-18 08:22:06 字数 38 浏览 3 评论 0原文

我想检查指针是否已释放。如何使用 gnu 编译器集执行此操作?

I would like to check if a pointer is freed already or not. How do I do this using gnu compiler set?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

北座城市 2024-12-25 08:22:06

你不能。跟踪此问题的方法是在释放指针后将其分配给 0NULL 。然而,正如 Fred Larson 提到的,这对指向同一位置的其他指针没有任何作用。

int* ptr = (int*)malloc(sizeof(int));
free(ptr);
ptr = NULL;

You can't. The way to track this would be to assign the pointer to 0 or NULL after freeing it. However as Fred Larson mentioned, this does nothing to other pointers pointing to the same location.

int* ptr = (int*)malloc(sizeof(int));
free(ptr);
ptr = NULL;
梦明 2024-12-25 08:22:06

你不能。只需在释放之后为其分配NULL即可,以确保不会释放它两次(free(NULL)也可以)。

更好的是,如果可能的话,不要在“忘记”已释放代码的地方编写代码。

编辑

将问题解释为如何查明指针指向的内存是否已释放:你做不到。你必须自己记账。

You can't. Just assign NULL to it after you free it to make sure you don't free it twice (it's ok to free(NULL)).

Better yet, if possible don't write code where you "forget" you already freed it.

EDIT

Interpreting the question as how to find out whether the memory pointed to by a pointer is freed already: you can't do it. You have to do your own bookkeeping.

倾城花音 2024-12-25 08:22:06

没有可靠的方法来判断指针是否已被释放,正如 Greg 评论的那样,释放的内存可能被其他不相关的数据占用,并且您将得到错误的结果。

事实上,没有标准方法来检查指针是否被释放。 也就是说glibc 确实有函数(mcheckmprobe)来查找 指针的 malloc 状态 < a href="http://www.gnu.org/s/hello/manual/libc/Heap-Consistency-Checking.html#Heap-Consistency-Checking" rel="noreferrer">堆一致性检查,其中之一是查看指针是否被释放。

但是,这些函数主要仅用于调试,并且它们不是线程的安全如果您不确定要求,请避免使用这些函数。只需确保您已配对 malloc/free 即可。


示例 http://ideone.com/MDJkj

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

void no_op(enum mcheck_status status) {}

int main()
{
    mcheck(&no_op);

    void* f = malloc(4);

    printf("%d (should be %d)\n", mprobe(f), MCHECK_OK);
    printf("%d (should be %d)\n", mprobe(f), MCHECK_OK);

    free(f);

    printf("%d (should be %d)\n", mprobe(f), MCHECK_FREE);
    printf("%d (should be %d)\n", mprobe(f), MCHECK_FREE);

    return 0;
}

There is no reliable way to tell if a pointer has been freed, as Greg commented, the freed memory could be occupied by other irrelevant data and you'll get wrong result.

And indeed there is no standard way to check if a pointer is freed. That said, glibc does have functions (mcheck, mprobe) to find the malloc status of a pointer for heap consistency checking, and one of them is to see if a pointer is freed.

However, these functions are mainly used for debugging only, and they are not thread-safe. If you are not sure of the requirement, avoid these functions. Just make sure you have paired malloc/free.


Example http://ideone.com/MDJkj:

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

void no_op(enum mcheck_status status) {}

int main()
{
    mcheck(&no_op);

    void* f = malloc(4);

    printf("%d (should be %d)\n", mprobe(f), MCHECK_OK);
    printf("%d (should be %d)\n", mprobe(f), MCHECK_OK);

    free(f);

    printf("%d (should be %d)\n", mprobe(f), MCHECK_FREE);
    printf("%d (should be %d)\n", mprobe(f), MCHECK_FREE);

    return 0;
}
ˇ宁静的妩媚 2024-12-25 08:22:06

您可以通过编写一个为您执行此操作的宏来扩展将 NULL 分配给指针值的概念。例如:

#define FREE(ptr) do{ \
    free((ptr));      \
    (ptr) = NULL;     \
  }while(0)

那么只要您确保您的代码仅使用 FREE() 而不是 free(),您就可以相当确信您编写的代码不会两次释放相同的内存。当然,这并不能阻止多次调用释放内存的库函数。它并不能保证每个 malloc 都有一个空闲空间。

您可以使用函数尝试此操作,但它会变得很尴尬,因为您必须引入引用运算符,并且它看起来不再像对 free() 的正常调用。

You can extend the concept of assigning NULL to the pointer value by writing a macro that does it for you. For example:

#define FREE(ptr) do{ \
    free((ptr));      \
    (ptr) = NULL;     \
  }while(0)

Then as long as you make sure your code only uses FREE() and not free(), you can be fairly confident that code you wrote doesn't free the same memory twice. Of course that does nothing to prevent multiple calls into library functions that free memory. And it does nothing to guarantee that there's a free for every malloc.

You can attempt this with a function, but it gets akward because you have to throw in a reference operator and it doesn't look like a normal call to free() anymore.

峩卟喜欢 2024-12-25 08:22:06

你不这样做,因为你不能。

跟踪从 malloc() 获取的指针,并且仅释放它们,并且仅释放一次。

如果你愿意的话,内存没有内存,所以它不知道它是否被分配。只有操作系统的内存管理器可以告诉您这一点(但 C 不包含任何标准化机制来查询此信息)。

You do not, since you cannot.

Keep track of pointers that you obtain from malloc() and only free those, and only once.

If you will, memory has no memory, so it doesn't know whether it is allocated or not. Only your OS's memory manager can tell you that (but C does not include any standardized mechanism to query this information).

赢得她心 2024-12-25 08:22:06

我知道这个答案有点晚了,但我刚刚阅读了这个答案并写道一些代码
验证以下内容:

Free会将内存块放入它自己的空闲块列表中。通常它还会尝试将地址空间中的相邻块融合在一起。空闲块列表只是内存块的循环列表,其中当然在开始时有一些管理数据。
free-list也是第一个位置,malloc在需要时寻找新的内存块。 在从操作系统调用新内存之前对其进行扫描。当发现一个块比所需的内存大时,它就被分成两部分。一个返回给调用者,另一个放回空闲列表。

此代码仅检查分配的第一个指针是否已释放:

int is_freed(void *p)
{
    void * q;
    char p_addr [50];
    char q_addr [50];

    sprintf(p_addr, "%p", p);

    q = malloc (1);
    sprintf(q_addr, "%p", q);
    free (q);

    return ! strcmp(q_addr, p_addr);
}

我已在 HP-UX 和 Linux Redhat 上测试了此代码,并且对于只有一个指针的情况,它可以工作。

I know that this answer is a little bit late, but I just read this answer and wrote some code to
verify the following:

Free will put the memory block in its own free block list. Normally it also tries to meld together adjacent blocks in the address space. The free block list is just a circular list of memory chunks which have of course some admin data in the beginning.
The free-list is also the first location, malloc looks for a new chunk of memory when needed. It is scanned before it calls for new memory from the OS. When a chunk is found that is bigger then the needed memory, it is just divided into two parts. One is returned to caller, the other is put back into the free list.

This code checks only if the first pointer that was allocated is freed:

int is_freed(void *p)
{
    void * q;
    char p_addr [50];
    char q_addr [50];

    sprintf(p_addr, "%p", p);

    q = malloc (1);
    sprintf(q_addr, "%p", q);
    free (q);

    return ! strcmp(q_addr, p_addr);
}

I've tested this code on HP-UX and Linux Redhat and it works, for the case of only one pointer.

北凤男飞 2024-12-25 08:22:06

友情提示:如果您在另一个函数中将指针参数设置为NULL,并且希望影响参数(传入的原始指针),则该函数必须接受指向该指针的指针(double ptr)。

例如,

void cleanup(int *int_ptr) {
  free(int_ptr);
  int_ptr = NULL; // Not working ??
}

int main() {
  int a = 8; 
  int* a_ptr = &a;
  cleanup(a_ptr);
  printf("%p", a_ptr); // Unexpected: Does not print NULL
}

这不会按预期工作。基本原理:a_ptr 是一个指针,但它实际上只是一个包含值的变量 - 包含的值有点特殊,因为它是虚拟内存地址,但它仍然是一个值。当此值传递到 cleanup 时,与任何其他变量一样,cleanup 会创建该值的本地副本。因此,如果 a_ptr 的值为 0x7ffd86656848,则 int_ptr 也将具有值 0x7ffd86656848。将int_ptr设置为NULL当然不会将a_ptr设置为NULL

因此,如果您希望设置int_ptr = NULL,则必须传入双指针

void cleanup(int **int_ptr) {
  free(*int_ptr);
  *int_ptr = NULL;
}

A friendly note: If you are setting a pointer parameter to NULL in another function and wish to have that affect the argument (original pointer passed in), the function would have to accept a pointer to that poiner (double ptr).

For example,

void cleanup(int *int_ptr) {
  free(int_ptr);
  int_ptr = NULL; // Not working ??
}

int main() {
  int a = 8; 
  int* a_ptr = &a;
  cleanup(a_ptr);
  printf("%p", a_ptr); // Unexpected: Does not print NULL
}

This doesn't work as expected. Rationale: a_ptr is a pointer, but it's really just a variable containing a value — the contained value is a little special because it is a virtual memory address, but it's a value nonetheless. When this value gets passed into cleanup, like any other variables, cleanup creates a local copy of that value. So, if a_ptr has value 0x7ffd86656848, int_ptr will also have value 0x7ffd86656848. Setting int_ptr to NULL of course does not set a_ptr to NULL.

So, if you wish to set int_ptr = NULL, you would have to pass in a double pointer.

void cleanup(int **int_ptr) {
  free(*int_ptr);
  *int_ptr = NULL;
}
向地狱狂奔 2024-12-25 08:22:06

编写一个函数来捕获信号 SIGABRT

Write a function to catch signal SIGABRT

Smile简单爱 2024-12-25 08:22:06

这就是我的做法:

bool pointer_allocated(void* ptr) {
  return ptr != NULL;
}

编辑:这个答案是非常错误的,所以我会纠正它

如果你想检查指针是否被解除分配,你可以释放指针后将其设置为 NULL。

free(ptr);
ptr = NULL;

// You can use ptr != NULL or ptr != 0, its pretty much the same thing
if(ptr) {
    // Pointer is set
} else {
    // Pointer has been freed
}

如果您不打算再次使用该指针,则无需将指针设置为 NULL。在这种情况下,没有任何意义,只会浪费 CPU 时间。

This is how I do it:

bool pointer_allocated(void* ptr) {
  return ptr != NULL;
}

EDIT: This answer is very wrong, so I will correct it

If you want to check if the pointer is de-allocated, you can just set the pointer to NULL after freeing it.

free(ptr);
ptr = NULL;

// You can use ptr != NULL or ptr != 0, its pretty much the same thing
if(ptr) {
    // Pointer is set
} else {
    // Pointer has been freed
}

If you aren't going to use the pointer again, you don't need to set the pointer to NULL. In that case there's no point and it just wastes CPU time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文