相信每一个C++学习者都被C++的typedef const 数组 函数 指针之间的花式组合抓狂过,这都是啥?于是开个坑记录下C++指针识别的一些技巧和坑点。
还在不断更新中......
const和指针识别
const和指针的组合识别可以这样:看const的右边是谁,右边是谁const就是修饰谁,
const int *p=&a; //这里const右边是int,代表修饰的是常量,p是指向一个常量的指针,p指针本身能修改但其指向一个常量不能修改
int * const p=&a; //这里const右边是p,代表修饰的是指针p,那么p是一个常指针,即p本身不能改变了,但是可以通过p改变其指向的值
值得注意的是上诉的第一种还可以写成:int const* p=&a;这种写法看起来是一个不能改变的常指针,但是其实它应该是和第一种写法相同含义的,这种写法容易混淆,我们更推荐使用上面第一种写法。
关于const和指针的识别还有一种办法:看const和*号的位置,const在左边是指向常量的指针,const在右边是常指针。
坑点:typedef char* ptr; const ptr cstr; (ptr const cstr;)
解答:看起来应该是 const char* cstr; 指向常量的指针。其实不是,此时const修饰的是ptr,ptr是一个指针,所以实际上cstr是一个指向char的常指针。即等于char * const cstr;
那么const ptr *cstr;这又是什么呢? 首先cstr是一个指针,它指向另一个指针,指向的指针是一个指向char的常指针。
数组指针与指针数组
这分辨这两个区别值钱,必须先清楚,数组名本身就是一个指针,指向数组首元素地址。
数组指针①:int (*p)[n]; 首先观察这个括号,括号优先级高代表p首先是一个指针,然后p指向一个长度为n的整型一维数组。
指针数组②:int *p[n]; 这里没有小括号了,那么[]优先级高,即p首先是一个长度为n的数组,然后有*,那么p数组是一个指针数组,即其每一个元素都是一个 整型指针。
① int a[3][4]; int (*p)[4]; p=a; p++;
注意观察,首先a是二维数组每一行长度为4,然后p是一个数组指针它指向长度为4的一维数组,那么p=a时候(相当于p=a[0] / p=&a[0][0]),p++过后p就跨过一行(a[0]这一行)指向了a[1]。
可以理解为这里的p是只有一个指针,孤军奋战内存中只有一个位置。
② int a[3][4]; int *p[3]; for (int i=0;i<3;i++) p[i]=a[i];
首先a还是一个3行4列的数组,p是一个指针数组,其每一个元素都是一个指针,所以经过for循环之后,p[0]指向了a数组第0行首地址,p[1]指向a数组第1行首地址......
可以理解为此时p是一个数组,他在内存中有4个位置,每一个都是指针类型。
函数指针
函数指针有什么用?函数指针指向函数地址,可以通过函数指针调用函数。简单用法示例:
int add(int a,int b); //首先我们有一个函数
int (*pf) (int,int); //其次我们有一个指针pf,pf是一个函数指针它可以指向一个函数,指针未初始化。注意观察:pf右边是参数列表(int,int),pf左边是函数返回值int。亦即pf可以指向一个参数列表为(int,int)返回值为int的函数。add是满足条件的函数。
pf=add; //上面分析过了,pf是可以指向add函数的。
pf(a,b) //此时pf和add无差别了,都是调用这个函数。
注意pf两边的括号不能省略,否则变成返回值为int *类型的函数,函数名为pf。
typedef int (*PF) (int,int) ; PF pf;
上面这个用法即先typedef PF为一个函数指针类型,之后可以用PF去定义别人。
函数指针不仅仅是像上面那样起到起别名的作用,还可以把函数指针当作函数参数传给函数:
比如有几个函数参数列表如下: void func(int a,int (*pf) (int,int) ); void func(int a,PF);
如果此时pf=add; 那么就可以之间把pf传过去:func(a,pf); 这相当于func(a,add);
decltype关键字:
参考资料:
《C++Primer第五版》