写在前面
先把一个题目贴出来,以题来学习数组指针与数组指针、多维数组之间的关系
#include<stdio.h>
int main()
{
char s[][10]={"KAIKEBA","XINZHIKE","LINUX","AIOT0622"};
char *ss[]={s+1,s+3,s+2,s};
char **sss=ss;
printf("%s\n",*++sss);
printf("%c\n",--*++*sss++);
printf("%s\n",sss[-2]+1);
printf("%c\n",*sss[-1]+3);
printf("%s\n",++*(sss--));
return 0;
}
得到答案很简单,跑一遍代码就行‘了,但是我们来一步一步的分析
1、先来理解一些概念
一、指针数组与数组指针
(1)指针数组的实质是一个数组,这个数组中存储的内容全部是指针变量。
(2)数组指针的实质是一个指针,这个指针指向的是一个数组。
int *p;
int p[10];
int *p[10];
int (*p)[10];
-
分析方法:
-
第一步:找核心;
第二步:找结合;
第三步:继续向外结合直到整个符号完。
①int *p;
核心是p,p和 * 结合是指针。所以i nt*p;是定义了一个指针
②int p[10];
核心是p,p和 [10] 结合是数组。所以 int p[5];是定义了一个数组
③int *p[10];
核心是p,这时候p先和[10]结合还是先和 * 结合,查优先级表得到[]优先级更高。所以p先和[10]结合成为数组(在这里就决定了 *p[10]的本质是一个数组还是指针)。 p[10]这个数组再和 * 结合 ,所以得到结果,有一个数组有10个元素,其元素都是指针,即指针数组。
④ int (*p)[10];
核心是p,小括号优先级更高,所以p先和 * 结合成为指针,*p这个指针再和数组结合,所以有一个指针,该指针指向一个数组,即数组指针。
指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身的大小决定,每一个元素都是一个指针,在32位系统下任何类型的指针永远是占8个字节。它是“储存指针的数组”的简称。
数组指针:首先它是一个指针,它指向一个数组。在32 位系统下任何类型的指针永远是占8个字节,至于它指向的数组占多少字节,不知道,具体要看数组大小。它是“指向数组的指针”的简称。
二、在数组中* p +1 与 * (p+1) 的区别
#include <stdio.h>
int main()
{
char a[5]={'A','B','C','D'};
char (*p3)[5] = &a;
printf("%p\n",*p3);
printf("%p\n",*(p3+1));
printf("%p\n",*p3+1);
printf("%p\n",a);
return 0;
}
得到的结果是
所以由上面这个图就可以知道 *(p +1) 是偏移了一个数组空间,而 *p+1只是地址先取 *p 的地址然后加一
三、数组名的三种含义
1、数组名可以代表整个数组
2、数组的首地址
3、数组首个元素的地址
2、先来分析这个题目
char s[][10]={"KAIKEBA","XINZHIKE","LINUX","AIOT0622"};
char *ss[]={s+1,s+3,s+2,s};
char **sss=ss;
其中s很简单是一个二位数组,4行10列;ss是一个指针的数组 ,存放的是指向s[1][0] 的地址的指针 ,指向s[3][0]的地址的指针….每个指针相差8个字节,sss是二级指针存放的是指针数组名,也可以说是指向指针数组ss的首元素sss与ss是完全相同的。
我们先假设 s 的地址为 0x100,所以s[1][0]的地址为0x10a,s[2][0]的地址为0x114,s[3][0]的地址为0x11e,
对应的存储内容为"KAIKEBA",“XINZHIKE”,“LINUX”,“AIOT0622”
假设ss的地址为0x200,ss[1]的地址为0x208,ss[2]的地址为0x210,ss[3]的地址为0x218
对应的存储内容为 0x10a 0x11e 0x114 0x100
3、题目答案:
-
①++*sss = *(0x200 + 8) = *(0x208)= “AIOT0622”
-
sss的地址为0x208
先是对sss解指针操作,得到的是ss[0]指针,也就是 s+1指针也就是s[1][0]
②- -
++*sss++ = - - ++
(0x208) = - -++(0x11e) = - -*0x11f= - - ‘I’(asll码)= ’H’
- sss的地址为 0x210 ss[1] =“HIOT0622” ③ sss[-2]+1 = *(sss–2)+1 = *(0x210 - 10)+1 = *(0x200) +1 = “XINZHIKE”+1 = “INZHIKE’’
- 未对sss/ss做出改变 ④*sss[-1]+3 = *(*(sss-1))+3 = *(*(3d0-8))+3 = *(3fe)+3= ‘H’+3=‘K‘
- 未对sss/ss做出改变 ⑤++*(sss–) = ++*(0x210) = ++( 0x114 ) = ” HINUX” + 1 = “INUX”
- sss的地址为 0x208
最后ss为{“XINZHIKE” “HOT0622” “INUX” “KAIKEBA” }
由于在①②⑤中有++或者–所以其操作是对sss本身进行的操作,其操作过后s二维数组发生了新的变化,而在③④无++或者–,对s[4][5]其自身没有变化,这就和值传递与地址传递的区别、形参使用普通类型和指针类型区别类似;a- 3和a+3中a的值是否改变一样
程序跑完的结果:
分析的结果与程序跑出来的结是相同的,在这个题目中弯弯绕绕比较多,必须一步步的分析才能得到答案