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

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

#include  #include  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 

这是因为您正在打印指针变量的地址,而不是指针。 从bitvptr中删除&符号。

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

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

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

为什么?

在这行代码中:

  unsigned char *bitv = mymalloc(5); 

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

但是,正如您所期望的那样,当您更改代码时, ptrbitv将具有相同的值。

为什么两个指针的地址有所不同

因为两个指针是两个不同的指针( – 变量 )s,每个指针都有自己的地址

这两个指针( – 变量)s携带的值实际上是相同的

为了certificate这一点通过改变来打印它们的价值(而不是它们的地址):

  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); 

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

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

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

您可以使用’%p’格式打印地址:

 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; } 

(除了其他答案,你会先阅读,可能应该帮助你更多……)

阅读一本好的C编程书。 指针和地址很难解释,我甚至都没有尝试。 所以指针&ptr的地址通常与指针的值不一样(但是,你可以编写ptr= &ptr;但是你经常不想这样做)…还要看图片解释虚拟地址空间 。

然后阅读有关malloc : malloc(3) Linux手册页,此参考文档等的更多文档 …… 这里是快速,标准的符合,但令人失望的malloc实现。

另请阅读有关printf : printf(3)手册页, printf参考等的文档…应该提到%p用于打印指针…

请注意,您不打印指针(请参阅Alk的答案 ),您甚至不打印其地址( 调用堆栈上的自动变量 ),您打印一些强制转换为size_t (可能没有相同的位宽度)一个指针,即使在我的Linux / x86-64上也是如此)。

另请阅读有关C动态内存分配和指针别名的更多信息 。

最后,阅读C11标准规范n1570 。

(我无法相信为什么你会期望两个输出是相同的;实际上,如果编译器通过内联 尾部调用来优化对mymalloc的调用,则可能会发生这种情况)

所以我没想到输出总体上是一样的。 然而,使用gcc -O2 antonis.c -o antonis我得到了(对你的代码进行了微小的修改)….

惊喜

但是,如果将第一个void *mymalloc(size_t bytes)static void*mymalloc(size_t bytes)并在Linux / Debian / x86-64上使用GCC 7进行编译并启用优化, 则会获得相同的输出 ; 因为编译器内联了调用并且对bitvptr使用了相同的位置; 这是用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 

顺便说一句,如果我使用gcc -fwhole-program -O2 -S -fverbose-asm编译你的未修改源(没有static )我得到与上面相同的汇编程序。 如果不添加static并且不使用-fwhole-program编译,则两个Adddress1Adddress1保持不同。


两个运行输出

我运行antonis可执行文件并在第一次运行:

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

第二次:

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

如果你想猜测为什么输出不同于一次运行到下一次运行,请考虑ASLR 。

顺便说一句,在C语言编码时,一个非常重要的概念是未定义的行为 (参见这个以及答案和我在那里给出的参考文献)。 你的问题中没有任何问题(这只是未指明的行为 ),但正如我的设计答案所示,你不应该期望在这种精确的情况下有特定的行为。

PS。 我相信(但我不完全确定)标准符合C的实现可以输出Address1= hello world ,同样也可以输出Address2 。 毕竟,带有%pprintf的行为是实现定义的。 肯定你可以得到0xdeadbeef两者。 更严重的是,地址并不总是与size_tint相同(具有相同的位宽),标准在定义了intptr_t