考虑以下C代码
int x=100;
int*addr=&x;
我知道addr会存储x的地址。一直在我的脑海中反复出现的问题是,addr指针将有其自己的地址,这可以再次使用&运算符访问,并且也将被存储在某个地方,因此我们在地址上有无限递归,那么这会在哪里结束呢?addr
的地址没有明确地“存储”在任何地方,它只是存在。如果您声明第二个变量并使用它来存储该地址,那么它肯定会占用空间:
int **addr2 = &addr;
int
和指针,并采用小端字节顺序,则您的情况可能如下所示:+----------+--+--+--+--+
| Address |Data bytes |
+----------+--+--+--+--+
|0x00000000|64|00|00|00|
+----------+--+--+--+--+
|0x00000004|00|00|00|00|
+----------+--+--+--+--+
100
(十进制下的100在十六进制下为0x64)。第二个四字节位置保存了值0x00000000,这是x
的地址。地址0x00000004没有存储在任何地方。+----------+--+--+--+--+
|0x00000008|04|00|00|00|
+----------+--+--+--+--+
addr2
,您可以看到它包含addr
的地址,即0x00000004。使用表达式*addr2
对addr2
进行解引用将产生地址0x00000004处的值,即带有类型int *
的0x00000000。再次解引用会得到该地址处的int
,即0x00000064。addr2
时,它会生成操作地址0x00000008等的指令。在实际代码中,这可能全部发生在堆栈上,但原理是相同的。int ** addr2 =&addr
。 - marczellmsizeof(T)
可以对每种指针类型T
进行评估,你不这么认为吗? - unwind如果您想要存储一个地址,自然需要有一个地方来存储它(即另一个地址),这样您可以一直进行下去。这将在您希望结束时精确结束。
int a = 1;
int *pa = &a;
int **ppa = &pa;
int ***pppa = &ppa;
int ****ppppa = &pppa;
...
这里有一个简单的比喻:假设你有一本有编号和行数的笔记本。假设你在第3页、第8行上做了个笔记,现在你想从其他地方引用它。也许你可以在第7页、第20行上写下一个“见第3页第8行的笔记”的引用。现在这个引用有了自己的“地址”,也就是第7页第20行。你也可以引用它 - 在第8页第1行上,你可以写下“见第7页第20行的笔记”。你可以无限延伸这个引用链。
&&a
。为什么呢?因为 &a
在存储之前没有地址。 - Claudiu您没有无限递归。每个变量都有它的地址,就这样。如果您定义一个变量等于另一个变量的地址,则该地址变量本身将被存储在某个地方,并且将具有一个地址。一个地址本身没有一个地址存储它的变量有。
概念上,只有在存储地址时才会为指针分配存储空间:
1)在您的情况下:int* addr=&x;
,addr
将占用sizeof(int*)
字节的内存。(但编译器保留不将指针存储在内存中的权利:它可能将其保留在CPU寄存器中)。
2)&x
没有显式分配任何存储空间。
3)&&x
、&&&x
等在语法上无效,因此您不需要担心潜在的递归问题。
&&
曾经是非法语法,这使得C++11可以采用它来表示r-value引用。
int x = 100;
int*addr = &x;
那么与变量 x
相关联的存储位置必须具有地址,因为它的地址被 取出来了。但是,与 addr
相关联的存储位置没有要求必须具有地址,因为它的地址从未被 取出来;因此,它可以被 寄存器化。它不是必须被寄存器化,但是可以这样做。
有意义吗?
/*
* show that a variable allocated on the heap sticks around, while a
* variable allocated on the stack vanishes after its enclosing
* function returns. Holding a pointer to the latter can lead to
* unexpected results.
*/
#include <stdio.h>
int heapvar = 20;
int *get_heapvar_ptr() {
return &heapvar;
}
int *get_stackvar_ptr() {
int stackvar = 30;
return &stackvar;
}
int main() {
int *heap_ptr = get_heapvar_ptr();
int *stack_ptr = get_stackvar_ptr();
/* should print value = 20 */
printf("heapvar address = %#x, heapvar value = %d\n", heap_ptr, *heap_ptr);
/* you might expect this to print value = 30, but it (probably) doesn't */
printf("stackvar address = %#x, stackvar value = %d\n", stack_ptr, *stack_ptr);
}
heapvar address = 0x22a8018, heapvar value = 20
stackvar address = 0x5d957fac, stackvar value = 0
当然,地址指针将有其自己的地址,但除非您专门访问它所持有的地址,否则它不会被使用,因此对于这个没有递归...
ptr and X are two houses.
//lets say &X is a sheet of paper containing the address of house X. I am going to keep this address in the house ptr. So the address of X is stored in ptr.
ptr = &X;
//Now what about ptr. Only if I need to know the address, I need to write the address in some paper and store it again in some other house. Else I am happy to know the house exits.
int**************************
。另外,除非你创建指针,否则地址不会被存储在任何地方。 - StoryTeller - Unslander Monica*
时,它就结束了。可以这样想,所有像int *
、int **
等的类型在编译时都是已知的。如果有一个实现定义的间接限制,您将在编译时得知,因此从循环或递归函数调用的角度来看,它并不是无限的。 - Brandin