指针与数组的关系及运算 一、概念: 1.1、指针数组(char*p[4]):表示p是含有4个素的数组,每个素存放的数据是指针类型。 1.2、数组指针(int(*p)[4]):表示p是个指针,p指向地址(p值)的数据空间长度为4个int。 1.3、指针与数组的关系: 其实指针的本质就是数组,一级指针是一维数组,二级指针是二维数组,以此类推。注意: “[]”与“*”都是取数据符号,但“[]”取得是数组自身素的数据,而”*”取得是间接取p值的数据,(也就是变量a的值)。 int *p \即p指向地址在内存的数据长度为1个int ,注意int*p与int(*p)[1]完全不一样,相当于变量和数组的区别。 int (*p)[1] \表示p是个指针,p指向地址(p值)的数据空间长度为1个int(只有1个素的数组,它与变量还是有区别的),此时将p指向地址的数据空间看作一个数组。该指针定义中有1个“*”和1个“[]”两个取数据符,也就是说表达式p中含有两个取数据符结果才是数据。 int (*p)[4] \表示p是个指针,p指向地址(p值)的数据空间长度为4个int,该数据空间看作含4个素的数组。如p[2]表达式的值为地址,表示指针p指向地址偏移2个单位(int(*)[4]即2×4字节后在内存中的地址;如p[2][3]表达式为数据,表示指针p指向地址先整体偏移2个单位(int(*)[4])即8字节,再偏移3个素,即*(p+2)+3的地址,取该地址在内存中的数据即*(*(p+2)+3)=p[2][3]。 注意:类型相同长度不同的指针,不能直接赋值,如下 int a[3]={0}; \数组a长度为3个int。 int *p=Null; p=a; \等价于p=&a[0],此时的a代表第一素的地址。 p=&a \此时a代表整个数组(长度3个int)的地址,这种写法是不规范的,正确写法:p=(int*)&a 1.4、指针变量p是个地址,而数组的数组名a也是个地址,从而可以这样赋值p=a,由此衍生的指针数组、数组指针所产生的表达式及运算千变万化,经常看到一个表达式都不知道,最终所求的值是地址还是数据。网络上看了好多推演的教程,也思考了很久,但看到好多推演断层式的表达式,还是想不明白。最终自己找到“以不变应万变”的方法,算是自己的感悟吧! 二、“3部曲” 部曲1:判断p在定义的指针表达式中是指针变量还是数组。用优先级原则判断,即p先跟“*”还是“[]”结合,前者p为指针变量也就是地址,后者p为数组名,以数组对待。 部曲2:数组的表达式中“[]”的个数是否等于维数,等于则表达式就是素值,不等于则表达式的值都是地址,无论多少维数组。验证如下: (1) 不管多少维的数组,表达式中”[]”比维数只要少一个,那么这个表达式的值就是地址,并且该地址是该维的首地址,如二维数组a[3][2],三维数据b[2][3][2],一维数组c[10]。
(2) 任何维数数组所表示的地址表达式(”[]”比维数少),增加”[]”结合成新表达式时(结合“*”相当于增加一个”[]”),只要“[]”的个数少于维数,无论怎么结合都是地址偏移(有多少个“[i]”或“*”要结合,那么直接加i就行),并且它结果还是个地址,只有当“[]”的个数等于维数,表达式的值才是素值(也就是该内存地址中的数据)。注意: “[]”与“*”都是取数据符号,等效的。 部曲3:p+1偏移代表什么。若p在指针定义表达式中是数组,则偏移一个素;若p在指针定义表达式中是指针变量,则偏移指针定义中指向的整个数据的长度。 三、案例分析 案例1(指针数组): int n[3][4] = { 1, 2, 3, 4, 8, 7, 6, 5, 9, 10, 11, 12 }; int *pn[3] = { n[1], n[0], n[2] }; \pn先与[]结合,所以pn为一维数组。 printf(“%d ”, (*(pn + 2))[3]); \数组pn少[],pn为地址且偏移2,取数据符*(pn+2)等价pn[2],即一维数组pn结合1个”[]”就是素值(数据),因pn[2]的值为n[2],而n为二维数组,n[2]少了1个”[]”表示为地址,n[2]在结合1个“[]”即n[2][3]=12表示素(数据)。 printf(“%d ”, pn[1][2]); \数组pn结合1个”[]”即pn[1]就是素(数据),因pn[1]的值为n[0],而n为二维数组,n[0]少了1个”[]”表示为地址,n[0]在结合1个“[]”即n[0][2]=3表示素(数据) printf(“%d ”, *(pn + 1)[1]); \数组pn少[],pn为地址且偏移1,(pn+1)没有[ ]还是个一维数组的地址,跟”[1]”结合,既结合“[]”又偏移1,满足“[]”个数 等于维数,即为pn数组的素pn[2],因pn[2]=n[2],而n为二维数组,n[2]少了1个”[]”表示为地址,与“*”结合,相当于增加一个”[]”,即*n[2][0]=9。这里要特别注意运算优先级。
案例2(数组指针): int a[14] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14 }; int(*p)[2] = a; //p先与*结合,所以p是指针,长度为2个int。从指针的定义看,指针有两个取数据符,也就是说表达式中含有两个取数据符结果才是数据,类推int(*p)[2][3]要3个取数据符结合才是数据。 printf(“%d ”, p); //p的不够2个取数据符,为地址。 printf(“%d ”, *p); //p的不够2个取数据符,为地址。 printf(“%d ”, p); //p结合2个取数据符,为数据。 printf(“%d ”, p[1]); //p的不够2个取数据符,为地址。 printf(“%d ”, *p[1]); //p结合2个取数据符,为数据。 printf(“%d ”, p[1][1]); //p结合2个取数据符,为数据。
案例3(数组指针): int n[3][4] = { 1, 2, 3, 4, 8, 7, 6, 5, 9, 10, 11, 12 }; int (*pn)[4]=n; \pn与*先结合,因此pn为指针变量,并且指向的数组长度为4。等价式pn=n,即可将pn当做二维数组n运算。 printf(“%d ”, (*(pn + 2))[3]); \pn偏移2单位还是地址,再与*结合(相当于pn增加一个”[]”),即pn[2]=n[2],最后n[2]和[3]结合即n[2][3],所以n[2][3]=12是数组的素。 printf(“%d ”, pn[1][2]); \pn=n,即pn[1][2]=n[1][2],而n[1][2]中“[]”个数等于数组维数,n[1][2]=6为数组素。 printf(“%d ”, *(pn + 1)[1]); \pn偏移1单位还是地址,跟”[1]”结合,既增加“[]”又偏移1,即pn[2],因pn[2]=n[2],而n为二维数组,n[2]少了1个”[]”表示为地址,与“*”结合,相当于增加一个”[]”,即*n[2][0]=9。
2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/43923.html