对数组和指针使用 sizeof 的实验

Experiments using sizeof with arrays and pointers

对于程序:

#include<stdio.h>
int main(void)
{

    int (*a)[2];
    int b[5];

    printf("sizeof(int) : %zu\n", sizeof(int)); 
    printf("sizeof(int*) : %zu\n", sizeof(int*));

    printf("sizeof(b) : %zu\n",sizeof(b));
    printf("sizeof((int*)b) : %zu\n",sizeof((int*)b));
    printf("sizeof(&b[0]) : %zu\n",sizeof(&b[0]));

    printf("sizeof(a) : %zu\n",sizeof(a));
    printf("sizeof(a[0]) : %zu\n",sizeof(a[0]));
    printf("sizeof(a[1]) : %zu\n",sizeof(a[1]));

    return 0;
}

输出为:

sizeof(int) : 4 -> Fact 1
sizeof(int*) : 8 -> Fact 2
sizeof(b) : 20 -> Case 1
sizeof((int*)b) : 8 -> Case 2
sizeof(&b[0]) : 8 -> Case 3
sizeof(a) : 8 -> Case 4
sizeof(a[0]) : 8 -> Case 5
sizeof(a[1]) : 8 -> Case 6

Questions/Observations(以大小写顺序):

  1. 案例 1 输出 20 是因为 b 被声明为整数数组,即 int[]?返回以字节为单位的总块数,由 Fact1 确认。不是吗?

  2. 我想将 b 转换为 int* 会有所不同。这里 b 是 被认为是一个指针。我使用 Fact2 确认了这一点。对还是错?

  3. &b[0] 衰减为指针 b。输出与 Fact2 一致。

  4. I expected 16 这里但我得到 8 作为输出。我得出结论,这是因为 a 毕竟是一个指针,输出与 Fact2 一致。我得到了类似于问题 2 的输出。

  5. a[0] 是指针。输出与 Fact2

  6. 重合
  7. a[1] 是指针。输出与 Fact2

  8. 重合

请回答问题,如有错误请指正。

Please answer the questions and correct me if any of the observations are wrong.

  1. Is Case 1 output 20 because b was declared as an array of integers ie int[]? The total block in bytes is returned as confirmed by Fact1. Isn't it?

是的,结果显示sizeof(int [5])。所以从 Fact1 来看,大小是 5*4

  1. I guess casting b to int* made the difference here. Here b is considered a pointer. I confirmed this using Fact2. Right or wrong?

