• C语言-数组指针与指针数组


    一、简介

            对于使用C语言开发的人来说,指针,大家都是非常熟悉的。数组,大家也同样熟悉。但是这两个组合到一起的话,很多人就开始蒙圈了。这篇文章,就详细的介绍一下这两个概念。

            指针数组数组指针,听起来非常像,但是两者是完全不同的概念。从名字上就可以知道,一个是数组一个是指针

            那如何区分呢?

            最简单的方法,就是根据语句中符号的优先级来。

            优先级关系:( ) > [ ] > *

            有了这个概念后,我们再来看如下两个定义:

    1. int *a[4];
    2. int (*a)[4];

            *a[4]语句中,因为优先级[ ] > *。所以,[ ]就是这个变量的“根”,即数组才是这个变量的本质。所以*a[4]就是数组。因为该数组前面加了取址符 * ,所以,它就是指针数组

            (*a)[4]语句中,因为优先级() > [],所以先看括号内的东西,是*a。这个一看就知道是个指针,所以,这个变量的本质就是个指针。又因为这个指针后面加了[ ]。所以,它是数组指针

            一句话,谁不重要,谁是定语。(中文语法不好的,回去补一补!)人话就是:本质是什么,最后两个字就是什么

            *a[4]本质是数组,那就是指针数组(*a)[4]本质是指针,那就是数组指针

            好啦,概念搞懂了,接下来就是看看其含义了。

            int *a[4]是个数组,那就要干数组的活指针数组的意思就是,这个数组里面的元素都是指针指针的类型是int,指向的内容也是int型

            int (*a)[4]是个指针,那就要干指针的活数组指针的意思就是,这个指针,指向了长度为4的数组这个数组的类型是int型

            好了,含义的概念也说完了。是不是感觉还是不懂。没关系,接下来用实例来对以上两个东西介绍一下。

    二、指针数组

            在上面的文章中说过,指针数组的本质是数组,数组内的元素都是指针。看如下这个例子

    1. char a[] = "123";
    2. char b[] = "456";
    3. char c[] = "789";
    4. char d[] = "012";
    5. char *p[4];
    6. p[0] = a;
    7. p[1] = b;
    8. p[2] = c;
    9. p[3] = d;

            这里定义了一个指针数组char *p[4]。数组内的元素都是指针,所以,把abcd四个地址赋值给指针。

            上面的写法可以用下面这个写法来代替。

    char *p[4] = {“123”,“456”,“789”,“012”};

            那以如下的例子来详细讲解一下

    1. char a[] = "123";
    2. char b[] = "456";
    3. char c[] = "789";
    4. char d[] = "012";
    5. char *p[4];
    6. LOG_I(TAG,"&p[0] = %d, &p[1] = %d, &p[2] = %d, &p[3] = %d",p[0], p[1], p[2], p[3]);
    7. p[0] = a;
    8. p[1] = b;
    9. p[2] = c;
    10. p[3] = d;
    11. LOG_I(TAG,"&a = %d, &b = %d, &c = %d, &d = %d",a, b, c, d);
    12. LOG_I(TAG,"&p[0] = %d, &p[1] = %d, &p[2] = %d, &p[3] = %d",p[0], p[1], p[2], p[3]);
    13. LOG_I(TAG,"p = %d, *p = %d, *(p+1) = %d, *(*(p+1)) = %c, *(*p+1) = %c, **p = %c",p, *p, *(p+1), *(*(p+1)), *(*p+1), **p);
    14. LOG_I(TAG,"p[0] = %s, p[1] = %s, p[2] = %s, p[3] = %s",p[0], p[1], p[2], p[3]);

            先看结果

             可以看到,在赋值之前,p[0],p[1],p[2],p[3]的地址都是指向乱地址。赋值之后,地址就与abcd相同。

           从上面的打印,我们可以看到,p与abcd变量的地址都不相同按照数组的概念来说的话,数组p的地址应该与首元素相同。但是这里却不同,相反,*p的内容却与a变量的地址相同。由此我们可以得到如下结论,p实际上是一个地址的地址。而其内容才是元素的地址。再看**p的内容,是1。元素的内容为1,即指向a数组的内容。与我们的结论相同。

            这里需要注意的是 *(p+1) , *(*(p+1)) , *(*p+1)。

            刚才我们得到结论,p实际是一个地址的地址而*p[4]的本质还是一个数组,那么p+1,实际上是指向了第二个元素地址的地址。取内容就是第二个元素的地址。从打印内容可以看到*(p+1)与第二个元素b的地址是相同的。

            有了上面的结论,那就可以推断出, *(*(p+1))就是第二个元素的内容。从打印上可以看到,打印的结果是4,与b数组的第一个元素是能对应上的。

            至于*(*p+1),上面结论是,*p是a数组的地址,其地址+1再取值,即a数组的第二个元素。其打印结果为2,也与结论相对应。

            最后,打印各个元素指针所指向的内容,也就是abcd四个数组的内容。

            因为p是数组,所以不能执行p++的操作

            说了这么多,可能会有人问,指针数组一般用在哪里

            比如说,我们在编程的时候某些地方需要做寻址操作,例如汉字或语音的寻址。因为这些内容的地址是不连续的,但是又不可能每次都去调用寻址。那么就可以一个指针数组,该数组内的指针元素对应各个不同地址的内容。后续我们只需要调用这个指针数组的各个元素,就能调用到不同的地址内容。同样的,这个指针数组各个元素也可以是函数指针,这样,就在同一个数组内,调用不同的回调函数,非常方便。

    三、数组指针

            数组指针的本质是指针指向一个数组

            数组指针一般与二维数组配合使用。见如下例子

    1. int (*p)[5];
    2. int a[3][5] = {{1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15}};
    3. p = a;
    4. LOG_I(TAG,"&a[0] = %d, a[0] = %d, &a[1] = %d, a[1] = %d, &a[2] = %d, a[2] = %d",&a[0], a[0], &a[1], a[1], &a[2], a[2]);
    5. LOG_I(TAG,"&a = %d,&p = %d, p = %d, *p = %d, *(p+1) = %d, *(*(p+1)) = %d, *(*p+1) = %d, **p = %d",&a, &p, p, *p, *(p+1), *(*(p+1)), *(*p+1), **p);
    6. p++;
    7. LOG_I(TAG,"&a = %d,&p = %d, p = %d, *p = %d, *(p+1) = %d, *(*(p+1)) = %d, *(*p+1) = %d, **p = %d",&a, &p, p, *p, *(p+1), *(*(p+1)), *(*p+1), **p);

            先看结果

            先创建一个数组指针(*p)[5]。这个指针指向长度为5的数组

            把a的地址赋值给数组指针p。

            跟一般的指针一样,&p与p是不同的。但是这里可以发现p与*p相同。一般来说,对于指针而言,p是地址,而*p是该地址的内容。这里看到p与*p相同,且都与a数组的地址相同。这里可以按照数组a与&a理解

            *(p+1)。与正常的指针一样,p+1即移动到下一个地址,不同的是因为该数组指针指向的是一个长度为5的数组,所以p+1则直接移动5个元素的长度。从打印的结果中也可以看到*(p+1)与 a[1]的地址相同

            *(*(p+1))。上述结论中,*(p+1)表示二维数组a[1]的地址,那么取值就是取该数组的值。为6.

            *(*p+1)。上述结论中,*p是二维数组a[0]的地址,那么*p+1则为a[0]数组的第二个元素的地址。*(*p+1)则表示取值,为2。

            **p。上述结论中,*p是二维数组a[0]的地址,那么*p则为a[0]数组的第一个元素的地址。**p则表示取值,为1。

            因为p的本质是个指针,那么是可以进行p++的操作的。p++将直接移动到数组长度的位置,即从a[0]直接移动到a[1]。所以**p的值为6。

  • 相关阅读:
    【JVM】年轻代进入老年代规整
    服务器如何防御攻击,有哪些方法
    Linux 系统如何设置开机程序自启动
    Git命令快速入门(建议收藏)
    c++ 学习 之 const,constexpr,volatile
    039-java集合框架的作用及使用(Collection,Set,Map,SimpleDateFormat)
    python难题切片处理
    对话句子互动创始人李佳芮 | AIGC结合私域运营影响不可估量
    Studio One6.5最新中文版安装步骤
    设计模式之装饰器模式
  • 原文地址:https://blog.csdn.net/qq_26226375/article/details/136259153