您的位置:首页 > 其它

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

2019-03-28 18:04 344 查看

文章目录

  • 数组指针
  • 指针数组
  • 四种变量混合在一起
  • 验证常量指针数组的属性
  • 附录代码
  • 常量指针

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

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

    我的理解:

    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
    的指针元素所指向的数值是可以的,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
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: 
    相关文章推荐