1.什么时候数组与指针相同
声明本身还可以进一步分成3种情况:
1.外部数组的声明;
2.数组的定义(定义是声明的一种特殊情况,它分配内存空间,并可能提供一个初始值);
3.函数参数的声明;
所有作为函数参数的数组名总是可以通过编译器转换为指针。
对于编译器而言,一个数组就是一个地址,一个指针就是一个地址的地址。
extern,如extern char a[];不能改写成指针形式
声明 —————————↗→定义,如char[0];不能改写成指针形式
↗ ↘ 函数的参数,如func(char a[]);可以选择数组形式或指针形式
数组
↘在表达式中使用——>如c=a[i];可以选择数组形式或指针形式
2.为什么会发生混淆
什么时候数组和指针是相同的?
C语言标准对此作了如下说明:
规则1.表达式中的数组名(与声明不同)被编译器当作一个指向该数组第一个元素的指针;
规则2.下标总是与指针的偏移量相同;
规则3.在函数参数的声明中,数组名被编译器当作指向该数组第一个元素的指针;
3.为什么C语言把数组形参当作指针
把作为形参的数组和指针等同起来是出于效率原因的考虑。
数组/指针实参的一般用法
调用时的实参 类型 通常的目的
func(&my_int) 一个指向整型数的地址 一个int 参数的地址调用
func(my_int_ptr) 指向整型数的指针 传递一个指针
func(my_int_array) 整型数组 传递一个数组
func(&my_int_array[i]) 一个整型数组摸个元素的地址 传递数组的一部分
4.数组片段的下标
可以通过向函数传递一个指向数组第一个元素的指针来访问整个数组,但也可以让指针指向任何一个元素,这样传递给函数的就是从该元素之后的数组片段。
5.数组和指针可交换性的总结
1.用a[i]这样的形式对数组进行访问总是被编译器“改写”或解释为像*(a+i)这样的指针访问;
2.指针始终始终指针,它绝不可以改写成数组,你可以用下标形式访问指针,一般都是指针作为函数参数时,而且知道实际传递给函数的是一个数组;
3.在特定的上下文中,也就是它作为函数的参数(也只有这种情况),一个数组的声明可以看作是一个指针.作为函数参数的数组(就是在一个函数调用中)始终被编译器修改成为指向数组第一个元素的指针;
4.因此,当把一个数组定义为函数的参数时,可以选择把它定义为数组,也可以定义指针。不管选择哪种方法,在函数内部事实上获得的都是一个指针;
5.在其它所有情况中,定义和声明必须匹配。如果定义了一个数组,在其它文件对它进行声明时也必须把它声明为数组,指针也是如此;
6.C语言的多维数组
6.1但所有其他语言都把这称为“数组的数组”
C语言的方法多少有点独特:定义和引用多维数组唯一的方法就是使用数组的数组。
6.2如何分解多维数组
不能把一个数组赋值给顶一个数组,因为数组作为一个整体不能不能成为赋值的形象。可以把数组名赋值给一个指针,就是因为“在表达式中的数组名被编译器当作一个指针的规则”。
6.3内存中数组是如何布局的
在C语言的多维数组中,最右边的下标是最先变化的,这个约定被称为“行主序”。C语言中多维数组最大用途是存储多个字符串。
6.4如何对数组进行初始化
一维数组可以通过把初始值都放在一对花括号内来完成初始化。注意可以在最后一个初始化值的后面加一个逗号,也可以省略它。同时也可以省略最左边下标的长度(也只能是最左边),编译器会根据初始化值的个数推断出它的长度。
如果数组的长度比所提供的初始化值的个数要多,剩余的几个元素会自动设置为0,如果元素类型是指针,那么它们被初始化为NULL,如果元素是float,那么它们被初始化为0.0。