指针数组、数组指针——用指针访问数组方法总结

2023-05-16

目录

1.数组元素的访问

2.通过指针访问数组

2.1 通过指针访问一维数组

2.2 通过指针访问二维数组

2.2.1 指向元素的指针

2.2.2 指向每一行的指针(指针数组方式)

2.2.3 指向整个数组的指针(数组指针方式)

3 总结


1.数组元素的访问

       数组中的各元素在内存中是连续分布的,要想访问数组中某一元素,那么就必须知道其地址

       在一维数组中,数组A的元素A[i]的地址&A[i]=A+L*i,其中A为数组的标识符(数组名),也可以用A来代表数组的首地址,L为数组A的数据类型,由此可见,对于一维数组,只需要知道数据类型大小和索引i,就可以知道A[i]的地址,从而就可以访问A[i]了,这也是为什么一维数组的定义可以不指定数组大小,也不会妨碍数组元素的访问

       二维数组,实际上也是一维数组,只不过这个一维数组的每个元素都是一个一维数组。因此,将二维数组的每一行看做一个元素,很容易可以知道二维数组中各元素在内存中是按行优先进行连续存储的,如定义数组A[3][4],那么它在内存中的存储情况如下:

            

        由此也可得到二维数组中元素A[i][j]的地址为&A[i][j]=A+L*(C*i+j),其中A为二维数组A的标识符(数组名),也就是数组的首地址,L为数组元素的数据类型,C为二维数组的列数。由此可见,要知道二维数组中某一元素的地址,就必须知道数据类型大小以及二维数组的列数,这样最终才能实现对二维数组元素的访问,这也是为什么二维数组的定义必须指定列数


2.通过指针访问数组

       在理解访问数组的指针之前,我们不得不先理解另一个问题:如果定义一个数组A,按前面所说,A就是数组第一个元素的首地址,那么A+1是什么意思呢?我在第一次遇到这个问题的时候,第一反应是A既然表示的是地址,那么A+1自然就是地址+1了呀!然而事实并非如此,我们先来做个测试如图所示:

                                          

       根据测试可知,a+1并非就是a数值上加1,a+2也并非是a数值上加上2,他们实际上两两之间加的是4,即是sizeof(int),而*a=a[0]=1,*(a+1)=a[1]=2.....由此可以知道,a+i实际上就是a的第i个元素的地址,这与前面&A[i]的地址计算是相匹配的。

       而对于二维数组来说,道理其实是一样的,不过二维数组的元素A[0]表示第一行,A[1]表示第二行......因此,二维数组中A是数组的首地址,也就是第0行A[0]的行首地址,A+1就是第1行A[1]的行首地址,.....,A+i就是第i行A[i]的行首地址了....

      

2.1 通过指针访问一维数组

 一维数组指针的定义方式如下:

int a[4]={1,2,3,4};
int *p=a;

       这里定义了一个指针变量p,它指向一个整型变量,而a实际上也就是a的第一个元素a[0]的地址,因此p就指向了数组的第一个元素a[0]。 那么p+1等于什么呢?实际上,p+1在数值上也就等于a+1,因此,p+1其实就是a[1]的地址,p+i就是a[i]的地址,这样,就可以通过*(p+i)来访问a[i]的值了。如图所示:

                                           

      由此可以得出,对于一维数组的数组指针p,数组名p实际上是指向数组第一个元素的指针,即p为int *类型,由于其指向int型数据,因此(p+i)就相当于在p的基础上偏移了i*sizeof(int)的地址大小,就等于数组第i个元素的地址(i=0,1,2....)。

2.2 通过指针访问二维数组

2.2.1 指向元素的指针

        这种办法可以说是最直接的办法了,定义方式如下:

int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int *p=&a[0][0];

        在这种定义方式下,对于数组元素的访问就需要一个个元素往后推,结合本文开头所说的,二维数组是按行优先存储的,第i行第j列元素实际上是整个二维数组中的第i*c+j个元素,其中c为二维数组的列数,相对于第一个元素,第i*c+j个元素的地址偏移量为4*(i*c+j),而由于p为int指针,p+x的地址偏移量为p+4*x,因此a[i][j]=*(p+i*c+j)

2.2.2 指向每一行的指针(指针数组方式)

        这种方式是定义指针来指向二维数组的某一行,定义方式如下:

