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
作为第一行大小的输出,而 *a
是 0th
行的 0th
元素的基地址,它的类型是一个指向整数的指针。 a
指向第一行本身。为什么会这样?
*a
不是指针,它是一个 int[5]
,这与您对 20
的阅读是一致的,假设一个 4 字节 int
.
*a
是 a
的第 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
列。
*a
是 1st
列的地址,我们有 5
列,所以当你尝试这个时:
sizeof(*a);
输出将是 20
=> (5
列) * (int pointer
即 4
字节)).
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]
) 相同。 *a
和 a[0]
的类型都是“int
的 5 元素数组”;因此 sizeof *a
和 sizeof 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 个字节。
同样,如果你将*a
或a[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 字节。
我知道当我们在数组名称上使用 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
作为第一行大小的输出,而 *a
是 0th
行的 0th
元素的基地址,它的类型是一个指向整数的指针。 a
指向第一行本身。为什么会这样?
*a
不是指针,它是一个 int[5]
,这与您对 20
的阅读是一致的,假设一个 4 字节 int
.
*a
是 a
的第 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
列。
*a
是 1st
列的地址,我们有 5
列,所以当你尝试这个时:
sizeof(*a);
输出将是 20
=> (5
列) * (int pointer
即 4
字节)).
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]
) 相同。 *a
和 a[0]
的类型都是“int
的 5 元素数组”;因此 sizeof *a
和 sizeof a[0]
都应该产生 5 * sizeof (int)
。
然而...
如果你将a
传递给一个函数,比如
foo( a );
那么 a
是 而不是 sizeof
或一元 &
运算符的操作数,表达式将从类型 " int
" 到 "pointer to 5-element array of int
":
void foo( int (*a)[5] ) { ... }
如果你在函数 foo
中计算 sizeof a
,你会 而不是 得到 5 * sizeof (int)
,你会得到 sizeof (int (*)[5])
,这取决于平台,将是 4 到 8 个字节。
同样,如果你将*a
或a[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 字节。