没错。但是添加更多信息:sizeof 只需要表达式的类型,它 不会 评估表达式(对于值),除非它是 VLA 类型。 (来自 6.5.3.4 sizeof operator of C99 specs

因为您正在对最终结果应用强制转换,所以之后的任何内容都无关紧要。

  1. &b[0] decays to a pointer b. The output coincides with Fact2 .

不,是的。 b[0] 的类型是 int,因此 &b[0] 的类型已经是 int *(回想一下 [...]& 绑定得更紧)。没有腐烂。是的,输出与 Fact2 一致。

  1. I expected 16 here but I got 8 as the output. I concluded that this is because a is afterall a pointer and the output coincides with Fact2 . I got the output similar to Question 2.

a 作为指向 int 的数组 2 的指针。所以打印的大小是指针(指向 int 数组)。

int (*a)[2];a 声明为指向 int 的数组 2 的指针。所以你得到 pointer to array.

的大小

要获得所需的结果(指向 int 的指针数组 2 的大小),请使用:int *a[2];

int (*a)[2];

a           anonymous
+----+      +----+----+
| a  |----->|int |int |
+----+      +----+----+

int *b[2];

b  
+----+----+
|int*|int*|
+----+----+
b[0] b[1]
  1. a[0] is pointer. The output coincides with Fact2
  2. a[2] is pointer. The output coincides with Fact2

如前所述,a是指向int数组2的指针。所以 a[index] 是一个数组 2 if int。因此,a[0]a[1] 的类型是 int 的数组 2。所以输出是来自事实 1 的 2*4
可能与这个答案无关,但是 a 未初始化并且在表达式中使用它会导致 undefined behaviour。虽然可以在 sizeof

中使用

为了理解输出,让我们分析一下 sizeof

的参数类型
printf("sizeof(b) : %zu\n",sizeof(b));             // int [5]
printf("sizeof((int*)b) : %zu\n",sizeof((int*)b)); // int *
printf("sizeof(&b[0]) : %zu\n",sizeof(&b[0]));     // int *

printf("sizeof(a) : %zu\n",sizeof(a));             // int (*) [2]
printf("sizeof(a[0]) : %zu\n",sizeof(a[0]));       // int [2]
printf("sizeof(a[1]) : %zu\n",sizeof(a[1]));       // int [2]

一个portable program (not foolproof) to confirm the types看起来像:

assert(sizeof(b) == sizeof(int [5]));
assert(sizeof((int*)b) == sizeof(int *));
assert(sizeof(&b[0]) == sizeof(int *));

assert(sizeof(a) == sizeof(int(*)[2]));
assert(sizeof(a[0]) == sizeof(int[2]));
assert(sizeof(a[1]) == sizeof(int[2]));

sizeof 运算符是为数不多的可以区分数组(假设它不是函数参数)和指针的东西之一。

  1. b 被识别为 5 个元素的数组,其中每个元素为 4 个字节,因此 sizeof(b) 计算为 20。
  2. 强制转换将数组转换为指针的方式与将其传递给函数的方式类似。所以大小是8.
  3. 这实际上并不是衰减到一个指针。它一个指针。您正在获取 int 的地址,因此类型当然是 int *。解决您的评论之一,如果将表达式 &b[0] 传递给函数,它会衰减为指针仍然不准确,因为它实际上是指针,而不是数组。
  4. 因为a是一个指向数组的指针,所以size就是一个指针的大小,即8。这和int *c[2]不同,后者是一个指针数组,大小为16.
  5. a[0] 不是一个 指针 而是一个 大小为 2 的数组。语法 a[0] 等同于 *(a + 0)。因此,由于 a 是一个指向数组的指针,取消引用 a 给了我们一个数组。由于每个元素为 4 个字节,因此大小为 8。如果 a 定义为 int (*a)[3],则 sizeof(a[0]) 计算为 12。
  6. 类似于数字 5,a[1] 是一个大小为 2 的数组。因此 sizeof(a[1]) 的计算结果为 8,因为它是一个包含 2 个元素的大小为 4 的数组。

如何使用a的例子如下:

int (*a)[2];
int d[3][2];

a=d;
d[0][0]=1;
d[0][1]=2;
d[1][0]=3;
d[1][1]=4;
d[2][0]=5;
d[3][1]=6;

printf("a00=%d\n",a[0][0]);
printf("a01=%d\n",a[0][1]);
printf("a10=%d\n",a[1][0]);
printf("a11=%d\n",a[1][1]);
printf("a20=%d\n",a[2][0]);
printf("a21=%d\n",a[3][1]);

输出:

a00=1
a01=2
a10=3
a11=4
a20=5
a21=6

将二维数组传递给函数时也可以使用它:

void f(int (*a)[2]) 
{
    ...
}

int main()
{
    int x[3][2];
    f(x);
}

这里是关于这个主题的一些个人研究。 我 运行 你在四种不同环境中的测试代码,两个 64 位和两个 32 位。
我使用了三种不同的编译器:llvm、gcc 和 mipsPro cc。
这是评论结果的比较:

// 64-bit environment - all compilers
sizeof(int) :     4 -> Fact 1       -32 bit int -> 4 bytes   
sizeof(int*) :    8 -> Fact 2       -this and other pointers in a 64-bit system are 8-bytes long
sizeof(b) :      20 -> Case 1       -array of 5 32 bit ints -> 20 bytes
sizeof((int*)b) : 8 -> Case 2
sizeof(&b[0]) :   8 -> Case 3
sizeof(a) :       8 -> Case 4
sizeof(a[0]) :    8 -> Case 5       -array of two 4 byte ints
sizeof(a[1]) :    8 -> Case 6       -array of two 4 byte ints

// 32-bit environments - all compilers
sizeof(int) :     4 -> Fact 1       -32 bit int -> 4 bytes 
sizeof(int*) :    4 -> Fact 2       -this and other pointers in a 32-bit system are 4-bytes long
sizeof(b) :      20 -> Case 1       -array of 5 32 bit ints -> 20 bytes
sizeof((int*)b) : 4 -> Case 2
sizeof(&b[0]) :   4 -> Case 3
sizeof(a) :       4- > Case 4
sizeof(a[0]) :    8 -> Case 5       -array of two 4 byte ints
sizeof(a[1]) :    8 -> Case 6       -array of two 4 byte ints

解释 - 所有结果始终符合以下模式:

  • int 的大小曾经取决于编译器,也许现在仍然如此,AFAIK。它在所有经过测试的环境和编译器中都是 4 字节(事实 1)。
  • 所有指针的大小默认为环境,64 位或 32 位(事实 2,案例 2、3、4)。
  • 两个四字节整数 数组的大小 等于 2*sizeof(int)(案例 5、6)。
  • a[0]可以改写为*aa[1]也可以写成*(a + 1)。下面SO post详细阐述

    希望这对您的话题有所帮助。