C专家编程-Chapter9 再论数组
什么时候数组和指针相同?(分声明和使用2类情况)
1. 声明:所有作为函数参数的数组名总是通过编译器转换为指针,在其他所有情况下,数组的声明就是数组,指针的声明就是指针,两者不能混淆。
2. 使用:在语句或表达式引用中,数组总是可以写成指针的形式,两者可以互换。
对编译器而言,一个数组就是一个地址,而一个指针是一个地址的地址。?
ANSI C中相关规定:
1. 表达式中的数组名(与声明不同)被编译器当做一个指向该数组第一个元素的指针
2. 下标总是与指针偏移量相同
3. 在函数参数的声明中,数组名被编译器当做指向该数组第一个元素的指针。
形参:在函数定义或函数声明的原型中定义 int power(int base, int n) base , n 都是形参
实参:在实际调用一个函数时所传递给函数的值。i = pow(10,j); 10, j都是实参
把数组当做整体看的情况:
1. 数组作为sizeof()的操作数,此时获得的是整个数组的大小。
2. 使用&操作符取数组的地址。
3. 数组是一个字符串常量初始值。
在C语言中,所有非数组形式的数据实参均以传值调用(对实参做一份拷贝并传递给调用的函数,函数不能修改作为实参的实际变量的值,只能修改传递给他的那份拷贝)。
我们倾向于始终把参数定义为指针,而不是数组,因为这是编译器内部所使用的形式。数组名是不可修改的左值,他的值是不能改变的,指针可以修改它的值,使其指向不同地址。
fun1(int *ptr){
ptr[1] = 3;
*ptr = 3;
ptr = array2;
}
fun2(int arr[]){
arr[1] = 3;
*arr = 3;
arr = array2; //正确,arr被编译器转为指针
}
int array[1000], array2[100];
main(){
array[1] = 3;
*array = 3;
array = array2; //错误,不能修改数组名
}
可以通过向函数传递一个指向数组第一个元素的指针来访问整个数组,也可以让指针指向任何一个元素,这样传递给函数的就是从该元素之后的数组片段。
总结:
1. 用a[i]这样的形式对数组进行访问总是被编译器“改写”或解释为像*(a+1)这样的指针访问。
2. 指针始终就是指针,它绝不可以改写成数组,你可以用下标形式访问指针,一般都是指针作为函数参数时,而且你知道实际传递给函数的是一个数组。
3. 作为函数参数的数组(就是在一个函数的调用中)始终会被编译器修改成为指向该数组第一个元素的指针。因此,当把一个数组定义为函数参数时,可以选择把它定义为数组,也可以定义为指针,不管哪种方法,函数内部事实上获得的都是一个指针。
4. 在其他所有情况中,定义和声明必须匹配,如定义了一个数组,在其他文件对他进行声明时也必须声明为数组,指针也是如此。
C中的多维数组为“数组的数组”,可以把数组看作是一种向量,也就是某种对象的一维数组,数组的元素可以是另一个数组。数组的分解图 int apricot[2][3][5]
上例为“数组的数组的数组”,每一个单独的数组都可以看做一个指针,不同的维所指向的数据步长也就不同 。
C中的多维数组最右边的下标是最先变化的,成为“行主序”只能在数组声明时,对他进行整体初始化,多维数组可以通过嵌套的花括号进行初始化,可以省略最左边下标的长度,编译器会根据初始化值的个数推断出它的长度。默认初始化值: 指针类型->NULL, float->0.0
初始化二维字符串数组时可以用 char veg[][8] = {“beet”, “barley”, ”beans”};
也可以用指针数组:char *veg[] = {“beet”, “barley”, ”beans”};只有字符串常量才可以初始化指针数组。指针数组不能由非字符串的类型直接初始化。如果非要用这种方法,可以创建几个单独的数组,然后用这些数组名来初始化指针数组。
char ga[] = "abcdefghijklm";
void my_array_func(char ca[10]){
printf(" sizeof array = %d \n",sizeof(ca));
printf(" addr of array param = %#x \n",&ca);//ca变成了指向数组第一个元素的指针
printf(" addr (ca[0]) = %#x \n",&(ca[0]));
printf(" addr (ca[1]) = %#x \n",&(ca[1]));
printf(" ++ca = %#x \n\n",++ca);
}
void my_pointer_func(char *pa){
printf(" sizeof ptr = %d \n",sizeof(pa));
printf(" addr of ptr param = %#x \n",&pa);//指向数组的指针的地址!=数组名的值了
printf(" addr (pa[0]) = %#x \n",&(pa[0]));
printf(" addr (pa[1]) = %#x \n",&(pa[1]));
printf(" ++pa = %#x \n\n",++pa);
}
int main()
{
printf(" sizeof global array = %d \n",sizeof(ga));
printf(" addr of global array param = %#x \n",&ga);
printf(" addr (ga[0]) = %#x \n",&(ga[0]));
printf(" addr (ga[1]) = %#x \n\n",&(ga[1]));
my_array_func(ga);
my_pointer_func(ga);
return 0;
}