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
这是因为您正在打印指针变量的地址,而不是指针。 从bitv
和ptr
中删除&符号。
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
有不同的值。
但是,正如您所期望的那样,当您更改代码时, ptr
和bitv
将具有相同的值。
为什么两个指针的地址有所不同
因为两个指针是两个不同的指针( – 变量 )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进行编译并启用优化, 则会获得相同的输出 ; 因为编译器内联了调用并且对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
顺便说一句,如果我使用gcc -fwhole-program -O2 -S -fverbose-asm
编译你的未修改源(没有static
)我得到与上面相同的汇编程序。 如果不添加static
并且不使用-fwhole-program
编译,则两个Adddress1
和Adddress1
保持不同。
两个运行输出
我运行antonis
可执行文件并在第一次运行:
/tmp$ ./antonis Address1 = 7ffe2b07c148 Address2 = 7ffe2b07c148
第二次:
/tmp$ ./antonis Address1 = 7ffc441851a8 Address2 = 7ffc441851a8
如果你想猜测为什么输出不同于一次运行到下一次运行,请考虑ASLR 。
顺便说一句,在C语言编码时,一个非常重要的概念是未定义的行为 (参见这个以及答案和我在那里给出的参考文献)。 你的问题中没有任何问题(这只是未指明的行为 ),但正如我的设计答案所示,你不应该期望在这种精确的情况下有特定的行为。
PS。 我相信(但我不完全确定)标准符合C的实现可以输出Address1= hello world
,同样也可以输出Address2
。 毕竟,带有%p
的printf
的行为是实现定义的。 肯定你可以得到0xdeadbeef
两者。 更严重的是,地址并不总是与size_t
或int
相同(具有相同的位宽),标准在
定义了intptr_t