常量指针
常量指针顾名思义就是一个指针,而此指针指向一个常量。所以指针所指向的内容不能改变,而他指向的地址可以改变,例如:
int a = 99,b;
const int *p=&a; //常量指针
//改变指针所指向的地址中所保存的值
*p = 88; //错误,指针所指向的值不能改变
//改变指针的值,即指针所指向的地址值(a)
p = &b; //正确,指针所指地址可以改变
我的理解:
const int *p = &a;
//首先声明了一个指针p指向&a,即int *p = &a,此时*p = a;
//然后用const来修饰了*p,即const (*p),我们可以这样理解:const int(*p)= &a,
//指针变量p指向&a,即p = &a;而指针*p = a,用const修饰*p,所以*p的值不能改变,即a不能变。
指针常量
指针常量:他就是一个常量,是用指针来修饰的。
int a,b;
int *const p=&a; //指针常量
*p = a; //正确,可以修改指针指向的地址中保存的数据
p = &b; //错误,指针是个常量,不可以改变指针值。
我的理解:
int *const p = &a;
//首先声明了一个指针p指向&a,即int *p = &a,此时*p=a,p=&a;
//其次用const对p进行了修饰,即const p,所以我们可以这样理解:int *(const p)=&a,
//由于const修饰的是p,所以p的值不能改变,即&a不能变,但是*p可以改变,即a可以变。
总结
对于指针常量和常量指针的区别,你可以观察在变量进行定义的时候,const在修饰谁,修饰的是p还是p,如果const修饰的是p则定义为const int *p;如果const修饰的是p,那定义为int *const p;
小技巧:在区分指针常量和常量指针的时候,可以按照const和*的先后顺序进行区分,const在前指针在后叫常量指针,const在后指针在前叫指针常量。谁在前面先读谁
数组指针
数组指针,实质上是一个指针,那么一个指针的值是什么呢?就是数组,所以在定义的时候要强调他是一个指针,则有如下定义:
int (*p)[n]; //指明指针p指向一个有n个元素的数组
//由于()的优先级高于数组[],所以用双括号来强调p是一个指针,然后用[n]来说明指针所指向的数是
//一个有n个int类型的数组
指针数组
指针数组,根据命名可知它是一个数组,那么数组的值是什么呢?那肯定就是指针了,所以在定义的时候要优先强调他是一个数组,由于[]的优先级大于*,所以不需要使用括号来进行特意说明,所以定义如下:
int *p[n]; //指明一个数组p,数组中的值是指针
//由于[]的优先级高于*,所以p此时是一个数组,然后用*来指定数组的值。
总结
在区分数组指针和指针数组的时候,关键要搞清楚 () , [ ] , * 这三个运算符之间的优先级,按照申明变量时候的优先级顺序进行区分和识别。
四种变量混合在一起
例:
int *const a[4]; //这是指针数组和指针常量?疑问???
//如果是指针数组的话,那么a[4]中存放的元素是指针
//如果是指针常量的话,那么a[4]中每个指针元素所指向的地址不能改变,但是地址中的元素可以改变
const int *a[4]; //这是指针数组和常量指针吗?疑问???
//指针数组的话,a[4]中存放的四个元素全部为指针
//常量指针的话,a[4]中四个指针元素所指向的地址值不能改变,但是指向的地址中的数据可以改变
以上能就是我一直不能分辨清楚的难点吧!混合之后到底a是代表什么呢?是指针常量数组和常量指针数组吗?
我的理解:
- 按照我前面的分析,int *const a[4]本质上是一个数组,然后用指针来描述了此数组,所以数组中存放的就是指针,最后用const来描述了a[4],这就是说明a[4]中的每个元素(指针所指的地址值)都是不可以改变的,也就是说a[0],a[1],a[2],a[3]不可以改变,但是指针所指向的内容可以改变。我这样理解对吗?
- const int *a[4]本质上也是一个数组,然后用指针描述,所以数组中存放的一样是指针,最后用const对*a[4]进行了一个总体的描述,可理解为const (*a[4]),所以a[0],a[1],a[2],a[3]中三个值可以改变,但是*a[0],*a[1],*a[2],*a[3]中的值不可以改变。
出于对以上问题的疑惑,编写了如下c程序进行验证
验证指针常量数组
1 /***********************************************
2 >File Name:time1.c
3 >Author:
4 >Email:
5 >Created Time:2019年03月28日 星期四 19时28分53秒
6 ***********************************************/
7
8 #include<stdio.h>
9 #include<stdlib.h>
10
11 int main()
12 {
13 int a[4] = {1,2,3,4};
14 int b[4] = {6,7,8,9};
15
16 int *const p[4] = {a,&a[1],&a[2],&a[3]}; //p数组中指针元素可以改变吗?
17 const int *q[4] = {&b[0],&b[1],&b[2],&b[3]}; //q数组中指针元素所指向的值可以改变吗?
18
19 if(a == p[0] && a+1 == p[1] && a+2 == p[2] && a+3 == p[3])
20 {
21 printf("p数组中存放的是a数组元素的地址,其值如下:\n");
22 printf("数组p中的值:p[1]:0x%08x p[2]:0x%08x p[3]:0x%08x p[4]:0x%08x\n",p[0],p[1],p[2],p[3]);
23 }
24 else
25 {
26 printf("数组中存放的不是a数组元素的地址\n");
27 exit(1);
28 }
29
30 if(b == q[0] && b+1 == q[1] && b+2 == q[2] && b+3 == q[3])
31 {
32 printf("q数组中存放的是b数组元素的地址,其值如下:\n");
33 printf("数组q中的值:q[1]:0x%08x q[2]:0x%08x q[3]:0x%08x q[4]:0x%08x\n",q[0],q[1],q[2],q[3]);
34 }
35 else
36 {
37 printf("数组中存放的不是b数组元素的地址\n");
38 exit(1);
39 }
40
41 printf("改变前的p数组指针元素指向的值为:%d,%d,%d,%d\n",*p[0],*p[1],*p[2],*p[3]);
42 *p[0] = b[0];*p[1] = b[1];*p[2] = b[2];*p[3] = b[3];
43 printf("改变后的p数组指针元素指向的值为:%d,%d,%d,%d\n",*p[0],*p[1],*p[2],*p[3]);
44
45 // p[0] = b;
46 // p[1] = b+1;
47 exit(0);
48
49 }
运行结果:
可以看到*p[n]的值可以改变,即直接操作数组p[n]的指针元素所指向的数值是可以的,p[n]的值没有改变,仍然是&a[n],*p[n]的值从a[n]变为了b[n];另外也可以得出结论二:由于&a[n]没有改变,但是&a[n]地址中存的值发生了改变,所以数组a的值肯定也会改变(可自行验证)
添加代码中的注释部分 p[0] = b; p[1] = b+1;
之后,再次运行,结果报错:
报错说向只读位置赋值,说明p[0],p[1],p[2],p[3]都是只读的,即数组p中的元素不可以改变,就是p[n]不能改变,但是数组元素p[0],p[1],p[2],p[3]所指向的值可以改变,即*p[n]的值可以改变。
总结
指针常量数组 ⟶ \longrightarrow ⟶ int *const p[4],*p[n]的值可以改变,p[n]的值不可以改变,因为const修饰的是p[],所以数组p的元素是不可以改变的。
验证常量指针数组的属性
1 /***********************************************
2 >File Name:time3.c
3 >Author:
4 >Email:
5 >Created Time:2019年03月28日 星期四 19时28分53秒
6 /***********************************************/
7
8 #include<stdio.h>
9 #include<stdlib.h>
10
11 int main()
12 {
13 int a[4] = {1,2,3,4};
14 int b[4] = {6,7,8,9};
15
16 int *const p[4] = {a,&a[1],&a[2],&a[3]}; //p数组中指针元素可以改变吗?
17 const int *q[4] = {&b[0],&b[1],&b[2],&b[3]}; //q数组中指针元素所指向的值可以改变吗?
18
19 if(a == p[0] && a+1 == p[1] && a+2 == p[2] && a+3 == p[3])
20 {
21 printf("p数组中存放的是a数组元素的地址,其值如下:\n");
22 printf("数组p中的值:p[1]:0x%08x p[2]:0x%08x p[3]:0x%08x p[4]:0x%08x\n",p[0],p[1],p[2],p[3]);
23 }
24 else
25 {
26 printf("数组中存放的不是a数组元素的地址\n");
27 exit(1);
28 }
29
30 if(b == q[0] && b+1 == q[1] && b+2 == q[2] && b+3 == q[3])
31 {
32 printf("q数组中存放的是b数组元素的地址,其值如下:\n");
33 printf("数组q中的值:q[1]:0x%08x q[2]:0x%08x q[3]:0x%08x q[4]:0x%08x\n",q[0],q[1],q[2],q[3]);
34 }
35 else
36 {
37 printf("数组中存放的不是b数组元素的地址\n");
38 exit(1);
39 }
40
41 printf("\n改变前的q数组指针元素指向的值为:%d,%d,%d,%d\n",*q[0],*q[1],*q[2],*q[3]);
42 q[0] = a; q[1] = a+1; q[2] = a+2; q[3] = a+3;
43 printf("改变后的q数组指针元素指向的值为:%d,%d,%d,%d\n",*q[0],*q[1],*q[2],*q[3]);
44
45 // *q[0] = b[0];
46 // *q[1] = b[1];
47 // *q[2] = b[2];
48 // *q[3] = b[3];
49 exit(0);
50
51 }
运行结果:
可以看到运行结果正常,q[0-3]的值开始为指向b数组元素的指针,即q[n]=&b[n],其后改变q[n]的指向,使它指向a数组元素,q[n]=&a[n],编译没有报错,并且输出结果正确。p[n]的值可以改变,相应的*(p[n])的值也改变。
注释部分添加到代码中
可以看到编译没有通过,报错明确说明*q[n]为只读位置,不可以赋值,由此可以看出常量指针数组的数组元素值可以改变,但是数组元素指向的值不能改变。
总结
常量指针数组 ⟶ \longrightarrow ⟶ const int * q[4],p[n]的值可以改变,*p[n]的值不可以改变,因为const修饰的是* p[],所以数组p的元素是可以改变的,但是数组元素所指向的值不可以改变。
附录代码
如下是另外一个测试代码,把指针常量数组和常量指针数组当作函数形参如何用?会不会改变实参的数组值?
1 /***********************************************
2 >File Name:time.c
3 >Author:
4 >Email:
5 >Created Time:2019年03月28日 星期四 10时57分30秒
6 /**********************************************/
7
8 #include<stdio.h>
9 #include<stdlib.h>
10 #include<time.h>
11
12 void time_print(char *const []);
13 void time_print1(const char * []);
14 void time_print2(char * (*)[3]);
15
16 int main()
17 {
18 // time_t t;
19 // struct tm *local;
20 // struct timeval timeday;
21 // struct timezone time
22 //
23 // t = time(NULL);
24 // local = gmtime(&t);
25 // printf("local time(UTC) is %d-%d-%d %d:%d:%d\n",(local->tm_year+1900),local->tm_mon+1,local->tm_mday,local->tm_hour,local->tm_min,local->tm_sec);
26 // printf("ctime func time is %s",ctime(&t));
27 // printf("asctime func time is %s",asctime(local));
28
29 char * date[]={"1996","April","25"};
30 const char *date1[]={"1996","April","25"};
31
32 time_print(date);
33 printf("date num:%s,%s,%s\n",date[0],date[1],date[2]);
34 printf("-----------------------------------------\n");
35 time_print1(date1);
36 printf("date num:%s,%s,%s\n",date[0],date[1],date[2]);
37 printf("-----------------------------------------\n");
38 time_print2(&date);
39 printf("date num:%s,%s,%s\n",date[0],date[1],date[2]);
40
41
42 exit(0);
43 }
44 void time_print(char * const time[])
45 {
46 printf("time array:%s,%s,%s\n",time[0],time[1],time[2]);
47 printf("addr &time[0]=0x%08x,&time[1]=0x%08x,&time[2]=0x%08x\n",&time[0],&time[1],&time[2]);
48 printf("addr time=0x%08x\n",time);
49 char * time_change[]={"1994","June","23"};
50 time = time_change;
51 printf("Change array:%s,%s,%s\n",time[0],time[1],time[2]);
52 printf("addr &time[0]=0x%08x,&time[1]=0x%08x,&time[2]=0x%08x\n",&time[0],&time[1],&time[2]);
53 printf("addr time=0x%08x\n",time);
54 // time[0] = "1995"; //time[]数组形参中的每个元素都是指针常量,所以不能直接改变每个元素的指向,但是可以每个元素指针所指的地址内容
55 // time[1] = "May";
56 // time[2] = "24";
57
58 // time[0] =
59 // printf("Change num:%s,%s,%s\n",time[0],time[1],time[2]);
60
61 }
62
63 void time_print1(const char * time[])
64 {
65 printf("time array:%s,%s,%s\n",time[0],time[1],time[2]);
66 printf("addr &time[0]=0x%08x,&time[1]=0x%08x,&time[2]=0x%08x\n",&time[0],&time[1],&time[2]);
67 const char * time_change[]={"1994","June","23"};
68 time = time_change;
69 printf("Change num:%s,%s,%s\n",time[0],time[1],time[2]);
70 printf("addr &time[0]=0x%08x,&time[1]=0x%08x,&time[2]=0x%08x\n",&time[0],&time[1],&time[2]);
71 time[0] = "1995"; //
72 time[1] = "May";
73 time[2] = "24";
74 printf("Change num:%s,%s,%s\n",time[0],time[1],time[2]);
75 }
76
77 void time_print2(char * (*time)[3])
78 {
79 printf("time array:%s,%s,%s\n",(*time)[0],(*time)[1],(*time)[2]);
80 printf("addr *&time[0]=0x%08x,*&time[1]=0x%08x,*&time[2]=0x%08x\n",&((*time)[0]),&((*time)[1]),&((*time)[2]));
81 (*time)[0] = "1995"; //
82 (*time)[1] = "May";
83 (*time)[2] = "24";
84 printf("Change num:%s,%s,%s\n",(*time)[0],(*time)[1],(*time)[2]);
85 char * time_change[]={"1994","June","23"};
86 time = &time_change;
87 printf("Change num:%s,%s,%s\n",(*time)[0],(*time)[1],(*time)[2]);
88 printf("addr *&time[0]=0x%08x,*&time[1]=0x%08x,*&time[2]=0x%08x\n",&((*time)[0]),&((*time)[1]),&((*time)[2]));
89 }
90