C语言数组和指针对于初学者来言,指针是一个很大的坑,但是C语言能够那么多年来屹立不倒,也有赖于指针,没有指针C语言将什么也不是,下面简单分析一下C指针与数组的关系,笔记是自己整理的,如果有大牛发现有些不详尽或者有错误的话,欢迎补充指正,谢谢!也希望初学者能够学好指针,因为把指针搞懂了,后面那些什么Java、C++、OC等一些库函数的底层实现就比较好懂了。
C语言中,数组和指针密不可分,在系统内部实现上有着近乎一致的特性,只有在极少数情况下才需要人为区分;在C语言中只有一维数组的概念,多维数组在系统内部也是开辟一块平坦连续的空间,如果只看内存地址空间,是看不出多维数组的行列数的,比如array1,二维数组就是一个一维数组,数组内部元素是另一个数组,多维数组也是类似递归定义的。
数组有两个确定的参数:数组大小和下标为“0”的元素的地址。数组的下标操作实际上都是通过指针来进行的,数组和指针有一一对应的关系。 - typedef int (*array_type)[3];
- int array1[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
- int array2[4][3]={1,2,3,4,5,6,7,8,9,10,11,12};
- int array3[7]={1,2,3,4,5,6,7};
- int *p1=array3;
- int *q1=p1+1;
- array_type p2=array2;
- array_type q2=p2+2;
当输出array1[1][5]时,输出了“10”,在正常情况下,array1是没有[1][5]这个偏移的,但系统确实能正确的读取到相关的数值,就说明二维数值其实也就是一维数组;
array1[1][5]表示第2行的第6个数据,一行有4个数据,则4+6,切换到数组上就是array1[2][1],表示第3行的第2个数据,可以验证:数组内部数据是扁平化连续分布的,而且是内部转换成指针操作。
分析以上代码:
先建立一个新的用户类型:指针类型,该指针指向了一个拥有3个整型元素的数组;
如何理解数组名其实就是指向第一个数组元素的地址?
又如何解释数组元素?
一维数组array3中,p1的地址信息是array3的第1个变量的地址0x00318064,q1中的地址信息是array3中的第2个变量的地址0x000318068;虽然“q1=p1+1”,但是q1中地址信息并不是0x000318065,而是增加了1个int变量空间,指向了第2个元素。同理,二维数组array2中,p2中地址信息是array2第1个变量的地址0x000318064,q2中的地址是array2中第3个变量地址0x00031804c,这次增加的就不是2个int变量的空间那么简单了,而是23个int变量空间,这里的“3”指的是一维数组“int (array_type)[3]”,这次的步进单位不再是一个int空间,而是3个int变量的数组空间; 因为“int (*array_type)[3]”表示了一个拥有3个整型元素的数组,而array_type q2表示的是这一类“拥有3个整型元素的数组”的第0个元素,所以跨越了3个int变量的数组空间。
array3(一维数组名称)可以直接赋值给int指针,则它指的数组元素是int变量;
array2(二维数组名称)不能直接赋值给int指针,只能直接赋值给一维数组指针(数组长度只能是3)的变量
那么,数组元素就可以这样解释:一维数组中直接就是定义数据类型;多维数组中是指除去最外围数组长度的剩余数组,即array[4][5]的数组元素:array[5],array[3][5][4]数组元素:array[5][4]。
可以认为,多维数组中的各维度在计算时是有优先级顺序。例如,array[3][4]意思是这个数组有3个元素,每个元素含有4个原子数据的数组;各维度在计算时,必须有固定的参考顺序,否则系统就会混乱。
如果指针指向数组中某一元素,则该指针的加减运算是以它指向的数组元素为单位的。即:如果数组元素是int类型,则指针+1会指向下一个int值;如果数组元素是以array[4]为类型,则指针+1会指向下一个array[4]的首地址。 一维数组和指针之间的微妙关系分析:
无论几维数组,它的名称都表示指向该数组“初始元素”(基本类型、结构体、多为数组)的指针唯一的例外就是数组名称作为sizeof的操作时,结果时整个数组空间的大小,与起始元素无关;
array3表示第一个元素(int)的指针,那么array3就表示下标为“0”的元素引用,同理(array3+i)表示下标为i的元素引用,简写为array3,因为*(array3+i)等价于array3;
在函数调用中,传递一维数组的名称时传递数组元素集合的首地址,有了首地址,函数就可以操纵任意长度的一维数组了,但是这个函数不知道该数组长度,而且编译器也不对数组下标进行有效性检查,这样可能会造成数据溢出,必要时需要用一个单独的参数传递数组长度。 - #include <stdio.h>
- int main(){
- int a[7]={1,2,3,4,5,6,7};//定义一个7个元素的数组
- int b=5;//定义一个变量b=5
- printf("%d",*(&b));//打印b地址中的内容
- printf("%d",*(a+6));//打印数组a第6个元素中的内容..注意从第0个开始数
- return 0;
- }
也就是说,数组名其实就是数组第0个元素的地址,a就是获取数组a第0个元素地址里面的内容;而变量,则跟数组没有直接关系,需要去(&变量地址)才能取出变量地址里面的内容
|