一.指针数组和数组指针
分析指针数组和数组指针的表达式
int *p[5]; int (*p)[5]; int *(p[5]);
总结:我们在定义一个符号时,关键在于:首先要搞清楚你定义的符号是谁(第一步:找核心);其次再来看谁跟核心最近、谁跟核心结合(第二步:找结合);以后继续向外扩展(第三步:继续向外结合直到整个符号完)。
例如:核心是指针,就表示该结合是什么什么的指针。
如果核心和*结合,表示核心是指针;如果核心和[ ]结合,表示核心是数组;如果核心和()结合,表示核心是函数
记住以下符号优先级即可([ ] . ->),优先级都是高的
int *p[5]; //p是一个数组,数组有5个元素,数组元素都是指针,指针指向的元素类型是int类型的;整个符号是一个指针数组
int (*p)[5]; //核心是p,p是一个指针,指针指向一个数组,数组有5个元素,数组中存的元素是int型;总结下整个符号的意义就是数组指针。
总结:
1.优先级和结合性是分析符号意义的关键
2.学会逐层剥离的分析方法
找到核心后从内到外逐层的进行结合,结合之后可以把已经结合的部分当成一个整体,再去和整体外面的继续进行结合。
二.函数指针与typedef
1.
1.1 函数指针的实质还是指针,还是指针变量。本身占4字节(32位系统中,所有的指针都是4字节)
1.2 函数指针、数组指针、普通指针之间并没有本质区别,区别在于指针指向的东西是什么
1.3 函数的实质是一段代码,这一段代码在内存中是连续分布的(一个函数的大括号括起来的所有语句将来编译出来生成的可执行程序是连续的),所以对于函数来说很关键的就是函数中的第一句代码的地址,这个地址就是所谓的函数地址,在C语言中用函数名这个符号来表示。
1.4结合函数的实质,函数指针其实就是个普通变量,这个普通变量的类型是函数指针变量类型,它的值就是某个函数的地址(也就是它的函数名这个符号在编译器中对应的值)
2.
2.1函数指针的书写和分析方法
假设我们有个函数是:void func(void);
对应的函数指针:void (*p)(void);
类型是:void(*)(void);
如果核心和*结合,表示核心是指针;然后指针和()结合,表示是函数指针
函数名和数组名最大的区别就是:函数名做右值时加不加&效果和意义都是一样的;但是数组名做右值时加不加&意义就不一样
。
3.typedef
3.1
一般用于用户自定义类型,如数组指针、指针数组、函数指针等都属于用户自定义类型
typedef一般给类型重命名,也就是说typedef加工出来的都是类型,而不是变量
如:
typedef char* (*pType)(char *,const char *);
//这句重命名了一种类型,这个新类型名叫pType,类型是:char* (*)(char *,const char *);
//函数指针数组
typedef char* (*pType[5])(char *,const char *);
//函数指针数组指针
typedef char* (*(*pType)[5])(char *,const char *);
总结:函数指针分析方法也是源于优先级和逐层剥离的基本理论,同上
3.2
typedef和const
typedef int *p; const p p2; 相当于是int *const p2;
typedef int *p; p const p2; 相当于是int *const p2;
3.3
typedef和#define
typedef char *pStr1;
#define pStr2 char *;
pStr1 s1, s2;
pStr2 s3, s4;
在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们
所预期的指针变量,根本原因就在于
define只是简单的字符串替换而typedef则是为一个类型起新名字
4.
结构体内嵌函数指针实现代码分层,内核基本使用该方式实现
4.1
分层后上层为下层提供服务,上层写的代码主要是为了在下层中被调用
4.2
上层注重业务逻辑,与我们最终的目标相直接关联,而没有具体干活的函数
4.3
下层代码中的核心是一个结构体变量,写下层代码的逻辑其实很简单。第一步先定义结构体变量;第二步填充结构体变量;第三步调用上层写好的接口函数,把结构体变量传给它即可。
三.二维数组的运算和指针(配图)
3.1指针指向二维数组的数组名
3.1.1 二维数组的数组名表示二维数组的第一维数组中首元素(也就是第二维的数组)的首地址
3.1.2 二维数组的数组名a等同于&a[0],这个和一维数组的符号含义是相符的
3.1.3 用数组指针来指向二维数组的数组名是类型匹配的
a[i][j] = *(*(p+i)+j)
int a[2][5];
int (*p3)[5]; //数组指针,指向一个数组,数组有5个int型元素,
p3 = a; //a是二维数组的数组名,作为右值表示二维数组第一维的数组的首元素首地址,等同于&a[0]
p3 = &a[0];
printf("a[0][3] = %d\n",*(*(p3+0)+3));
printf("a[1][4] = %d\n",*(*(p3+1)+4));
3.2指针指向二维数组的第一维
3.2.1 用 int *p来指向二维数组的第一维a[i]
int *p4 = a[0]; //a[0]表示二维数组的第一维的第一个元素,相当于是第二维的整体数组的数组名。数组名又表示数组首元素的首地址,因此a[0]等同于&a[0][0]
int *p5 = &a[0][0];
3.3指针指向二维数组的第二维
二维数组的第二维元素其实就是普通变量了,已经不能用指针类型匹配了
总结:二维数组和指针的纠葛,关键点
1.数组中各个符号的含义
2.数组的指针式访问,尤其是二维数组的指针式访问