打印malloc指针始终提供相同的地址

时间:2014-02-18 20:17:18

标签: c pointers malloc printf

我打错了吗?

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

int
main( void )
{
    int *       p = malloc(100000);
    int *       q;

    printf("%p\n%p\n", (void *)p, (void *)q);

    (void)getchar();            /* to run several instances at same time */

    free(p);
    return 0;
}

无论是顺序运行还是同时运行多个终端,它总是为p打印“0x60aa00000800”(q不同)。

编辑:感谢您的回答,我感到困惑的一个原因是因为每次都使用打印不同的地址。事实证明,我开始使用的新编译器选项-fsanitize=address导致了这种变化。糟糕。

4 个答案:

答案 0 :(得分:6)

q的值是未初始化的垃圾,因为您从未为其分配值。

每次运行程序时,p获得相同的地址就不足为奇了。该地址几乎肯定是虚拟地址,因此它仅适用于当前正在运行的程序(进程)的内存空间。

从一个程序看到的虚拟地址0x60aa00000800和从另一个程序看到的虚拟地址0x60aa00000800是不同的物理地址。操作系统将虚拟地址映射到物理地址,反之亦然,因此没有冲突。 (如果不同的程序可以读取和写入相同的物理内存,那将是一场安全噩梦。)

如果它们每次都不同,也就不足为奇了。例如,某些操作系统随机化堆栈地址以防止某些代码漏洞。我不确定堆地址是否也是随机的,但它们当然可以。

https://en.wikipedia.org/wiki/Virtual_memory

答案 1 :(得分:3)

这种行为并不奇怪。 malloc操作只是在进程中返回指向用户可寻址+已分配内存的指针。对于相同大小的第一个内存请求,通过进程的不同调用返回相同的地址是完全合理的

q的行为与此并不矛盾。你给了q没有值,因此它得到写入堆栈部分的最后一个值。毫不奇怪,未定义的行为会因同一进程的不同调用而有所不同(毕竟,它是未定义的)

答案 2 :(得分:2)

你的代码很好。

每次运行相同的代码,以及使用malloc()获取内存的相同算法,因此地址不应该是不同的。

  • 某些malloc实现可以随机化内存分配的开始,而不是。
  • 这是因为virtual memory。内存q的物理内存地址不同,但操作系统为每个进程提供内存虚拟视图,将不同的物理内存地址映射到进程中的相同虚拟地址。所以所有进程都有类似的内存视图(并且看不到其他进程的内存)

答案 3 :(得分:1)

每次运行程序时,堆分配器都不需要提供不同/唯一的地址。无论如何都不能保证这一点,但是malloc()的实现具有确定性行为并且每次运行程序时都给出相同的指针是完全合理的。

另一方面,堆栈通常(但不是必须)位于不同的地址。这是protection measure against buffer-overflow exploits。通过使堆栈位置不确定,它们使攻击者更难以通过缓冲区溢出攻击注入代码的直接内存地址。

最后请注意,程序中的所有指针都是虚拟内存地址,而不是物理地址。因此,即使两个并发进程在指针中可能具有相同的内存地址,这两个进程仍然在物理内存的不同区域中具有不同的内存。操作系统通过其虚拟内存管理器和页面转换来处理这个问题。每个进程都有自己的虚拟地址空间,操作系统根据需要将各个部分透明地映射到物理内存。