int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int *p=a[0];

       这里可能会有些迷惑了,为什么这里的指针变量p是指向的a[0]呢?而不能让p指向a呢?

       实际上,前面说过,二维数组实际上是一维数组中每个元素都为一个一维数组,那么此时定义了a[3][4],a代表什么呢?一定要知道,不管数组a是几维的,它实际上都是一维的,a一定是数组第一个元素的地址,这里的第一个元素是指的将n维数组看做一维数组后的第一个元素。因此,在a[3][4]中,将a看做一维数组后它的每一个元素实际上是每一行,因此如果让指针变量p指向a,就相当于让p指向第0行,而这里的第0行并不是整形变量,因此不能让p指向a;

       而如果让p指向a[0],实际上就相当于指向a[0]的第一个元素,也就是a[0][0]了,此时的a[0][0]是整形变量,因此让p指向a[0]是可以的,当然,也可以让p指向a[1]、a[2].....如果让p指向第i行,那么此时的p+j就相当于是一维数组中第j个元素的地址了,即p+j就指向了a[i][j]。

       这样看来,对于有r行的二维数组,就需要定义r个指针指向每一行,这样其实就可以定义一个装有r个指针的数组,其中每一个指针分别指向二维数组的每一行,定义方式如下:

int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int *p[3];

for(int i=0;i<3;i++)p[i]=a[i];

       在这种定义方式下,p[i]即指向数组的第i行,也就是a[i][0],知道了a[i][0]的地址,要想访问a[i][j],地址即是a[i][0]+4*j,这里由于p[i]是int型的指针变量,因此刚好就等于p[i]+j,即a[i][j]=*(p[i]+j)。这就是一种定义指向二维数组的指针的方式,这里的p是以指针作为元素的数组,也就是指针数组

       值得注意的是,这种方法必须知道二维数组的行数

2.2.3 指向整个数组的指针(数组指针方式)

       这种方式是定义指针来指向整个数组,定义方式如下:

int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int (*p)[4]=a;

       那么这里的p是什么意思呢?如果看不懂(*p)[4],那就把*p用b去替换掉,就成了b[4],这里的b就很明显了,就是一个有4个元素的数组的首地址,那么这里的p的含义也就不难得出了:指向一个有四个元素的数组的首地址,尤其需要注意的是,这里p是指向首地址,并非就是首地址,*p才是首地址,也就是指向第一个元素,因此这里的p也就是指向指针的指针。在int (*p)[4]=a中,p就是指向了第一个含四个元素的数组的首地址,也就是p指向a的首地址也就是a[0],*p指向a[0]的首地址也就是a[0][0],要访问a[0][0],就就是*(*p)了;

       既然p是指向一个有四个元素的数组首地址的指针,那么p+i呢?*p+i呢?要分析清楚这个问题,我们还是参考b[4],前面说过,这里的p是指向首地址的指针,因此p+i就对应了&b+i,因此p+i就指向了&b+i所在的位置;*p是b的首地址,指向b的第一个元素,*p+i就对应了b+i,因此*p+i就指向了b+i所在的位置。

       对于p+i,我们来看看&b+i和&b之间偏移了多少:

                                 

      可以看到,&b+1偏移了16个字节,&b+2偏移了32个字节,而16个字节刚好就是数组b的大小,因此&b+i实际上偏移的地址为i*sizeof(b)=i*c*sizeof(int)。也就是说p+i会跳过整个包含四个整型元素的数组指向下一个包含四个元素的数组,回到a[3][4]中,p指向的是a[0],那么p+1就指向a[1],p+i就指向a[i]了,因此,p+i偏移i个b数组大小的地址,也就是指向二维数组的第i行。

        而对于*p+i,就比较简单了,可以看做*p=b,那么*p+i也就是b+i,即是第i个元素的地址,因此也可得出*p+i指向当前有四个元素的数组的第i个元素

       好了,那么我们要是想访问数组中的a[i][j]怎么办呢?前面说过,要访问数组中的元素,必须先得到其地址,对于a[i][j],它是a数组中第i行的子数组中的第j个元素,综合上面分析的,p+i即指向了数组a的第i行,*(p+i)就是该行的首地址,也就是指向了a[i][0],而对于a[i]这个一维数组的第j个元素当然就是a[i]+j,也就是*(p+i)+j了,因此,a[i][j]的地址就是*(p+i)+j,a[i][j]=*(*(p+i)+j)

3 总结

      综合以上分析,总结一下用指针访问数组元素的方法(以数组a为例):

 

 

