为什么在释放指针后取消引用指针会得到不同的结果? [英] Why do I get different results when I dereference a pointer after freeing it?

查看:18
本文介绍了为什么在释放指针后取消引用指针会得到不同的结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于 C 中内存管理的问题(以及 Debian GNU/Linux 下的 GCC 4.3.3).

I've a question about the memory management in C (and GCC 4.3.3 under Debian GNU/Linux).

根据 K&R 的 C Programming Language Book(第 7.8.5 章),当我释放一个指针然后取消引用它时,是一个错误.但是我有一些疑问,因为我注意到有时,就像我在下面粘贴的源代码中那样,编译器 (?) 似乎根据明确定义的原则工作.

According to the C Programming Language Book by K&R, (chap. 7.8.5), when I free a pointer and then dereference it, is an error. But I've some doubts since I've noted that sometimes, as in the source I've pasted below, the compiler (?) seems to work according a well-defined principle.

我有一个像这样的简单程序,它展示了如何返回动态分配的数组:

I've a trivial program like this, that shows how to return an array dynamically allocated:

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


int * ret_array(int n)
{
    int * arr = (int *) malloc(10 * sizeof(int));
    int i;
    for (i = 0; i < n; i++)
    {
        arr[i] = i*2;
    }
    printf("Address pointer in ret_array: %p
", (void *) arr);
    return arr;
}

int * ret_oth_array(int n)
{
    int * arr = (int *) malloc(10 * sizeof(int));
    int i;
    for (i = 0; i < n; i++)
    {
        arr[i] = i+n;
    }
    printf("Address pointer in ret_oth_array: %p
", (void *) arr);
    return arr;
}

int main(void)
{
    int *p = NULL;
    int *x = NULL;
    p = ret_array(5);
    x = ret_oth_array(6);

    printf("Address contained in p: %p
Value of *p: %d
", (void *) p, *p);

    free(x);
    free(p);
    printf("Memory freed.
");
    printf("*(p+4) = %d
", *(p+4));
    printf("*x = %d
", *x);

    return 0;
}

如果我尝试使用一些参数编译它:-ansi -Wall -pedantic-errors,它不会引发错误或警告.不仅;它也运行良好.

If I try to compile it with some arguments: -ansi -Wall -pedantic-errors, it doesn't raises errors or warning. Not only; it also runs fine.

Address pointer in ret_array: 0x8269008
Address pointer in ret_oth_array: 0x8269038
Address contained in p: 0x8269008
Value of *p: 0
Memory freed.
*p+4 = 8
*x = 0

*(p+4) 是 8,*x 是 0.为什么会发生这种情况?如果 *(p+4) 是 8,那么 *x 不应该是 6,因为 x 数组的第一个元素是 6?

*(p+4) is 8 and *x is 0. Why does this happen? If *(p+4) is 8, shouldn't *x be 6, since the first element of the x-array is 6?

如果我尝试将调用顺序更改为 free,则会发生另一件奇怪的事情.例如:

Another strange thing happens if I try to change the order of the calls to free. E.g.:

int main(int argc, char * argv[])
{
/* ... code ... */

    free(p);
    free(x);

    printf("Memory freed.
");
    printf("*(p+4) = %d
", *(p+4));
    printf("*x = %d
", *x);

    return 0;
}

事实上,在这种情况下,输出(在我的机器上)将是:

In fact in this case the output (on my machine) will be:

*p+4 = 8
*x = 142106624

为什么 x 指针真的被释放"了,而 p 指针被不同地"释放了(我希望)?好的,我知道在释放内存后我应该将指针指向 NULL,但我只是好奇:P

Why does the x pointer is really "freed", while the p pointer is freed (I hope) "differently"? Ok, I know that after freeing memory I should make the pointers to point to NULL, but I was just curious :P

推荐答案

free()(和 malloc())不是来自 gcc.它们来自 C 库,在 Debian 上通常是 glibc.所以,您看到的是 glibc 的行为,而不是 gcc 的行为(并且会随着不同的 C 库或不同版本的 C 库而改变).

free() (and malloc()) are not from gcc. They come from the C library, which on Debian is usually glibc. So, what you are seeing is glibc's behavior, not gcc's (and would change with a different C library, or a different version of the C library).

我特别指出,在您使用 free() 之后,您正在释放 malloc() 给您的内存块.它不再是你的了.由于不应再使用它,glibc 中的内存管理器可以自由地对内存块做任何它想做的事情,包括使用它的一部分作为它自己的内存结构(这可能是你看到它的内容发生变化的原因;它们已被簿记信息覆盖,可能是指向其他块或某种计数器的指针).

I particular, after you use free() you are releasing the memory block malloc() gave you. It's not yours anymore. Since it is not supposed to be used anymore, the memory manager within glibc is free to do whatever it wants with the memory block, including using parts of it as its own memory structures (which is probably why you are seeing its contents change; they have been overwritten with bookkeeping information, probaly pointers to other blocks or counters of some sort).

还有其他可能发生的事情;特别是,如果您分配的大小足够大,glibc 可以向内核请求一个单独的内存块(使用 mmap() 或类似的调用),然后将其释放回free() 期间的内核.在这种情况下,您的程序会崩溃.这在理论上也可能发生在某些情况下,即使分配很小(glibc 可以增加/缩小堆).

There are other things that can happen; in particular, if the size of your allocation was large enough, glibc can ask the kernel for a separate memory block for it (with mmap() or similar calls), and release it back to the kernel during the free(). In that case, your program would crash. This can in theory also happen in some circunstances even with small allocations (glibc can grow/shrink the heap).

这篇关于为什么在释放指针后取消引用指针会得到不同的结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