指针的概念
指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占据的内存区。所有指针在32位上都是4个字节,在64位系统是8个字节。
为什么要用指针
1)指针的使用使得不同区域的代码可以轻易的共享内存数据,这样可以使程序更为快速高效;
2)C语言中一些复杂的数据结构往往需要使用指针来构建,如链表、二叉树等;
3)C语言是传值调用,而有些操作传值调用是无法完成的,如通过被调函数修改调用函数的对象,但是这种操作可以由指针来完成,而且并不违背传值调用。
六大常用指针
int *arr; //单指针 int **arr; //双重指针,指向指针的指针 int (*arr)[3]; //数组指针,指向int型的的一维数组 int *arr[3]; //指针数组,该数组有3个元素,每个元素都是一个指向int型对象的指针 int (*arr)(int, int); //函数指针,指向一个有两个int参数的函数 int *arr(int, int); //指针函数,函数的返回类型为int型指针
技巧:是指针都是变量单独带括号,优先级:()>[]>*,后面以指针结尾,其就是指针。
怎么解析复杂指针?
右左法则:首先从最里面的圆括号(应该是未定义的标识符)看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。
int (*func)(int *p);
首先找到那个未定义的标识符,就是func,它的外面有一对圆括号,而且左边是一个*号,这说明func是一个指针,然后跳出这个圆括号,先看右边,也是一个圆括号,这说明(*func)是一个函数,而func是一个指向这类函数的指针,就是一个函数指针,这类函数具有int*类型的形参,返回值类型是 int。
int (*func)(int *p, int (*f)(int*));
func被一对括号包含,且左边有一个*号,说明func是一个指针,跳出括号,右边也有个括号,那么func是一个指向函数的指针,这类函数具有int *和int (*)(int*)这样的形参,返回值为int类型。再来看一看func的形参int (*f)(int*),类似前面的解释,f也是一个函数指针,指向的函数具有int*类型的形参,返回值为int。
int (*func[5])(int *p);
func右边是一个[]运算符,说明func是一个具有5个元素的数组,func的左边有一个*,说明func的元素是指针,要注意这里的*不是修饰 func的,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合,因此*修饰的是func[5]。跳出这个括号,看右边,也是一对圆括号,说明func数组的元素是函数类型的指针,它所指向的函数具有int*类型的形参,返回值类型为int。
int (* (*func) [5] ) (int *p);
func被一个圆括号包含,左边又有一个*,那么func是一个指针,跳出括号,右边是一个[]运算符号,说明func是一个指向数组的指针,现在往左看,左边有一个*号,说明这个数组的元素是指针,再跳出括号,右边又有一个括号,说明这个数组的元素是指向函数的指针。总结一下,就是:func是一个指向数组的指针,这个数组的元素是函数指针,这些指针指向具有int*形参,返回值为int类型的函数。
int (*(*func)(int *p))[5];
func是一个函数指针,这类函数具有int*类型的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。
int (*(*func)[5][6])[7][8];
func是一个指向数组的指针,这类数组的元素是一个具有5X6个int元素的二维数组,而这个二维数组的元素又是一个二维数组。typedef分解:
typedef int (*PARA)[7][8];
typedef PARA (*func)[5][6];
int (*(*(*func)(int *))[5])(int *);
func是一个函数指针,这类函数的返回值是一个指向数组的指针,所指向数组的元素也是函数指针,指向的函数具有int*形参,返回值为int。typedef分解:
typedef int (*PARA1)(int*);
typedef PARA1 (*PARA2)[5];
typedef PARA2 (*func)(int*);
int (*(*func[7][8][9])(int*))[5];
func是一个指针数组,这个数组的元素是函数指针,这类函数具有int*的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。typedef分解:
typedef int (*PARA1)[5];
typedef PARA1 (*PARA2)(int*);
typedef PARA2 func[7][8][9];
复杂指针的宏替换
过于复杂的指针,会给他人阅读代码带来麻烦,一般会使用宏定义来替换复杂的指针
举个例子:
//int *(*(*fun)(int*))[10]; typedef int *Arr[10]; typedef Arr*(pFun)(int*); Arr* myfun(int *) { static int a[10]={1,2,3,4,5,6,7,8,9,10}; static int* array[10]; for (int i = 0; i < 10; i++) { array[i]=&a[i]; } return &array; } void main() { pFun fun; fun=&myfun; }
同样,以下函数可以写为:
//int(*func)(int*,int(*),pFun pf); typedef int(*pFun)(int*); typedef int(*pFunType)(int*,pFun pf); pFunType func; //int (*func[5])(int *); typedef int (*pFun)(int *); pFun func[5]; //int (*(*func)[5])(int *); typedef int (*pFun)(int *); typedef pFun (*Func)[5]; Func func; //int (*(*func)(int *))[5]; typedef int *Ar[5]; typedef Ar *(*pFun)(int *); pFun fun; //int *(*func(int *))[5] typedef int *Ar[5]; Ar *func(int *);
野指针
不是NULL指针,是指向垃圾内存的指针
1.声明一个指针没有进行合法的初始化
2.free后,没有置NULL
指针与const
const int *p = &a; //p所指向的内容不能改变,指针可以改变 int const *p1 = &a; //p1所指向的内容不能改变,指针可以改变 int *const p2 = &a; //p2指针不能改变,内容可变 const int *const p3=&a; //p3指针不能改变,内容不能改变