其他答案是正确的,但是它们都没有强调这三个概念可能包含相同的值,因此它们在某种程度上是不完整的。
从其他答案中无法理解这一点的原因是,尽管所有插图在大多数情况下都是有用且绝对合理的,但它们并未涵盖指针x
指向自身的情况。
这很容易构造,但是显然有点难以理解。在下面的程序中,我们将看到如何强制所有三个值都相同。
注意:该程序中的行为是未定义的,但是我将其纯粹是作为指针可以执行但不应这样做的有趣演示。
#include <stdio.h>
int main () {
int *(*x)[5];
x = (int *(*)[5]) &x;
printf("%p\n", x[0]);
printf("%p\n", x[0][0]);
printf("%p\n", x[0][0][0]);
}
C89和C99都将在没有警告的情况下进行编译,并且输出如下:
$ ./ptrs
0xbfd9198c
0xbfd9198c
0xbfd9198c
有趣的是,所有三个值都是相同的。但这并不奇怪!首先,让我们分解程序。
我们将其声明x
为指向5个元素的数组的指针,其中每个元素的类型均为指向int的指针。该声明在运行时堆栈上分配4个字节(或更多取决于您的实现;在我的机器上,指针是4个字节),因此x
是指实际的内存位置。在C语言家族中,的内容x
仅仅是垃圾,是该位置以前使用时遗留下来的东西,因此x
它本身不会指向任何地方-一定不会指向已分配的空间。
因此,自然地,我们可以获取变量的地址x
并将其放在某个位置,这正是我们要做的。但是我们将继续将其放入x本身。由于&x
类型不同于x
,我们需要进行强制转换,因此我们不会收到警告。
内存模型如下所示:
0xbfd9198c
+------------+
| 0xbfd9198c |
+------------+
因此,该地址处的4字节内存块0xbfd9198c
包含对应于十六进制值的位模式0xbfd9198c
。很简单。
接下来,我们打印出三个值。其他答案解释了每个表达式所指的含义,因此现在应该清楚这种关系。
我们可以看到值是相同的,但是只是在非常低的意义上……它们的位模式是相同的,但是与每个表达式关联的类型数据意味着它们的解释值是不同的。例如,如果我们x[0][0][0]
使用格式字符串打印出来%d
,我们将得到一个巨大的负数,因此“值”实际上是不同的,但是位模式是相同的。
这实际上非常简单...在图中,箭头仅指向相同的内存地址,而不是指向不同的地址。但是,尽管我们能够从未定义的行为中强制获得预期的结果,但这仅仅是未定义的。这不是生产代码,只是为了完整起见进行演示。
在合理的情况下,您将使用malloc
创建5个int指针的数组,并再次创建该数组中指向的int。malloc
总是返回一个唯一的地址(除非您内存不足,在这种情况下它将返回NULL或0),因此您不必担心像这样的自引用指针。
希望这是您要寻找的完整答案。您不应期望x[0]
,x[0][0]
和x[0][0][0]
相等,但是如果被迫,它们可能会相等。如果有什么事发生,请告诉我,以便我澄清!
x[0]
,x[0][0]
并且x[0][0][0]
具有不同的类型。它们无法比较。你是什么意思!=
?