再论数组
来源:互联网 发布:腾讯视频网络错误1 编辑:程序博客网 时间:2024/06/06 15:47
1.什么时候数组和指针相同
在实际应用中,数组和指针可以互换的情形比不可互换的情形要更为常见,让我们分别考虑“声明”和“使用”这两种情况;数组声明可以分成3种情况:
1.外部数组的声明(external array)
2.函数定义(定义是声明的特殊情况,它分配内存空间)
3.函数参数的声明
所有作为函数参数的数组总是可以通过编译器转换为指针,在使用数组(在语句或表达式中的引用)时,数组总是可以写成指针的形式,两者可以互换。
图1 指针和数组何时相同
数组和指针在编译处理时是不同的,在运行时的表示形式也是不一样的,并可能产生不同的代码。对编译器而言,一个数组就是一个地址,一个指针就是一个地址的地址
2.c标准中的数组规定
规则1:"表达式中的数组名"就是指针
对数组下标的引用总是可以写成“一个指向数组的起始地址的指针加上偏移量”;对数组的引用如a[i]在编译时总是被编译器改成*(a+i)的形式,在表达式中,指针和数组可以互换,因为在编译器里的最终形式都是指针。
编译器自动把下标值的步长调整到数组元素的大小。如果数组元素的大小是4字节,那么a[i]和a[i+1]在内存中的距离就是4。对起始地址执行加法之前,编译器会负责计算每次增加的步长。这就为什么指针总是有类型限制的,每个指针只能指向一个类型的原因所在:编译器需要知道对指针进行解引用操作时应该取几个字节,以及每个下标的步长应取几个字节。
规则2:c语言把数组下标作为指针的偏移量
规则3:“作为函数参数的数组名”等同于指针
在函数形参定义这个特殊情况下,编译器必须把数组形式改成指向数组第一个元素的指针形式,编译器只向函数传递数组的地址,而不是整个数组的拷贝。
例如:定义函数
在func函数的调用上,实参是数组和指针都是合法的void func(int *ptr){...}void func(int ptr[]){...}void func(int ptr[20]){...}
3.数组和指针的可交换性的总结
1)用a[i]这样的形式对数组进行访问总是被编译器解释为像*(a+i)这样的指针访问。
2)指针始终是指针。它绝不可以改成数组,你可以用下标形式访问指针,一般都是指针作为函数参数时,而且你知道实际传递给函数的是一个数组。3)把一个数组定义为函数的参数时,可以选择把它定义为数组,也可以定义为指针;不管是哪种,在函数内部获得的都是一个指针。4)在其他所有情况中,定义和声明必修匹配。如果定义了一个数组,在其它文件对它进行声明时也必须把它声明为数组,指针也是如此。
4.多维数组的内存布局
在C语言中数组的元素可以是另一个数组,有助于数组的分解,例如声明如下的三维数组:
int array[2][3][5]
图 2 整个数组的内存
图 3 sizeof[i]的内存空间
图4 sizeof[i][j]的内存空间
再如:图 5 sizeof[i][j][k]的内存空间
有人把二维数组看作是排列在一张表格中的一行行的一维数组,如下:char ch[4][3];
图 6 假想的内存分布
实际的内存分布如下:
图 7 实际内存分布
ps:对于二维数组,像图6假想的内存分布有助于平时分析,但实际的内存分布不是这样子的
在C语言的多维数组中,最右边的下标最先变化,绝大数的语言都是采用这个约定且在堆栈内存朝低地址方向增长;
例如:
char b[2][2];
0 0
- 再‘论’指针&数组
- 再论数组
- 再论数组
- 再论数组与指针
- 再论数组和指针
- 再论二维数组传参问题
- 再论数组和指针的区别
- 再论数组和指针(2)
- 再论字符数组和字符指针
- 论指针数组和数组指针
- 论指针数组和数组指针
- 论指针数组与数组指针
- 字符串转成数组,数组再转成字符串
- 论指针与数组
- 再谈谈java 数组
- 指针数组再理解
- 二维数组再折腾!!!
- 再谈字符数组
- GCD介绍(三):Dispatch Sources
- Java数字格式化
- 黑马程序员_java关于子类的继承
- Flume架构的简单学习
- 设计模式之适配器模式
- 再论数组
- Oracle11g使用exp导出空表
- Java内存泄露的理解与解决(转)
- asp.net mvc 性能优化——(1)静态化
- 3D打印(1)十大优势
- GCD介绍(四):完结
- Android库的建立与使用
- 一个应届计算机毕业生的2012求职之路
- javascript 函数节流