我有以下问题。为什么以下示例中的两个指针的地址存在差异?这是完整的代码:
#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
答案 0 :(得分:2)
这是因为您正在打印指针变量的地址,而不是指针。从printfs中的bitv
和ptr
移除&符号(&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
具有不同值的原因。
但是,正如您所料,ptr
和bitv
在您更改代码时将具有相同的值。
答案 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的图片。
然后阅读有关malloc
:malloc(3) Linux手册页,此reference documentation等等的更多文档... Here快速,符合标准,但令人失望的{ {1}}。
另请阅读有关malloc
:printf(3)手册页,printf
reference等的文档...应该提及printf
打印指针......
请注意,您不打印指针(请参阅Alk's answer),您甚至不打印automatic variable上的call stack的地址,打印一些演员表到%p
(可能与指针的位宽不同,即使在我的Linux / x86-64上也是如此)。
还详细了解C dynamic memory allocation和pointer 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-program
和Adddress1
会保持不同。
我运行Address2
可执行文件并第一次启用:
antonis
第二次:
/tmp$ ./antonis
Address1 = 7ffe2b07c148
Address2 = 7ffe2b07c148
如果您想猜测为什么输出与一次运行不同,请考虑undefined behavior。
BTW,在C语言编码时非常重要的概念是this(请参阅that和unspecified behavior答案以及我在那里给出的参考文献)。你的问题中没有任何问题(只是intptr_t
in <stdint.h>
),但正如我的设计答案所示,你不应该期望在这种精确的情况下有特定的行为。
PS。我相信(但我不完全确定)符合标准的C实现可以为/tmp$ ./antonis
Address1 = 7ffc441851a8
Address2 = 7ffc441851a8
输出Address1= hello world
。毕竟,Address2
与printf
的行为是实现定义的。当然,你可以得到%p
。更严重的是,地址并不总是与0xdeadbeef
或size_t
相同(位宽相同),标准定义git config
man page