数组的本质
上一章节讲过了指针,那么数组是什么,数据类型是什么,为什么数组做函数参数的时候会退化为指针,怎么理解。
先看一段代码:
int i,*p,a[] = {3,4,5,6,79}; p= a; for (i=0;i<=9;i++) { printf("%d ",a[i])//通过数组名访问元素 printf("%d ",*a+i)//也可以这样 printf("%d ",p[i]//也可以这样 }
其实从程序上看数组和指针没有区别,数组从内存上是获取连续的内存区域进行数据存放,通过数组名获取了这块内存地址,所以数组名就是这块内存的代表,被定义为这块内存的首地址。数组名是一个地址,不可修改的常量,一个地址常量。数组名这个符号就是代表内存的首地址,本身就是这个地址。它是一个右值,不能放在=左边进行赋值,而指针是变量确实一个左值。
数组作为形参,在编译器当做指针来看,编译器从效率上将不提倡传入内存空间,但同时要操作一段内存空间,所以编译器默认的将数组名转化为指针,只是转化,传入的是数组地址而已。
多维数组和多级指针
在C语言中并不存在多维数组,从本质上讲是数组的数组,也就是数组的嵌套,各维之间有鲜明的层次关系。上一维把下一维看做作下一级数组,也就是数组的嵌套。
首先存储行号为0的n个元素,对于这n个元素按列号从小到大依次存储:紧接着存储行号为1的n个元素…最后存储行号为m-1的n个元素。
经过上面的分析,我们用sizeof来强化对数组的理解。
int a[5][8][9]; sizeof(a)//5*8*9*sizeof(int) sizeof(a[0])//8*9*sizeof(int) sizeof(a[1])//8*9*sizeof(int) sizeof(a[0][3])//9*sizeof(int) sizeof(a[2][2][4])//sizeof(int) sizeof(&a[0])//sizeof(int)
从上面很容易得到a[0]是指向一个二维数组,通过a[0]可以获取这个二维数组内存值,当然用sizeof,就是获取一个二维数组的内存大小。&a[0]这是像获取指向二维数组指针的大小,也就是二维数组开始的内存地址。在数组中&a和&a[0],&a[0][0]是一样的,这就是都是内存开始的地址值。但是一定注意&a与&a[0]作为右值赋值是,是不一样的分别赋值给三级指针和二级指针。
指针数组和数组指针
指针数组:array of pointers,即用于存储指针的数组,也就是数组元素都是指针
数组指针:a pointer to an array,即指向数组的指针
还要注意的是他们用法的区别,下面举例说明。
-
int* a[4] 指针数组
表示:数组a中的元素都为int型指针
元素表示:a[i] (a[i])是一样的,因为[]优先级高于* -
int (*a)[4] 数组指针
表示:指向数组a的指针
元素表示:(*a)[i]
其中()是不能去掉的,因为[]优先级比*高,这样就变成指针数组了
注意:在实际应用中,对于指针数组,我们经常这样使用:
#include <iostream> using namespace std; int main() { int c[4]={1,2,3,4}; int *a[4]; //指针数组 int (*b)[4]; //数组指针 b=&c;//数组指针指向数组的地址,用数组的地址进行初始化 //将数组c中元素赋给数组a for(int i=0;i<4;i++) { a[i]=&c[i];//指针数组,数组中存放的时指针,所以传入的内存地址 } //输出看下结果,两者的输出方式不同 cout<<*a[1]<<endl; //输出2就对 cout<<(*b)[2]<<endl; //输出3就对 return 0; }
重点讲解
数组和指针的区别
定义一个数组的时候,需要在栈中静态分配一块内存,那么需要知道内存的大小,因为定义数组的时候需要确定各维的上限。数组是一个可以拥有内存,保存变量的数组类型,数组名代表地址。指针是一个存储内存地址的数据类型,定义一个指针需要知道它指向对象的类型,不需知道对象的大小。
字符串常量
字符串常量在c语言就是一个字符数组,尽管外部表现和数组不一样,实际上字符串常量本身就是数组的首地址,并且具有数组类型。sizeof(“abdaaff”)是 7而不是4。重点区别是字符串常量放在静态存储区,不允许改变;数组在栈中静态分配。
运算符&和*
&是取地址符,*是间接运算符。
&a的结果是一个指针,指针指向的类型就是a的类型加上。在运算中加上就是获取了指针指向的内存值。
版权声明:本文为博主原创文章,未经博主允许不得转载。