常量指针、指针常量、指针数组和数组指针混搭后会是什么效果?混搭后如何使用和理解的思考
文章目录
常量指针
常量指针顾名思义就是一个指针,而此指针指向一个常量。所以指针所指向的内容不能改变,而他指向的地址可以改变,例如:
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个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
的值可以改变,即直接操作数组p
的指针元素所指向的数值是可以的,p
的值没有改变,仍然是&a
,*p
的值从a
变为了b
;另外也可以得出结论二:由于&a
没有改变,但是&a
地址中存的值发生了改变,所以数组a的值肯定也会改变(可自行验证)
添加代码中的注释部分
p[0] = b; p[1] = b+1;之后,再次运行,结果报错:
报错说向只读位置赋值,说明p[0],p[1],p[2],p[3]都是只读的,即数组p中的元素不可以改变,就是p
不能改变,但是数组元素p[0],p[1],p[2],p[3]所指向的值可以改变,即*p
的值可以改变。
总结
指针常量数组 ⟶\longrightarrow⟶ int *const p[4],*p
的值可以改变,p
的值不可以改变,因为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
=&b
,其后改变q
的指向,使它指向a数组元素,q
=&a
,编译没有报错,并且输出结果正确。p
的值可以改变,相应的*(p
)的值也改变。
注释部分添加到代码中
可以看到编译没有通过,报错明确说明*q
为只读位置,不可以赋值,由此可以看出常量指针数组的数组元素值可以改变,但是数组元素指向的值不能改变。
总结
常量指针数组 ⟶\longrightarrow⟶ const int * q[4],p
的值可以改变,*p
的值不可以改变,因为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
- 什么是指针?如何理解指针?指针又是如何定义与使用的?
- 使用快速排序算法对字符串数组进行排序(复习指向指针的指针以及指针数组的使用)
- C语言的函数中,如何使用指针交换两个数的值,深入理解指针
- 指针数组 与 数组指针 的理解
- java面向对象,什么是对象,什么是类,如何理解,怎么使用
- 你对MVC的理解,MVC有什么优缺点?结合Struts,说明在一个Web应用如何去使用?
- 数组指针和指针数组的使用
- 【指针数组和数组指针的使用】
- 根据一段代码理清一些变量,常量,数组,指针的关系及理解
- C-036.字符数组与字符指针,它们的使用场景是什么?
- 如何使用指针从函数返回一个数组。
- 理解 指针数组 数组指针 函数指针 函数指针数组 指向函数指针数组的指针
- 什么是指针?关于指针的数组,数组指针,函数指针,函数指针数组,指向函数指针数组的指针的理解
- 理解函数指针数组和定义,转移表 理解指向函数指针数组的指针和定义 理解回调函数的使用 (最易理解版)
- C语言学习笔记(6)-如何从变量声明的表面上来区分指针数组和数组指针
- 二维数组做函数参数,如何将三维数组降为二维数组,指向数组的指针的使用
- 指针数组和数组指针分别是如何指向二维数组的
- 指针数组和数组指针的使用
- C++中常量指针,指针常量(const 和*)的使用方法和理解方法
- 【练习1】输出一个螺旋数组,可以很好地理解数组和指针的使用