那这样p和*p记录的地址不一样了吗?
不,p
和 *p
记录的地址在某种意义上是“相同”的,但它们在类型和使用方式上有所不同。
-
p
的地址:p
是一个指针,它本身存储了一个地址,这个地址是二维数组arr
的第一行(或称为第一个一维数组)的首元素的地址。因此,p
的值(即它存储的地址)是指向arr[0][0]
的。 -
*p
的“地址”:当我们说*p
的地址时,实际上有些误导,因为*p
不是一个指针,而是一个数组(尽管在表达式中它会被退化为指向其首元素的指针)。但是,如果我们谈论*p
“指向”的地址,我们实际上是在谈论*p
(即arr[0]
)的首元素的地址,这与p
存储的地址是相同的,都是&arr[0][0]
。
然而,重要的是要理解 p
和 *p
在类型和使用上的差异:
-
类型:
p
的类型是int (*)[5]
,即一个指向包含5个整数的数组的指针。而*p
的类型是int[5]
,即一个包含5个整数的数组(但在表达式中它会被退化为int*
)。 -
使用:你不能直接对
*p
进行赋值或将其作为函数参数传递(因为它不是一个左值),但你可以通过索引来访问它的元素(如(*p)[0]
)。而p
可以被赋值,可以作为函数参数传递,也可以进行指针算术运算(如p + 1
将指向下一行)。
为了澄清,让我们再次强调:p
存储了一个地址,这个地址是二维数组第一行的首元素的地址。而 *p
在表达式中会被退化为指向这个首元素的指针,但技术上 *p
表示的是整个一维数组的“视图”。然而,我们总是通过索引来访问这个数组中的元素。
总结:p
和 *p
在“指向”的地址上是相同的(都指向 arr[0][0]
),但它们的类型和使用方式完全不同。
那*p+1会得到什么?
在C语言中,当 *p
表示一个数组(尽管在表达式中它通常会被退化为指向其首元素的指针)时,直接对 *p
进行算术运算(如 +1
)是不合法的,因为 *p
本身不是一个可修改的左值,也不是一个指针。
然而,如果你写了 *p + 1
,这里实际上发生的是指针算术的“假象”。由于 *p
在表达式中会被退化为指向数组首元素的指针(即 int*
类型),*p + 1
的结果是一个指向 arr[0][1]
的指针(即 &arr[0][1]
)。这里,+1
是按照指针的步长(即指向类型的大小)来计算的,对于 int*
类型的指针来说,步长通常是 sizeof(int)
。
但是,重要的是要明白这种写法(*p + 1
)虽然在技术上是合法的,并且可能符合你的预期(得到指向下一个元素的指针),但它实际上是在对已经退化为指针的 *p
进行操作,而不是直接对数组本身进行操作。
如果你想要访问二维数组中的下一个元素(比如从 arr[0][0]
移动到 arr[0][1]
),你应该使用 (*p)[1]
。但是,如果你想要得到指向下一个元素的指针,那么 *p + 1
是正确的写法,尽管它看起来可能有些令人困惑。
然而,如果你想要遍历二维数组的行,你应该使用指针 p
本身进行算术运算,比如 p + 1
会指向二维数组的下一行(即 &arr[1]
)。
总结一下:
*p + 1
得到的是指向arr[0][1]
的指针。(*p)[1]
访问的是arr[0][1]
的值。p + 1
指向二维数组的下一行。