为什么值不同?C++指针

7

我在谷歌上搜索如何在C++中获取数组的长度。我找到了其中一种解决方案:

int arr[] = {1,2,3,4,5,6};
int size = *(&arr+1)-arr; //size is the length of the array

我曾经在&arrarr之间感到困惑,因为它们都给出了数组的基地址。我又去搜索了一下,发现当&arr + 1时,它会给出不属于该数组的下一个内存块的地址;而当arr + 1时,它会给出该数组中下一个元素的地址。
以下是我编写的测试代码,以验证&arrarr之间的差异:
int arr[] = {1,2,3,4,5,6};
printf("value of &arr + 1 - &arr = %d\n", &arr + 1 - &arr);
printf("value of *(&arr + 1) - arr = %d\n", *(&arr + 1) - arr);

第一个 printf 的答案是 1,而第二个 printf 的答案是 6。这是令我困惑的部分:既然 &arrarr 都保存了同一数组的基地址,为什么结果不同呢?


请尝试访问https://en.cppreference.com/w/cpp/types/extent。 - jtbandes
&arr + 1 - &arr = &arr - &arr + 1 = 1。 - solarflare
@solarflare -- 不是这样的,*(&arr + 1) - arr == 6。为什么?&arr 是一个指向 char [6] 数组的指针,因此 &arr + 1 是一个指向 char [6] 数组之后地址的指针。当您对 数组指针 进行解引用时,您会得到一个 数组,通过访问转换为指针的地址,即在 arr 之后的 int 的地址。因此,*(&arr + 1) - arr 将给出 int 数组中的 元素数量,就像 sizeof arr / sizeof *arr 一样。 - David C. Rankin
@DavidC.Rankin在第一行并没有对其进行取消引用操作,他基本上是在进行指针运算,从而得出结果1。我已经解释了原因。 - solarflare
好的,我指的是第一个 int size = *(&arr+1)-arr;,抱歉让你感到困惑。你可以使用 int size = (char*)*(&arr+1)-(char*)arr; 来获取数组中的 字节数 - David C. Rankin
显示剩余2条评论
2个回答

7
由于"&arr"和"arr"都持有相同数组的基地址,为什么结果不同呢?
因为它们的类型不同。指针运算受指针类型影响,特别是所指对象的类型。
"&arr"是一个指向6个int数组的指针。将1添加到该指针时,会递增到下一个6个int数组(如果它是数组的元素)。
虽然"arr"是一个数组,但在使用它的值(如指针运算表达式)时,它会衰变为指向数组第一个元素的指针。衰变后的值是一个指向int的指针,将1添加到其中会移动指针到下一个整数。
P.S. 您可以使用std::size代替。或者在C++17之前使用std::extent。在C++11之前使用sizeof arr / sizeof *arr。
"*(&arr + 1) - arr"可能有效,但从技术上讲,它通过过去的末端指针进行间接操作(到一个不存在的对象),这通常是未定义的行为。我不确定是否可能有一些例外情况,考虑到该值仅用于衰变为指针。

更好的做法是,您可以使用 std::arraystd::vector - Ayxan Haqverdili
让我感到困惑的是所有这些的合法性。指针算术仅在对象内部有效。难道有特殊例外适用于超出对象的技巧吗?哈!你瞧,早该点一下看编辑了!我也找不到任何例外。 - user4581301
关于指针算术运算:虽然+1是可以的,但实际上在执行减去指针算术运算时,由于它们不在同一个数组中,这可能确实是技术上未定义的行为。但这可能属于未定义行为的类别,任何明智的编译器都不会破坏它,因为这将防止在标准C++中实现std::vector等功能。 - eerorika
那就是我要用的例子。计算完整std::vector的长度。即使他们的措辞有点紧绷,但这演示了意图。 - user4581301
@user4581301 我在考虑向量内的任何指针算术,因为那里不能有“T数组”。只有单个T对象可以重复使用char数组(或类似的)的存储空间。这使得“指针算术仅在数组内有效”变得棘手。 - eerorika
显示剩余2条评论

0

&arr和arr是不同的指针。 arr是数组“arr”的第一个元素的地址。 但&arr是指针arr的地址。在&arr地址中有数组“arr”的地址。 因此,&arr是数组地址的地址。 因此,&arr是不可预期的,*(&arr + 1)也是不可预期的。 因为我们不知道&arr的下一个地址保存了哪个值。

让我解释一下你的两个printf语句。 &arr + 1 - &arr始终返回1。因为它将1添加到&arr并再次减去&arr,所以结果为1。 *(&arr + 1)- arr返回不可预期的结果。因为*(&arr + 1)是不可预期的,arr也是不可预期的,所以结果是不可预期的。

这就是为什么这两个结果不同的原因。

抱歉没有友好的答案。 谢谢,最好的问候。

Jin Yi。


因为我们不知道&arr的下一个地址保存了哪个值。我们不必知道那里保存了什么。如上所述,您只关心地址,而不是该地址处的内容。 - David C. Rankin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接