一、用变量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)为移动单位的。
如下例:
首先,要先明白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
三、指针比较
数组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指针。
六、指针数组和数组指针的使用
运行结果:
分析:
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
相关地址操作细节可以参考程序输出的地址,慢慢参详。
转载于:https://blog.51cto.com/tangxiaoguo/1714834