在此声明中
int foo[5];
您声明了数组类型int[5] 的对象。对象foo 不是指向数组第一个元素的指针。要查看差异,请考虑以下演示程序。
#include <stdio.h>
int main(void)
{
int foo[5];
int *foo_ptr = &foo[0];
printf( "sizeof( foo ) = %zu\n", sizeof( foo ) );
printf( "sizeof( foo_ptr ) = %zu\n", sizeof( foo_ptr ) );
return 0;
}
程序输出是
sizeof( foo ) = 20
sizeof( foo_ptr ) = 8
或者考虑其他方案
#include <stdio.h>
int main(void)
{
int foo[5];
int *foo_ptr = &foo[0];
int ( *p1 )[5] = &foo;
int **p2 = &foo_ptr;
printf( "sizeof( *p1 ) = %zu\n", sizeof( *p1 ) );
printf( "sizeof( *p2r ) = %zu\n", sizeof( *p2 ) );
return 0;
}
程序输出又是
sizeof( *p1 ) = 20
sizeof( *p2r ) = 8
指针类型p1 和p2 之间甚至存在差异。
此外,指针可能是可分配的,而数组是不可修改的左值。
那是你可能不会写例子
int foo[5] = { 1, 2, 3, 4, 5 };
int bar[5] = { 5, 4, 3, 2, 1 };
foo = bar;
但你可以写
int foo[5] = { 1, 2, 3, 4, 5 };
int bar[5] = { 5, 4, 3, 2, 1 };
int *foo_ptr = foo;
int *bar_ptr = bar;
for_ptr = bar_ptr;
但实际上,除了极少数例外,数组指示符会转换为指向其第一个元素的指针。
例如在这个声明中
int *foo_ptr = foo;
用作初始化器的数组指示符被转换为指向其第一个元素的指针。
来自 C 标准(6.3.2.1 左值、数组和函数指示符)
3 除非它是 sizeof 运算符的操作数或一元 &
运算符,或者是用于初始化数组的字符串文字,
具有“类型数组”类型的表达式被转换为
类型为“pointer to type”的表达式,指向初始
数组对象的元素并且不是左值。如果数组对象
有注册存储类,行为未定义。
按照您的建议标记单个元素
int foo0, foo1, foo2, foo3, foo4;
意义不大。
例如,一个数组可以包含非常多的元素,例如一千个元素甚至更多。
你会写这样的声明吗?
int foo0, foo1, foo2, foo3, foo4, /*other variable declarations...*/, foo1000;
另一个问题如何将所有变量传递给函数?
您需要列出所有变量。此外,当您将数组传递给函数时,实际上数组的所有元素都是通过引用传递的。也就是说,该函数将通过指向其第一个元素的指针来处理数组的原始元素。将所有“标记元素”传递给函数意味着该函数将处理元素的副本。您需要向每个“标记元素”传递运算符地址。
另一个问题是 C 标准没有指定在每个顺序中局部变量将被放置在内存中。例如,编译器可能会放置从 foo0 或 foo1000 开始的变量。
还有一个问题是如何编写一个循环来处理变量?您可能不会使用指针来遍历所有变量,因为如果对象属于数组,您可能会使用指针来遍历对象。
或者如何动态分配所有变量并作为数组访问?
如果你会写例如
int *p0 = malloc( sizeof( int ) );
...
int p1000 = malloc( sizeof( int ) );
那么没有任何保证分配的对象将存储在相邻的内存范围中。