一、用变量a给下面的定义:

1、定义一个整型数

int a;

2、定义一个指向整型数的指针

int *a;

3、定义一个指向指针的指针,它指向的指针是一个指向整型数指针

int **a;

4、定义一个有10个指针的数组,该指针是指向一个整型数的指针

int *a[10];

5、定义一个指向有10个整型数数组的指针

int (*a)[10];

6、定义一个指向函数的指针,该函数有一个整型参数,并返回一个整型数

int (*a)(int);

7、定义一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数,并返回一个整型数

int (*a[10])(int);


知识扩展:

右左法则:首先从未定义的标识符开始月的,然后从最里面的圆括号看起,然后往右看,再往左看。每当遇到圆括号时,就应该调转阅读方向。

如,int(*func)(int *p)

首先找到未定义的标识符func,它的外面有一对圆括号,而且左边是一个*号,这说明func是一个指针,然后跳出括号,先看右边,也是一个括号,这说明(*func)是一个函数,而func是一个指向这类函数的指针,就是一个函数指针,这类函数具有int *类型的形参,返回值类型是int

如,int(*func[5])(int *p)

func数组中有5个元素,每一个元素都是一个函数指针,每一个指针所指向的函数具有int*类型的形参,函数返回值类型是int

如,int(*(*func)[5]) (int *p)

首先,func是一个指针,跳出括号,右边是一个[]运算符,说明func是一个指向数组的指针,向左看,左边是*号,说明这个数组的元素是指针,再跳出括号,右边又是一个括号,说明这个数组的元素是指向函数的指针。总结一下,即func是一个指向数组的指针,这个数组的元素是函数指针,这些指针指向具有int*类型形参,返回值为int类型的函数。

如,int(*(*func)(int *p))[5];

func是一个函数指针,这类函数具有int*类型的形参,返回值是指向数组的指针,指向的数组的元素是5个int类型变量


二、指针加减操作

对指针进行加1操作,得到的是下一个元素的地址,而不是原有地址值直接加1。

所以,类型为t的指针的移动是以sizeof(t)为移动单位的。

如下例:

wKiom1ZMgeGSMdHOAAI7G0oSb0A974.png

首先,要先明白a+1 和 &a+1 的区别,或者说,a 和 &a的区别:

a是数组首地址,即数组第一个元素a[0]的地址;&a是对象首地址。

因此,

a+1是数组中第二个元素a[1]的地址。

而&a+1是 对象首地址+对象长度,即&a+sizeof(int)*5,也就是a[5]的地址,显然,当前&a+1已经越过了数组的界限。

(int*)(&a+1)则是把上一步计算出来的地址,强制转换为int*类型,并赋给指针ptr。

因此,第8行*(a+1)应是a[1]

第9行,*(ptr-1)应该是a[4]

所以,上述应输出:

2

5


三、指针比较

wKiom1ZMhPKyQgvhAAOfAqPYsWY324.png

数组str1 str2 str3 str4都是栈中分配的,内存中的内容都是"abc\0",但是他们的存储位置不同,因此第15和16行都输出0。

指针str5 str6 str7 str8也是栈中分配的,他们都指向abc这个字符串,abc存放于数据区,所以str5 str6 str7 str8都指向同一块数据区的内存,因此第17、18、19行都是输出1


四、指针常量和常量指针

指针常量:指针自身是一个常量,即它所指向的地址,一旦初始化,这个地址就固定了。但是它指向的地址中的内容是可以修改的。

常量指针:指向常量的指针,即它所指向的地址中的内容,是不能修改的。

例如:

char* const p1    指针常量,即p1本身是常量,但它指向的内容可以被修改

char const* p2    常量指针,即p2所指向的内容为常量

const char* p3    常量指针

const char* const p4    p4指针本身是常量,指向的地址中的内容也是常量


五、this指针

类的非静态成员函数属于类的对象,含有this指针,而类的static函数属于类本身,不含this指针。

即,类的非静态成员函数才有this指针。


六、指针数组和数组指针的使用

wKioL1ZNyzXw6dnIAAMQbh-G1Z0831.jpg

wKiom1ZNx_zyxMHqAALphmq4t_Y597.jpg

运行结果:

wKiom1ZNzBmTQf62AAJt3Y3Vc7Q377.jpg

分析:

str是个指针数组,数组中有4个元素,每一个元素都是一个指针,每一个指针都指向一个字符串

为了便于分析,我将所有的地址都打印出来了。

记四个字符串为A(代表Welcome),B(代表to),C(代表Fortemedia),D(代表Nanjing123)

第16行,char **p=str+1; 定义了一个指针的指针,p指向B,即当前的str[1]。

第19行,str[0]=(*p++)+2; 完成*p++后,p就指向C了,再加2,则str[0]就指向D后面的那个元素了,str[0]所指向的物理地址存在,但是地址中的内容,就为空了。

第23行,str[1]=*(p+1); str[1]指向D(相比较第16行而言,此时str[1]指向的内容已经刷新了),p仍旧指向C。而此时的p[0]即就是p,指向C,也可以说是p指向了str[2];那么p[1]就是指向D了,也可以说p[1]指向了str[3]。

这里有一个小说明:19行中*p++,*和++属于同一逻辑运算优先级,因此运算顺序为从右向左,因此先计算p++,然后再取值,因此p指向C;23行中*(p+1),其实效果跟*p++是一样了,先计算p+1,然后再取值;如果将这一样换为str[1]=*p+1; 那么str[1]就指向C字符串的第2个元素了,即Fortemedia中的'o'字母。

第29行,str[2]=p[1]+3; 前面已分析,p[1]指向D,则p[1]+3指向D的第4个元素,也就是字符串Nanjing123的'j'字母,那么str[2]也是指向'j'字母的。前面也分析过,p(或者说p[0])指向str[2],现在str[2]指向了j,那么p[0]最终指向的地址也就是j

第35行,str[3]=p[0]+(str[2]-str[1]); str[2]指向字符串D的字母j,str[1]指向字符串D的首字母,则str[2]-str[1]=3,所以str[3]=p[0]+3,即*p+3,即指向字符串D的字母g

相关地址操作细节可以参考程序输出的地址,慢慢参详。