一维数组a[ ]

                                   二维数组a[R ][ C ]

定义方式

T *p=a;

T *p=&a[m][n];

T *p[R];

p[m]=a[m];

(m=0,1..R-1)

 T (*p)[C]=a;

访问方式

a[i]=*(p+i)

a[i][j]=*(p+(i-m)*C+(j-n))

a[i][j]=*(p[i]+j);

a[i][j]=*(*(p+i)+j)

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

指针数组、数组指针——用指针访问数组方法总结 的相关文章

  • 51单片机串口通讯UART

    1 串行通信的的基本知识 在实际的工业生产 xff0c 或者生活中 xff0c 计算机的CPU要与外部的设备之间进行信息的交流 xff0c 数据的交换 xff0c 所有的这些信息交换均可称为通信 通信的方式有两种 xff0c 分别为串行通信
  • 库函数开发与寄存器开发

    在以前 8 位机时代的程序开发中 xff0c 一般直接配置芯片的寄存器 xff0c 控制芯片的工作方式 xff0c 如中断 xff0c 定时器等 配置的时候 xff0c 常常要查阅寄存器表 xff0c 看用到哪些配置位 xff0c 为了配置
  • Arduino修改Serial接收缓冲区大小

    看到网上有资料说 xff0c 直接添加以下宏定义就可以了 xff1a span class token macro property span class token directive keyword define span SERIAL
  • RT-Thread nmealib库WH-GN100模块设置仅支持北斗

    RT Thread nmealib库主页 在nmea thread init函数的末尾 xff0c 添加以下代码块 xff0c 发送配置指令 xff0c 仅使用北斗卫星 xff0c 即可配置成仅GPS卫星工作模式 span class to
  • C#中字符串判断为空或者空格

    最近遇到这个问题 xff0c 来大概说一下C 中字符串判断为空或者空格这个问题 xff08 1 xff09 字符串为空null xff0c 怎么讲就是内存中没有放东西 xff0c 比如新创建的字符串就为空null xff0c string
  • 【冷知识】火车票座位分布知识点

    最近到了每年过年 xff0c 春运火车高峰期的时候了 xff0c 有的人想知道自己具体的位置在哪里 xff08 比如硬座是不是靠窗的 xff0c 座位的大小号排序等 xff09 xff0c 现在来讲讲这方面的知识点 xff0c 个人整理 列
  • QT中的自定义信号以及自定义函数

    信号与槽函数是QT的一大创新 xff0c 通过自定义信号与槽函数可以实现自己想实现的功能 标准的信号与槽写法如下 xff1a connect amp button amp QPushButton clicked this amp QWidg
  • 如何摆放PCB元器件?(建议收藏)

    PCB设计 xff0c 既是科学也是艺术 其中有非常多关于布线线宽 布线叠层 原理图等等相关的技术规范 xff0c 但当你涉及到PCB设计中具有艺术特质元器件布局问题时 xff0c 问题就变得有趣起来了 事实上 xff0c 关于元器件摆放限
  • 【MFC开发(6)】复选框按钮控件Check Box

    1 新建复选框 直接拖拽即可 xff0c 设置名字可修改caption内容 2 设置默认选中 复选框可多选 xff0c 所以可以给很多复选框按钮进行选中 xff0c 代码如下所示 xff0c 放在dlg初始化函数中实现 获取多选框香蕉的指针
  • 【MFC开发(15)】进度条控件Progress Control

    1 进度条控件的常用方法 首先给控件添加一个变量 在dlg初始化函数钟进行方法的实现 进度条显示区域 设置进度条的范围 m progress SetRange 0 100 设置进度条当前的位置 m progress SetPos 75 获取
  • 【MFC开发(16)】树形控件Tree Control

    1 树形控件的属性配置 xff08 1 xff09 Check Boxes xff1a 默认为false xff0c 如果选择为true的话每个节点前面会带有一个方框 xff08 2 xff09 Edit Labels xff1a 默认为f
  • 【MFC开发(17)】高级列表控件List Control

    1 介绍 ListCtrl 高级列表控件也是我们平时编程过程中很常用的一个控件 xff0c 一般涉及到报表展示 记录展示之类的 xff0c 都需要ListCtrl 高级列表控件 例如 xff1a 任务管理器啊 xff0c 文件列表啊 xff
  • STM32L4单片机连接语音模块NVC的源码

    这周写了一下STM32L4的语音模块 xff0c 使用的语音芯片是NVC系列芯片 xff0c 提供一下代码给以后需要的朋友们 xff0c 不喜勿喷 头文件NVC h ifndef NVC H define NVC H 音源 define S
  • oled显示模块ssd1306

    管脚定义 GND 电源地 VCC xff1a 供电电源3 3v 5v都可以 D0 xff1a 串行输入时钟CLK D1 xff1a 串行输入数据 RES xff1a 复位 DC xff1a 控制输入数据 命令 xff08 高电平1为数据 低
  • 上位机串口数据检验方式(一)——校验和

    最近还是在写上位机软件 xff0c 还是有一堆问题 xff0c 因为是第一次做这个东西 xff0c 有些东西只能到论坛上来查 xff0c 最近做到了数据通信 xff0c 刚开始没有想到数据协议这些东西 xff0c 现在涉及到了 xff0c
  • c#上位机开发(三)——串口通信上位机开发1

    今天主要做一个跟市面上差不多的稍微简单点的上位机软件 xff0c 效果如下图所示 1 功能概述 xff08 1 xff09 端口扫描 xff0c 主要是扫描出可用的端口用来连接 xff08 2 xff09 波特率的选择 xff0c 使用一个
  • 使用python执行外部命令subprocess

    1 使用python执行外部命令subprocess subprocess模块是Python自带的模块 xff0c 无须再另行安装 xff0c 它主要用来取代一些旧的模块或方法 xff0c 如os system os spawn os po
  • #Qt on android#使用Qt 获取GPS信号

    注意事项 xff1a 1 Qt版本一定要大于等于5 3 xff0c 因为低于5 3的版本对于android系统来说并不能成功获取gps信号 2 环境正确搭建 xff0c 一定要注意 xff01 构建 xff08 build xff09 的系
  • 2023年TI杯全国大学生电子设计竞赛通知正式发布

    关于组织2023年 全国大学生电子设计竞赛的通知 xff08 电组字 2023 01号 xff09 各赛区组织委员会 各有关高等学校 xff1a 全国大学生电子设计竞赛 xff08 以下简称全国竞赛 xff09 组委会在认真总结往届电子设计
  • HTTPClient调用https请求,通过基本认证用户名密码(Basic Auth)

    本文来源是Apache官网例子 xff1a httpcomponents client ClientAuthentication java at 4 5 x apache httpcomponents client GitHub 之前找过很

