我刚刚在这里看到了这段代码片段Q4,想知道我是否正确理解了这一点。
#include <stdio.h>
int main(void)
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int*)(&a + 1);
printf("%d %d\n", *(a + 1), *(ptr - 1));
return 0;
}
这是我的解释:
int a[5] = { 1, 2, 3, 4, 5 };
=>a
指向数组的第一个元素。换句话说:a
包含数组第一个元素的地址。
int *ptr = (int*)(&a + 1);
=>这&a
将是一个双指针,并指向整个数组。我将其可视化为:int b[1][5] = {1, 2, 3, 4, 5};
,这里b
指向2D数组的一行。&a + 1
应该指向内存中的下一个整数数组(不存在)[类似,b + 1
指向具有1行的2D数组的第二行(不存在)]。我们将其强制转换为int *
,因此这可能指向内存中下一个数组的第一个元素(不存在)。
*(a + 1)
=>这很容易。它只是指向数组的第二个元素。
*(ptr - 1)
=>这很棘手,我对此的解释可能有误。按ptr
原样int *
,这应该指向int之前的int ptr
。ptr
指向内存中不存在的第二个数组。因此,ptr-1应该指向第一个数组(a[4]
)的最后一个元素。
您的陈述本质上是正确的,您可能比大多数专业人士都更了解。但是,由于您正在寻求批评,所以答案很长。C语言中的数组和指针是不同的类型,这是C语言中最微妙的细节之一。我记得我最喜欢的一位教授曾经说过,后来编写该语言的人感到遗憾的是,这样做是如此的微妙,并且常常令人困惑。
在许多情况下,确实是一种类型的数组,并且可以用相同的方式对待类型的指针。它们的值都等于其地址,但是它们实际上是不同的类型。
当您获取数组的地址时&a
,就有一个指向数组的指针。当您说(a + 1)
有一个指向int的指针时,当您只是说a
有一个数组(而不是指针)时。a[1]
与*(a + 1)
type完全相同,实际上您可以键入,1[a]
并且与前两个完全相同。当您将数组传递给函数时,您实际上并没有传递数组,而是在传递指针void Fn(int b[])
,void Fn(int *b)
并且两者都是完全相同的函数签名,如果sizeof b
在函数中使用它们,则在两种情况下都将获得指针的大小。
指针算术很棘手,它总是偏移所指向的对象的大小(以字节为单位)。每当您使用运算符的地址时,您都将获得一个指向您应用于它的类型的指针。
因此,对于以上示例中发生的情况:
&a
是一个指向数组的指针,因此当您向其添加一个数组时,它会偏移该数组的大小(5 * sizeof(int))
。int*
为时,强制转换保留指针的值,但是现在其类型为指向int的指针,然后将其存储ptr
为类型为int的指针的变量。a
是一个数组,而不是一个指针。因此,当您说a + 1
要对数组而不是指针应用加法运算符时;并生成一个指针,该指针指向过去存储在数组中的类型的第一个元素int
。用取消引用*
将为您提供所指向的int。ptr
是一个指向int的指针,它指向数组末尾。(顺便说一句指向数组末尾是合法的,取消引用该指针是不合法的)从中减去1后,最后得到一个指向数组最后一个整数的指针,您可以取消引用。(您对可视化的解释int b[1][5] = {1, 2, 3, 4, 5};
是我之前从未听说过的,虽然我不能诚实地说这在技术上是否正确,但我会说这是工作原理,我认为这是一种很好的思考方式;我从现在起我很可能会这样做。)在C和C ++中,类型将变得非常棘手。最好的还在后头。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句