C 中 sizeof 运算符中的参数

Parameters in the sizeof operator in C

我知道当我们在数组名称上使用 sizeof 运算符时,它会给出数组的总大小(以字节为单位)。例如

int main(int argc, const char * argv[]) {
    int a[][5] = {
        {1,2,3,4,5},
        {10,20,30,40,50},
        {100,200,300,400,500}
    };

    int n=sizeof(a);
    printf("%d\n",n);

}

它给出 60 作为数组 15 elements 的输出。但是当我写

int n=sizeof(*a);

它给出 20 作为第一行大小的输出,而 *a0th 行的 0th 元素的基地址,它的类型是一个指向整数的指针。 a 指向第一行本身。为什么会这样?

*a 不是指针,它是一个 int[5],这与您对 20 的阅读是一致的,假设一个 4 字节 int.

*aa 的第 0 行,该行是五个 int.

的数组

在大多数表达式中,数组会自动转换为指向其第一个元素的指针。因此,当您在 int *x = *a; 等语句中使用 *a 时,*a 将转换为指向其第一个元素的指针。这导致指向 int 的指针,它可能被分配给 x.

但是,当数组是 sizeof 运算符、一元 & 运算符或 _Alignof_ 运算符的操作数时,它不会转换为指向其第一个的指针元素。此外,用于初始化数组的字符串文字数组不会转换为指针(因此,在 char foo[] = "abc"; 中,"abc" 用作数组来初始化 foo;它未转换为指针)。

在这个 2d 数组中 *a 是一个指针,因为当您打印它时,它似乎是一个地址(但它是 1st 列地址):

printf("%d\n", *a);

输出:9435248

所以 :

for(int i = 0;i < 3;i++)
    printf("%d\n", *a[i]);

输出为:

1
10
100

当您像这样使用 *a 时:*a[3] 表示您默认位于 3rd 行和 1st 列。

*a1st 列的地址,我们有 5 列,所以当你尝试这个时:

sizeof(*a);

输出将是 20 => (5 列) * (int pointer4 字节)).

Sizeof returns 变量在内存中的大小,以字节表示。这包括填充(编译器将未使用的字节添加到结构中以提高性能)。您的数组有 15 个元素,大小为 4。在您的情况下,内存中整数的大小为 4。您可以通过 运行:

轻松验证这一点
printf("sizeof an integer: %zu\n", sizeof(int));

使用标准 int 类型总是一个好主意。

#inlcude <stdint.h>
uint32_t a[][5] = {
    {1,2,3,4,5},
    {10,20,30,40,50},
    {100,200,300,400,500}
};

这将生成完全相同的代码,但会清楚地显示(32 位)整数的内存大小。 在您的情况下 uint8_t (8 位无符号整数)可能更合适。您可以阅读更多 here。要获得元素的数量,您应该将数组的总内存除以元素的大小。

sizeof(a)/sizeof(a[0])

您也可以使用宏来执行此操作:

#define ARRAY_LENGTH(array)(sizeof(array)/sizeof(array[0]))
/*ARRAY_LENGTH(a) will return 15 as expected.*/

您也可以在这里寻找答案:How can I find the number of elements in an array?

除非它是 sizeof 或一元 & 运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,表达式 类型 "N-element array of T" 将被转换 ("decay") 为类型 "pointer to T" 的表达式,表达式的值将是数组第一个元素的地址。

表达式 a 的类型为“int 的 5 元素数组的 3 元素数组”;因此,sizeof a 应该产生 3 * 5 * sizeof (int)

表达式*a与表达式a[0]相同(a[i]定义为*(a + i) - *a与[=25相同=],这与 a[0]) 相同。 *aa[0] 的类型都是“int 的 5 元素数组”;因此 sizeof *asizeof a[0] 都应该产生 5 * sizeof (int)

然而...

如果你将a传递给一个函数,比如

foo( a );

那么 a 而不是 sizeof 或一元 & 运算符的操作数,表达式将从类型 " int" 到 "pointer to 5-element array of int":

的 5 元素数组的 3 元素数组
void foo( int (*a)[5] ) { ... }

如果你在函数 foo 中计算 sizeof a,你会 而不是 得到 5 * sizeof (int),你会得到 sizeof (int (*)[5]),这取决于平台,将是 4 到 8 个字节。

同样,如果你将*aa[i]传递给一个函数,函数实际接收到的是指向int的指针,而不是int的数组, sizeof 将反映这一点。

二维数组被视为一维数组的数组。也就是说,二维数组中的每一行都是一维数组。对于给定的二维数组 A,int A[m][n] 你可以想到

  • A[0]作为第0行的地址
  • A[1] 作为第 1 行的地址等等。

解引用可以这样想,

 A[i][j] = *(A[i] + j) = *(*(A+i) + j)

所以当你说 *A 时,它的意思是 A[0],它给你第一行的地址,而不是矩阵的第一个元素。

  • 取消引用 A 或 *A 给出第 0 行或 A[0] 的地址。
  • A[0] 的取消引用给出 A 或 A[0][0] 的第一个条目,即

    **A = A[0][0].

& 因为第一行有 5 个元素,所以大小为 20 字节。