精华篇:数组指针

一.数组指针

1.定义:

         数组指针,指的是数组名的指针,即数组首元素地址的指针。即是指向数组的指针。

         例:int (*p)[10]; p即为指向数组的指针,又称数组指针。

2.特性:

         数组指针用于指向一个数组,其本质为指针;

         ()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长也 就 是说执 行p+1时,p要跨过n个整型数据的长度。

         数组指针也叫行指针

3.二维数组指针:

         int (*p)[5]

         p是一个指针变量,它指向包含5个int元素的一维数组,此时p的增量以它所指向的一维数组长度为单位;

        *(p+i)是一维数组a[i][0]的地址;

        *(p+2)+3表示a[2][3]地址(第一行为0行,第一列为0列),*(*(p+2)+3)表示a[2][3]的值。

4.用法用例:

(1).一维数组指针

#include<stdio.h>

int main(){
    
    int a[12] = {10,20,30,40,50,60,70,80,90,100,110,120};
    
    int (*p_array)[12] = &a;                //指向一维数组的数组指针
                                            //a 是一个int [12] 类型的数组, 取它的地址初始化p_array. 值得注意的是此时数组名array不再表示数组首元素的地址.
    int *p = a;                                //指向一维数组元素的指针
    
    printf("%d\n",p[0]);
    printf("%d\n",*p_array[0]);
    
    printf("%d\n",a[1]);
    printf("%d\n",*(p + 1));
    printf("%d\n",p[1]);
    printf("%d\n",(*p_array)[1]);    
    printf("%d\n",p_array[0][1]);    
                                            /*
                                            (1) 二维数组实际上就是元素为一维数组的数组
                                            (2) 二维数组名可以看做指向其第一个元素(一维数组)的指针
                                            (3) 现在我们将array看作一个只有一个元素的二维数组,
                                            并且该二维数组的元素是 int [5] 类型的,
                                            显然arrayptr指向了该二维数组的第一个元素(相当于二维数组名)
                                            所以我们可以通过下标运算符 arrayptr[0]
                                            获得二维数组的第一个元素(实际上就是array数组),
                                            然后再次利用下标运算符 arrayptr[0][0] 获取array数组的第一个元素.
                                            注意到无法使用 arrayptr[1]是错误的, 因为该二维数组只有一个元素.
                                            */
    
    return 0;
}

 

(2).二维数组指针

#include<stdio.h>

int main(){
    
    int a[3][4] = {10,20,30,40,50,60,70,80,90,100,110,120};
    
    printf("%d\n",a[0][1]);
    int (*p_array)[4] = a;                //指向一维数组的数组指针 ,此时p_array指向的是a数组的第一个元素(元素是数组)
                                        //等价与 int* p_array = &a[0]
    printf("%d\n",p_array[0][1]);       //同理,p_array【0】指向的是 a[0][]这个数组
    printf("%d\n",(*p_array)[1]);       //[]的优先级要比*要高,所以要加括号
                                        /*在一维数组中,
                                        数组名表示的是数组第一个元素的地址,
                                        那么二维数组呢?
                                        a 表示的是元素 a[0][0] 的地址吗?
                                        不是!我们说过,二维数组就是一维数组,
                                        二维数组 a[3][4] 就是有三个元素 a[0]、a[1]、a[2] 的一维数组,
                                        所以数组 a 的第一个元素不是 a[0][0],
                                        而是 a[0],所以数组名 a 表示的不是元素 a[0][0] 的地址,而
                                        是 a[0] 的地址*/
                                        
    printf("%d\n",*((*p_array) + 1));   //a[0][]的地址的下一个地址自然就是a[0][1]了
    
                                        //那么我们要如何访问a[2][1]这个元素呢
                                        
    printf("%d\n",a[2][1]);
    printf("%d\n",p_array[2][1]);
    printf("%d\n",(*p_array)[9]);                        //从p_array[0][0]开始,第十个元素就是a[2][1] (2 * 4 + 2 = 10)
    printf("%d\n",*((*p_array) + 9));                     //等价上面的代码
    printf("%d\n",p_array[0][9]);                        //等价上面的代码
    printf("%d\n",(*(p_array + 2))[1]);                   //注意数组指针是行指针,他得改变是针对一个一维数组改变的
    printf("%d\n",*(*(p_array + 2) + 1));                 //*(p_array + 2)他表示的是a[2][0]的地址,它的下一个地址自然就是a[2][1]了
                                                        //从上面的代码中我们可以看得出,访问数组元素,要么用下标法,即[],要么用指针法
    printf("%d\n",((p_array + 1)[1])[1]);               //(p_array + 1)[1])等价与p_array[2]
    printf("%d\n",((p_array + 1) + 1)[0][1]);             //p_array + 2等价于a[2],第一个[0]位于内层数组标号,
                                                        //还是按行指针加法规则,意思是相对于a[2][]偏移0个行指针,即还是a[2][],
                                                        //第二个下标[1]    是行指针内的元素
    
    printf("%d\n",(*((p_array + 1) + 1))[1]);             //因为是行指针,所以最内层的p_array每加一按一个数组的长度加(即到了第三个数组,下标为2)
                                                        //等价与上面代码
    
    
    return 0;
}

 

关于指针数组,我们只需掌握一个规则:

(1).访问数组元素,要么用下标法 [],要么用指针*.

(2).一维数组用一个下标,二维数组用两个下标

(3).指针指向数组元素时,指针表示数组元素的地址,用 * 对这个地址运算就求出了这个地址(即数组元素)的值

(4).指针数组指向二维数组时,因为它本身是个指向数组的指针,所以它的内层每加一,就相当于下一个数组

          如 array[m][n],int (*p)[n] = a

          本来p是指向 a[0][] 这个数组的,*p 本身就相当于a[0],p[0]

          p + 1 就指向了二维数组的分数组的下一个数组,实际是 m + 1,即 p + 1 >> m + 1,*(p + 1) >> a[m + 1]

          而,如果想让数组指针指向当前分数组的下一个元素,我们需要让它的 n + 1

          即 (* p) + 1 == &a[0][1], *((*p) + 1) == a[0][1]

(5),我们回想一下,在

         int a[3][4]   ,int(*p)[4] = a

         中 a 代表 a分数组的第一个数组的地址,即 a >> &a[0],  而a[0] >> &a[0][0]

         所以  a 间接 与 &a[0][0],实际效果是相同的,但我们不能说它们等价,因为等价的意思是符号表达的意义是相同的

         但这里它们意义是不相同的,只能说它们的值相等

         而 我们说过,指针数组是指向数组首地址的指针,所以

         p >> a ,而 a >> &a[0], 所以, p >> &a[0]

         所以很自然的我们能够得出

         p[m] >> a[m], *p >> a[0] >> *a

         *(p + m) >> a[m] >> *(a + m),

         *(*(p + m) + n) >> (*(p + m))[n] >> a[m][n] >> p[m][n]

         <1>.第一步中的m,对于a来说,是a总数组的第m个分数组,

         但对于p来说,它是指指向当前数组的下m个数组的首地址,虽然它们等价,

         但是这实际上是因为沾了(数组内存是连续)的光,如果二维数组的分数组地址是不连续的,

         那么这个结论自然也就不成立,

         所以,即使它们等价,我们还是要理解的它们实际意义的区别

         <2>.从第一步以后的推论,我们可以发现一个重要的事情:

         p >> a

         即,是p的地方,我们就可以换成a

         是a的地方,我们就能换成p

         这是因为

         a 代表 &a[0],  p指向a中第一个分数组的首地址,即&a[0],

         注意是数组的首地址,不是数组第一个元素的首地址,即使它们的地址是相同的

         综上所述,虽然 p >> a,而且是完全等价,但是,我们还是要理解它们的区别

         因为对于

         a[m][n], int(*p)[n] = a

         这一切都是 a >> &a[0] 造成的影响

         若写成 p = &a[m], 你还懂么?

 

  • 26
    点赞
  • 131
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
C/C+语言struct深层探索............................................................................2 C++中extern "C"含义深层探索........................................................................7 C语言高效编程的几招...............................................................................11 想成为嵌入式程序员应知道的0x10 个基本问题.........................................................15 C语言嵌入式系统编程修炼...........................................................................22 C语言嵌入式系统编程修炼之一:背景............................................................22 C语言嵌入式系统编程修炼之二:软件架构........................................................24 C语言嵌入式系统编程修炼之三:内存操作..........................................................30 C语言嵌入式系统编程修炼之四:屏幕操作..........................................................36 C语言嵌入式系统编程修炼之五:键盘操作..........................................................43 C语言嵌入式系统编程修炼之六:性能优化..........................................................46 C/C++语言void及 void指针深层探索.................................................................50 C/C++语言可变参数表深层探索 .......................................................................54 C/C++数组名与指针区别深层探索 .....................................................................60 C/C++程序员应聘常见面试题深入剖析(1) ..............................................................62 C/C++程序员应聘常见面试题深入剖析(2) ..............................................................67 一道著名外企面试题的抽丝剥茧 ......................................................................74 C/C++结构体的一个高级特性――指定成员的位数 .......................................................78 C/C++中的近指令、远指针和巨指针 ...................................................................80 从两道经典试题谈C/C++中联合体(union)的使用......................................................81 基于ARM的嵌入式Linux移植真实体验................................................................83 基于ARM的嵌入式Linux移植真实体验(1)――基本概念...........................................83 基于ARM的嵌入式Linux移植真实体验(2)――BootLoader.........................................96 基于ARM的嵌入式Linux移植真实体验(3)――操作系统..........................................111 基于ARM的嵌入式Linux移植真实体验(4)――设备驱动..........................................120 基于ARM的嵌入式Linux移植真实体验(5)――应用实例..........................................135 深入浅出Linux 设备驱动编程.......................................................................144 1.Linux内核模块..............................................................................144 2.字符设备驱动程序 ...........................................................................146 3.设备驱动中的并发控制.......................................................................151 4.设备的阻塞与非阻塞操作.....................................................................15
嵌入式C/C++语言精华文章集锦 C/C+语言struct 深层探索............................................................................2 C++中extern "C"含义深层探索........................................................................7 C 语言高效编程的几招...............................................................................11 想成为嵌入式程序员应知道的 0x10 个基本问题.........................................................15 C 语言嵌入式系统编程修炼...........................................................................22 C 语言嵌入式系统编程修炼之一:背景............................................................22 C 语言嵌入式系统编程修炼之二:软件架构........................................................24 C 语言嵌入式系统编程修炼之三:内存操作..........................................................30 C 语言嵌入式系统编程修炼之四:屏幕操作..........................................................36 C 语言嵌入式系统编程修炼之五:键盘操作..........................................................43 C 语言嵌入式系统编程修炼之六:性能优化..........................................................46 C/C++语言 void 及void 指针深层探索.................................................................50 C/C++语言可变参数表深层探索.......................................................................54 C/C++数组名与指针区别深层探索.....................................................................60 C/C++程序员应聘常见面试题深入剖析(1) ..............................................................62 C/C++程序员应聘常见面试题深入剖析(2) ..............................................................67 一道著名外企面试题的抽丝剥茧 ......................................................................74 C/C++结构体的一个高级特性――指定成员的位数.......................................................78 C/C++中的近指令、远指针和巨指针...................................................................80 从两道经典试题谈 C/C++中联合体(union)的使用......................................................81 基于 ARM 的嵌入式Linux 移植真实体验................................................................83 基于 ARM 的嵌入式Linux 移植真实体验(1)――基本概念...........................................83 基于 ARM 的嵌入式Linux 移植真实体验(2)――BootLoader .........................................9
宋宝华嵌入式 C/C++语言精华文章集锦 C/C+语言 struct 深层探索 ............................................................................2 C++中 extern "C"含义深层探索........................................................................7 C 语言高效编程的几招...............................................................................11 想成为嵌入式程序员应知道的 0x10 个基本问题 .........................................................15 C 语言嵌入式系统编程修炼...........................................................................22 C 语言嵌入式系统编程修炼之一:背景 ............................................................22 C 语言嵌入式系统编程修炼之二:软件架构 ........................................................24 C 语言嵌入式系统编程修炼之三:内存操作 ..........................................................30 C 语言嵌入式系统编程修炼之四:屏幕操作 ..........................................................36 C 语言嵌入式系统编程修炼之五:键盘操作 ..........................................................43 C 语言嵌入式系统编程修炼之六:性能优化 ..........................................................46 C/C++语言 void 及 void 指针深层探索 .................................................................50 C/C++语言可变参数表深层探索 .......................................................................54 C/C++数组名与指针区别深层探索 .....................................................................60 C/C++程序员应聘常见面试题深入剖析(1) ..............................................................62 C/C++程序员应聘常见面试题深入剖析(2) ..............................................................67 一道著名外企面试题的抽丝剥茧 ......................................................................74 C/C++结构体的一个高级特性――指定成员的位数 .......................................................78 C/C++中的近指令、远指针和巨指针 ...................................................................80 从两道经典试题谈 C/C++中联合体(union)的使用 ......................................................81 基于 ARM 的嵌入式 Linux 移植真实体验 ................................................................83 基于 ARM 的嵌入式 Linux 移植真实体验(1)――基本概念 ...........................................83 基于 ARM 的嵌入式 Linux 移植真实体验(2)――BootLoader .........................................96 基于 ARM 的嵌入式 Linux 移植真实体验(3)――操作系统 ..........................................111 基于 ARM 的嵌入式 Linux 移植真实体验(4)――设备驱动 ..........................................120 基于 ARM 的嵌入式 Linux 移植真实体验(5)――应用实例 ..........................................135 深入浅出 Linux 设备驱动编程 .......................................................................144 1.Linux 内核模块..............................................................................144 2.字符设备驱动程序 ...........................................................................146 3.设备驱动中的并发控制 .......................................................................151 4.设备的阻塞与非阻塞操作 .....................................................................157

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT蓝月

谢谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值