请考虑C中的以下代码
int x=100;
int*addr=&x;
Run Code Online (Sandbox Code Playgroud)
我知道addr会存储xA问题的地址,这个问题一直在我脑海中浮现,因为addr指针将有自己的地址,并且可以再次使用&符号运算符进行访问,并且它也会存储在某处,所以我们在这里有无限递归在地址上这样结束了吗?
unw*_*ind 26
地址addr不是明确地"存储"在任何地方,它只是.如果您要声明第二个变量并使用它来存储该地址,那么确保它占用空间:
int **addr2 = &addr;
Run Code Online (Sandbox Code Playgroud)
你可以把记忆想象成一系列的盒子.假设4字节int和指针以及little-endian字节顺序,您的方案可能如下所示:
+----------+--+--+--+--+
| Address |Data bytes |
+----------+--+--+--+--+
|0x00000000|64|00|00|00|
+----------+--+--+--+--+
|0x00000004|00|00|00|00|
+----------+--+--+--+--+
Run Code Online (Sandbox Code Playgroud)
地址显示在左侧,包含在右侧该位置的字节.您可以看到100存储在前四个字节中的值(十进制100是十六进制的0x64).第二个4字节位置保存值0x00000000,这是地址x.地址0x00000004不存储在任何地方.
现在,如果我们添加第二个指针,我们将使用更多内存:
+----------+--+--+--+--+
|0x00000008|04|00|00|00|
+----------+--+--+--+--+
Run Code Online (Sandbox Code Playgroud)
这将是用于表示addr2指针的内存,您可以看到它包含地址addr,即0x00000004.
addr2使用表达式取消引用*addr2将产生地址0x00000004处的值,即具有类型的0x00000000 int *.再次取消引用会产生该int地址,即0x00000064.
由于这个内存布局是由编译器选择的,它"知道"所涉及的地址,并且可以替代,以便在代码引用时addr2,它生成操作地址0x00000008的指令,依此类推.在实际代码中,这可能都发生在堆栈上,但原理是相同的.
最后说明:请注意@Phil Perry的建议; 上面的内容简化并使ocncrete成为许多有点抽象的东西.这就是它在许多当前架构中的实际工作方式,但C中并没有保证所提到的许多内容,所以你不能真正依赖它们来保持真实.我的意思是上面的例子(希望)使概念略微模糊.
das*_*ght 14
如果您存储地址,当然,您需要一些地方来存储它(即另一个地址),因此您可以根据需要继续这样做.当你希望它结束时,这就结束了.
int a = 1;
int *pa = &a;
int **ppa = &pa;
int ***pppa = &ppa;
int ****ppppa = &pppa;
...
Run Code Online (Sandbox Code Playgroud)
这是一个简单的比喻:假设你有一个带有编号页面和线条的笔记本.假设您在第3页第8行做了注释,然后想要从其他地方引用该注释.也许你可以在第7页第20行写一篇参考文献"见第3页第8行注释".现在引用有自己的"地址" - 即第7页第20行.您也可以引用它 - 在第8页第1行,您可以写"请参阅第7页第20行注释".您可以根据需要继续使用此链接引用.
C实现了所谓的冯·诺依曼机器.您可以在其他类型的计算机上编译C,如果您可以使计算机执行冯诺依曼机器的操作.
那么,什么是冯诺依曼机器?对于BBC道歉,大多数人都认为内存中的程序具有严格而独特的代码和数据概念,但实际上 - 从统一的冯·诺伊曼的角度来看 - 程序的内存空间更像是一个摇摆不定的大球,数字- 笨蛋...... 东西.您可以像访问数据一样访问甚至更改数据,也可以像代码一样运行它.但如果你不确定它是否正常工作,后者不是一个好主意,这是人们不再经常使用汇编的原因之一.高级编程语言仔细地将数字组织成(理想情况下)工作的东西:它们在这方面并不完美,而C在设计上并不像大多数人那样完美.但他们通常会完成工作.
现在,这与你的问题有什么关系?正如你所说,每个变量都必须有一个地址,而C必须知道这些地址是什么才能使用它们.确切的实现细节可能因编译器而异,有时在编译器中的不同设置上也有所不同,但在某些情况下,程序在达到机器代码级别时甚至不再知道变量名称.地址都是剩下的,它们实际上是被使用的.
这些地址由编译器决定.最终,它们成为代码本身的一部分.它们保存在您通常不应访问的区域,但如果您真的需要,则可以.这些区域基本上是递归停止的地方.
你没有无限递归.每个变量都有它的地址,就是这样.现在,如果你定义一个等于另一个变量的地址的变量,那么地址变量本身将存储在某个地方,并且会有一个地址.地址本身没有存储它的变量的地址.