随机推荐

  • c中结构体数据对齐问题

    1 为什么需要数据对齐 提升CPU读取数据的效率 CPU每次都是从以4字节 xff08 32位CPU xff09 或是8字节 xff08 64位CPU xff09 的整数倍的内存地址中读进数据的 xff08 例如32位的只能0x000000
  • js打开新窗口的方法总结

    Window open 方法 完整代码 window span class token punctuation span span class token function open span span class token punctu
  • 一文详解堆栈(二)——内存堆与内存栈

    前言 xff1a 我们经常听见一个概念 xff0c 堆 xff08 heap xff09 和栈 xff08 stack xff09 xff0c 其实在数据结构中也有同样的这两个概念 xff0c 但是这和内存的堆栈是不一样的东西哦 xff0c
  • 《动手学ROS2》3.2ROS2工作空间介绍

    本系列教程作者 xff1a 小鱼 公众号 xff1a 鱼香ROS QQ交流群 xff1a 139707339 教学视频地址 xff1a 小鱼的B站 完整文档地址 xff1a 鱼香ROS官网 版权声明 xff1a 如非允许禁止转载与商业用途
  • Ubuntu18.04 realsenseD435i深度摄像头外参标定的问题

    Ubuntu18 04 realsenseD435i深度摄像头外参标定的问题 鱼香ROS介绍 xff1a 鱼香ROS是由机器人爱好者共同组成的社区 xff0c 欢迎一起参与机器人技术交流 进群加V xff1a fishros2048 文章信
  • STM-32:USART串口协议、串口外设—数据发送/数据发送+接收

    目录 一 串口通信1 1通信接口1 2串口通信1 2 1简介1 2 2硬件电路1 2 3串口参数及时序 二 STM32的USART外设2 1USART简介2 2USART框图 三 数据传输3 1数据帧3 2输入数据策略3 2 1起始位侦测3
  • 大疆M3508、M2006必备CAN总线知识与配置方法

    大疆M3508 M2006必备CAN总线知识与配置方法 文章目录 大疆M3508 M2006必备CAN总线知识与配置方法前言 xff1a 0x00 需要 额外的 CAN收发器 xff01 xff01 xff01 0x01 硬件层面分析为什么
  • 换个角度聊聊PID吧,很干。

    01 前言 大家好 xff0c 前面发了几篇关于PID的文章 xff1a 点击图片即可阅读 教你10分钟完成智能小车的PID调速 快速调试PID参数的3种方法 02 自动控制系统 在直流有刷电机的基础驱动中 xff0c 如果电机负载不变 x
  • linux发起http请求,GET、POST

    GET请求 curl 推荐 curl v 34 https test com login username 61 tyw amp password 61 123 34 curl 34 https test com 34 URL指向的是一个文
  • VSCode对C++的DEBUG调试配置

    C 43 43 vscode上的调试配置 1 调试配置2 修改编译模式 按照本 的流程可在vscode平台上实现像在windows系统下VS调试C 43 43 程序的效果 1 调试配置 当写好代码和 CMakeLists txt 之后 xf
  • VSCode的C/C++扩展功能

    VSCode的C C 43 43 扩展功能 1 在 Linux 上 使用 C 43 43 1 1 创建 Hello World1 2 探索 IntelliSense1 3 构造 helloworld cpp1 3 1 运行 build1 3
  • 从源码理解智能指针(二)—— shared_ptr、weak_ptr

    目录 计数器 Ref count Ref count del Ref count del alloc Ptr base Ptr base的成员变量 构造函数 赋值重载 获取引用计数 减少引用计数 Reset函数 Resetw函数 share
  • muduo源码学习(1):异步日志——日志消息的存储及输出

    目录 前言 日志存储的实现 日志输出的实现 总结 前言 muduo中的日志 xff0c 是诊断日志 用于将代码运行时的重要信息进行保存 xff0c 方便故障诊断和追踪 日志一般有两种 xff0c 一种是同步日志 xff0c 一种是异步日志
  • muduo源码学习(2):异步日志——异步日志的实现

    目录 什么是异步日志 异步日志的实现 前端与后端 前端与后端的交互 资源回收 后端与日志文件 滚动日志 自动flush缓冲区 开启异步日志功能 总结 在前文中分析了日志消息的存储和输出 xff0c 不过并没有涉及到异步日志 xff0c 下面
  • muduo异步日志——core dump后查找还未来得及写出的日志

    目录 前言 生成core文件 gdb调试Core文件 前言 通过异步日志的实现可以知道 xff0c 日志消息并不是生成后立刻就会写出 xff0c 而是先存放在前端缓冲区currentBuffer或者前端缓冲区队列buffers中 xff0c
  • C++知识积累:成员函数运算符重载与非成员函数运算符重载

    运算符重载 xff0c 是C 43 43 多态的表现形式之一 xff0c 可以通过对运算符进行重载来实现运算符特定的功能 运算符重载一般具有以下原则 xff1a xff08 1 xff09 不可重载不存在的运算符 xff0c 如重载 来表示
  • (二叉树)二叉树的最近公共祖先

    题目描述 给定一个二叉树 找到该树中两个指定节点的最近公共祖先 百度百科中最近公共祖先的定义为 xff1a 对于有根树 T 的两个结点 p q xff0c 最近公共祖先表示为一个结点 x xff0c 满足 x 是 p q 的祖先且 x 的深
  • 有符号数、无符号数理解

    大家都知道 xff0c 在C C 43 43 中 xff0c 对于w位编译器 xff0c 其有符号数表示的数值范围为 2 w 1 2 w 1 1 xff0c 无符号数表示的数值范围为0 2 w 1 xff0c 举个例子 xff0c 在16位
  • ​PCB的 “ 黑科技 ” ,应该是这个。

    大家好 xff0c 我是张巧龙 xff0c 前段时间炒的很火的折叠屏手机不知道大家还记得不 xff1f 折叠屏手机之所以这么具有 34 韧性 34 xff0c 全靠背后的柔性电路板 FlexiblePrintedCircuit xff0c
  • 指针数组、数组指针——用指针访问数组方法总结

    目录 1 数组元素的访问 2 通过指针访问数组 2 1 通过指针访问一维数组 2 2 通过指针访问二维数组 2 2 1 指向元素的指针 2 2 2 指向每一行的指针 xff08 指针数组方式 xff09 2 2 3 指向整个数组的指针 xf