【问题标题】:C getting the size of an arrayC获取数组的大小
【发布时间】:2025-12-26 06:35:06
【问题描述】:

代码:

int arr[5] = {10, 20, 30, 40, 50};

printf("%lu %lu\n", *(&arr + 1), arr); // 6422036 6422016
printf("%lu\n", *(&arr + 1) - arr);    // 5

为什么第二个printf 打印的是 5 而不是 20?

【问题讨论】:

  • &arr 的类型为 pointer-to-array int [5] 所以*(&arr + 1)arr 之后的下一个5 int 数组中的第一个元素的地址并且您要打印的类型是int *,因此这些值彼此相距5 int(20 字节)。 (从技术上讲,由于 转换说明符 和类型不匹配,您会调用 Undefined Behavior"%p" 是指针的正确说明符(尽管 "%lu" 应该足够宽) )
  • 这只是一个建议,您可能需要编辑它并将标题更改为问题。有点模糊。
  • 好电话,但是什么? “C - 为什么打印数组地址时的差异”
  • 因为*(&arr + 1)arr之间的距离是5个元素
  • @DavidC.Rankin 也是 UB 因为这个:C11, 6.5.6/9: "如果结果指向数组对象的最后一个元素,则不应用作被评估的一元 * 运算符的操作数。"

标签: c arrays pointers


【解决方案1】:

你的有趣问题有两点:

  1. 指针操作如何工作?
  2. arr 和 &arr 有什么区别?

1:指针操作如何工作?

试试下面的代码:

#include <stdio.h>
#include <inttypes.h>

int main(int argc, char **argv) {

int simpleInt= 10 ;
printf("Output 1 : %p %p \n", &simpleInt+1, &simpleInt); // 61FE20 and 61FE1C
printf("Output 2 : %lld \n", &simpleInt+1 - &simpleInt); // 1
printf("Output 3 : %lld\n", (uint64_t)(&simpleInt+1) - (uint64_t)(&simpleInt)); // 4

}

输出1:很明显,两个打印的指针值之差是4

输出 2:您正在对 int * 执行操作。 1 被添加到 int * 类型的操作数,并在 int * 类型的操作数被减去之后。从“int * 的角度”(如果我可以这样简化的话),只添加了一个。因此,输出为 1。

输出 3:减法的每个操作数都被强制转换为 long long unsigned int。所以减法是对整数而不是指针进行的。正如预期的那样,输出为 4。

2。 arr 和 &arr 有什么区别?

让我们看看下面的代码

int arr[5] = {10, 20, 30, 40, 50};

printf("Output 1 : %p %p %p \n", arr, &arr, *(&arr) ); //Seems to be the same thing but NOT. int*, int*[5], int*, respectively

// printf("%lld\n", arr - &arr ); // compilation error : int * and int(*)[5]
printf("Output 2 : %lld\n", arr - *(&arr) );
//printf("%lld\n", &arr - *(&arr) ); // compilation error : int(*)[5] and int *


printf("Output 3 : %p %p %p \n", (arr + 1), (&arr + 1), *(&arr + 1) ); // +4, +20, +20
printf("Output 4 : %lld\n", *(&arr + 1) - arr);

printf("Output 5 : %lld\n", (uint64_t)(*(&arr + 1)) - (uint64_t)(arr));

输出 1:值相同,但参数类型不同。这一点非常重要。数组的名称是指向其第一个元素的指针。在您的情况下,您的数组是int 的数组,因此arr 是指向int 的指针:int*&amp;arr 是变量arr 的地址,它是一个由 5 个整数组成的数组。所以&amp;arr 的类型是int(*)[5]。而*(&amp;arr)的类型是int*

输出 2:由于上面的解释,一些行给出了编译错误。您可以对相同的指针类型进行操作:arr*(&amp;arr)

输出 3:根据增加的指针类型,获得 +4 或 +20。 +20 因为 1 被添加到 int(*)[5] 类型的操作数:5 * 4 (sizeof int = 4)

输出 4 和 5 :在第一点(指针操作)中,您正在以 int* 作为操作数执行减法

【讨论】:

    【解决方案2】:

    为什么第二个 printf 打印的是 5 而不是 20?

    代码生活在边缘。

    &amp;arr是数组的地址,所以+ 1next数组的地址:5int后面。到目前为止,这很好。

    *(&amp;arr + 1) 取消引用该地址。所以我们得到了 next 数组。不太好@RobertS supports Monica Cellio。传递给 ... 函数的数组(如 printf())被转换为第一个元素的地址,即 int *

    *(&amp;arr + 1) - arr 减去两个相同类型的指针 int *,它们相距 5 int,导致 5 类型为 intptr_t 的差异。回想一下,指针减法是引用类型数量的差异(在这种情况下为int),而不是指针值的差异。 5 而不是 20

    代码尝试将intptr_t 打印为unsigned long"%lu",这可能有效,但可能无效(UB)。不太好。最好使用"%td"

    printf("%td\n", *(&arr + 1) - arr); 
    

    【讨论】: