常量指针、指针常量、指针数组和数组指针混搭后会是什么效果?混搭后如何使用和理解的思考

常量指针

常量指针顾名思义就是一个指针,而此指针指向一个常量。所以指针所指向的内容不能改变,而他指向的地址可以改变,例如:

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是代表什么呢?是指针常量数组和常量指针数组吗?

我的理解:

  1. 按照我前面的分析,int *const a[4]本质上是一个数组,然后用指针来描述了此数组,所以数组中存放的就是指针,最后用const来描述了a[4],这就是说明a[4]中的每个元素(指针所指的地址值)都是不可以改变的,也就是说a[0],a[1],a[2],a[3]不可以改变,但是指针所指向的内容可以改变。我这样理解对吗?
  2. 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[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    
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言中,指针数组数组指针都是指针数组的组合,但是它们的含义和用法是不同的。 指针数组是一个数组,其中每个元素都是一个指针。它的定义形式为:`type *array_name[size]`,其中`type`是指针指向的数据类型,`array_name`是数组的名称,`size`是数组的大小。例如,`int *ptr_arr[5]`就是一个包含5个`int`指针数组数组指针是一个指针,它指向一个数组。它的定义形式为:`type (*ptr_name)[size]`,其中`type`是数组元素的数据类型,`ptr_name`是指向数组指针,`size`是数组的大小。例如,`int (*ptr_arr)[5]`就是一个指向包含5个`int`元素的数组指针。 区别在于,指针数组是一个数组,它的每个元素都是一个指针,而数组指针是一个指针,它指向一个数组。因此,指针数组可以通过索引访问每个元素,每个元素都是一个指针,它可以指向不同类型的数据。而数组指针可以通过指针运算访问数组中的元素,因为它指向的是一个数组,它只能指向相同类型的数组。 举个例子,如果有一个`int`类型的数组`arr`,那么可以定义一个指针数组来保存每个元素的指针: ``` int arr[5] = {1, 2, 3, 4, 5}; int *ptr_arr[5]; for (int i = 0; i < 5; i++) { ptr_arr[i] = &arr[i]; // 获取每个元素的指针 } ``` 也可以定义一个数组指针来指向整个数组: ``` int arr[5] = {1, 2, 3, 4, 5}; int (*ptr_arr)[5]; ptr_arr = &arr; // 获取整个数组指针 ``` 总的来说,指针数组数组指针都是非常常用的数据结构,但它们的用法和定义有所不同,需要根据实际情况选择使用哪种数据结构。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值