malloc指针地址在main和其他函数的区别

时间:2017-11-05 14:37:35

标签: c pointers malloc memory-address

我有以下问题。为什么以下示例中的两个指针的地址存在差异?这是完整的代码:

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

void *mymalloc(size_t bytes){
void * ptr = malloc(bytes);
printf("Address1 = %zx\n",(size_t)&ptr);
return ptr;
}

void main (void)
{
unsigned char *bitv =  mymalloc(5);
printf("Address2 = %zx\n",(size_t)&bitv);
}

结果:

Address1 = 7ffe150307f0
Address2 = 7ffe15030810

4 个答案:

答案 0 :(得分:2)

这是因为您正在打印指针变量的地址,而不是指针。从printfs中的bitvptr移除&符号(&amp;)。

printf("Address1 = %zx\n",(size_t)ptr);

printf("Address2 = %zx\n",(size_t)bitv);

另外,使用%p作为指针(然后不要转换为size_t)

<强> WHY吗

在这行代码中:

 unsigned char *bitv =  mymalloc(5);

bitv是一个指针,它的值是新分配的内存块的地址。但是该地址也需要存储,&bitv是该值存储位置的地址。如果你有两个变量存储相同的指针,它们仍然会有自己的地址,这就是&ptr&bitv具有不同值的原因。

但是,正如您所料,ptrbitv在您更改代码时将具有相同的值。

答案 1 :(得分:1)

  

为什么两个指针的地址存在差异

因为两个指针是两个不同的指针( - 变量),每个指针都拥有地址

这两个指针(-variable)的携带实际上是相同的

通过更改:

来证明这打印了它们的价值(而不是它们的地址)
  printf("Address1 = %zx\n",(size_t)&ptr);

  printf("Address1 = %p\n", (void*) ptr);

  printf("Address2 = %zx\n",(size_t)&bitv);

  printf("Address2 = %p\n", (void*) bitv);

答案 2 :(得分:0)

在您的代码中,您曾使用以下代码打印指针的地址:

printf("%zx", (size_t)&p);

它没有打印指向的varbele的地址,它打印指针的地址。

您可以使用&#39;%p&#39;打印地址格式:

printf("%p", &n); // PRINTS ADDRESS OF 'n'

有一个解释打印地址的例子

int n;
int *v;

n = 54;
v = &n;

printf("%p", v); // PRINTS ADDRESS OF 'n' 
printf("%p", &v); // PRINTS ADDRESS OF pointer 'v'
printf("%p", &n); // PRINTS ADDRESS OF 'n'
printf("%d", *v); // PRINTS VALUE OF 'n'
printf("%d", n); // PRINTS VALUE OF 'n'

所以你的代码应该这样写:

void * get_mem(int size)
{
     void * buff = malloc(size); // allocation of memory
     // buff is pointing to result of malloc(size)
     if (!buff) return NULL; //when malloc returns NULL end function
     //else print address of pointer
     printf("ADDRESS->%p\n", buff);
     return buff;
}

int main(void)
{
    void * buff = get_mem(54);
    printf("ADDRESS->%p\n", buff);
    free(buff);
    return 0;
}

答案 3 :(得分:-2)

(除了其他答案,你会先阅读,可能应该对你有所帮助......)

阅读一本优秀的C编程书。指针和addresses很难解释,我甚至都没有尝试。因此,指针&ptr的地址通常与指针的值不同(但是,您可以编写ptr= &ptr;但您通常不希望这样做)...也请看解释virtual address space的图片。

然后阅读有关mallocmalloc(3) Linux手册页,此reference documentation等等的更多文档... Here快速,符合标准,但令人失望的{ {1}}。

另请阅读有关mallocprintf(3)手册页,printf reference等的文档...应该提及printf打印指针......

请注意,您不打印指针(请参阅Alk's answer),您甚至不打印automatic variable上的call stack的地址,打印一些演员表到%p(可能与指针的位宽不同,即使在我的Linux / x86-64上也是如此)。

还详细了解C dynamic memory allocationpointer aliasing

最后,阅读C11标准规范n1570

(我无法相信为什么你会期望两个输出是相同的;实际上如果编译器optimizing inlining size_t的调用可能会发生tail call } {a GCC

所以我没想到输出一般都是一样的。但是,mymalloc我得到了(通过对代码的微小修改)....

一个惊喜

但是,如果您将第一个gcc -O2 antonis.c -o antonis声明为void *mymalloc(size_t bytes)并在Linux / Debian / x86-64上使用ASLR 7进行编译且启用了优化,那么即可获得相同的输出;因为编译器内联了调用并使用了static void*mymalloc(size_t bytes)bitv相同的位置;这是生成的汇编程序代码ptr

gcc -S -O2 -fverbose-asm antonis.c

顺便说一句,如果我用 .section .rodata.str1.1,"aMS",@progbits,1 .LC0: .string "Address1 = %zx\n" .LC1: .string "Address2 = %zx\n" .section .text.startup,"ax",@progbits .p2align 4,,15 .globl main .type main, @function main: .LFB22: .cfi_startproc pushq %rbx # .cfi_def_cfa_offset 16 .cfi_offset 3, -16 # antonis.c:5: void * ptr = malloc(bytes); movl $5, %edi #, # antonis.c:11: { subq $16, %rsp #, .cfi_def_cfa_offset 32 # antonis.c:6: printf("Address1 = %zx\n",(size_t)&ptr); leaq 8(%rsp), %rbx #, tmp92 # antonis.c:5: void * ptr = malloc(bytes); call malloc@PLT # # antonis.c:6: printf("Address1 = %zx\n",(size_t)&ptr); leaq .LC0(%rip), %rdi #, # antonis.c:5: void * ptr = malloc(bytes); movq %rax, 8(%rsp) # tmp91, ptr # antonis.c:6: printf("Address1 = %zx\n",(size_t)&ptr); movq %rbx, %rsi # tmp92, xorl %eax, %eax # call printf@PLT # # antonis.c:13: printf("Address2 = %zx\n",(size_t)&bitv); leaq .LC1(%rip), %rdi #, movq %rbx, %rsi # tmp92, xorl %eax, %eax # call printf@PLT # # antonis.c:14: } addq $16, %rsp #, .cfi_def_cfa_offset 16 popq %rbx # .cfi_def_cfa_offset 8 ret .cfi_endproc .LFE22: .size main, .-main 编译你的未修改的源(没有static),我会得到与上面相同的汇编程序。 如果您未添加gcc -fwhole-program -O2 -S -fverbose-asm且未使用static进行编译,则-fwhole-programAdddress1会保持不同。

两个运行输出

我运行Address2可执行文件并第一次启用:

antonis

第二次:

/tmp$ ./antonis
Address1 = 7ffe2b07c148
Address2 = 7ffe2b07c148

如果您想猜测为什么输出与一次运行不同,请考虑undefined behavior

BTW,在C语言编码时非常重要的概念是this(请参阅thatunspecified behavior答案以及我在那里给出的参考文献)。你的问题中没有任何问题(只是intptr_t in <stdint.h>),但正如我的设计答案所示,你不应该期望在这种精确的情况下有特定的行为。

PS。我相信(但我不完全确定)符合标准的C实现可以为/tmp$ ./antonis Address1 = 7ffc441851a8 Address2 = 7ffc441851a8 输出Address1= hello world。毕竟,Address2printf的行为是实现定义的。当然,你可以得到%p。更严重的是,地址并不总是与0xdeadbeefsize_t相同(位宽相同),标准定义git config man page