获取数组的长度时不要对指针应用 sizeof 操作符
在 C 语言中,sizeof 这个其貌不扬的家伙经常会让无数程序员叫苦连连。同时,它也是各大公司争相选用的面试必备题目。简单地讲,sizeof 是一个单目操作符,不是函数。其作用就是返回一个操作数所占的内存字节数。其中,操作数可以是一个表达式或括在括号内的类型名,操作数的存储大小由操作数的类型来决定。例如,对于数组 int a[5],可以使用“sizeof(a)”来获取数组的长度,使用“sizeof(a[0])”来获取数组元素的长度。
但需要注意的是,sizeof 操作符不能用于函数类型、不完全类型(指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void 类型等)与位字段。例如,以下都是不正确形式:
/*若此时max定义为intmax();*/
sizeof(max)
/*若此时arr定义为char arr[MAX],且MAX未知*/
sizeof(arr)
/*不能够用于void类型*/
sizeof(void)
/*不能够用于位字段*/
struct S
{
unsigned int f1 : 1;
unsigned int f2 : 5;
unsigned int f3 : 12;
};
sizeof(S.f1);
了解 sizeof 操作符之后,现在来看下面的示例代码:
void Init(int arr[])
{
size_t i=0;
for(i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
{
arr[i]=i;
}
}
int main(void)
{
int i=0;
int a[10];
Init(a);
for(i=0;i<10;i++)
{
printf("%dn",a[i]);
}
return 0;
}
从表面看,上面代码的输出结果应该是“0,1,2,3,4,5,6,7,8,9”,但实际结果却出乎我们的意料,如图 1 所示。

是什么原因导致这个结果呢?
很显然,上面的示例代码在“void Init(int arr[])”函数中接收了一个“int arr[]”类型的形参,并且在main函数中向它传递一个“a[10]”实参。同时,在 Init() 函数中通过“sizeof(arr)/sizeof(arr[0])”来确定这个数组元素的数量和初始化值。
在这里出现了一个很大问题:由于 arr 参数是一个形参,它是一个指针类型,其结果是“sizeof(arr)=sizeof(int*)”。在 IA-32 中,“sizeof(arr)/sizeof(arr[0])”的结果为 1。因此,最后的结果如图 1 所示。
对于上面的示例代码,我们可以通过传入数组的长度的方式来解决这个问题,示例代码如下:
void Init(int arr[],size_t arr_len)
{
size_t i=0;
for(i=0;i<arr_len;i++)
{
arr[i]=i;
}
}
int main(void)
{
int i=0;
int a[10];
Init(a,10);
for(i=0;i<10;i++)
{
printf("%dn",a[i]);
}
return 0;
}
除此之外,我们还可以通过指针的方式来解决上面的问题,示例代码如下所示:
void Init(int (*arr)[10])
{
size_t i=0;
for(i=0;i< sizeof(*arr)/sizeof(int);i++)
{
(*arr)[i]=i;
}
}
int main(void)
{
int i=0;
int a[10];
Init(&a);
for(i=0;i<10;i++)
{
printf("%dn",a[i]);
}
return 0;
}










