当前位置: 首页 > 编程日记 > 正文

图解c/c++多级指针与“多维”数组

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

前言

指针与数组是C/C++编程中非常重要的元素,同时也是较难以理解的。其中,多级指针与“多维”数组更是让很多人云里雾里,其实,只要掌握一定的方法,理解多级指针和“多维”数组完全可以像理解一级指针和一维数组那样简单。

首先,先声明一些常识,如果你对这些常识还不理解,请先去弥补一下基础知识:

1、实际上并不存在多维数组,所谓的多维数组本质上是用一维数组模拟的。2、数组名是一个常量(意味着不允许对其进行赋值操作),其代表数组首元素的首地址。3、数组与指针的关系是因为数组下标操作符[],比如,int a[3][2]相当于*(*(a+3)+2) 。4、指针是一种变量,也具有类型,其占用内存空间大小和系统有关,一般32位系统下,sizeof(指针变量)=4。5、指针可以进行加减算术运算,加减的基本单位是sizeof(指针所指向的数据类型)。6、对数组的数组名进行取地址(&)操作,其类型为整个数组类型。7、对数组的数组名进行sizeof运算符操作,其值为整个数组的大小(以字节为单位)。8、数组作为函数形参时会退化为指针。

一维数组与数组指针

假如有一维数组如下:

char a[3];

该数组一共有3个元素,元素的类型为char,如果想定义一个指针指向该数组,也就是如果想把数组名a赋值给一个指针变量,那么该指针变量的类型应该是什么呢?前文说过,一个数组的数组名代表其首元素的首地址,也就是相当于&a[0],而a[0]的类型为char,因此&a[0]类型为char *,因此,可以定义如下的指针变量:

 char * p = a;//相当于char * p = &a[0] 

以上文字可用如下内存模型图表示。

大家都应该知道,a和&a[0]代表的都是数组首元素的首地址,而如果你将&a的值打印出来,会发现该值也等于数组首元素的首地址。请注意我这里的措辞,也就是说,&a虽然在数值上也等于数组首元素首地址的值,但是其类型并不是数组首元素首地址类型,也就是char *p = &a是错误的。

前文第6条常识已经说过,对数组名进行取地址操作,其类型为整个数组,因此,&a的类型是char (*)[3],所以正确的赋值方式如下:

char (*p)[3] = &a;

      注:很多人对类似于a+1,&a+1,&a[0]+1,sizeof(a),sizeof(&a)等感到迷惑,其实只要搞清楚指针的类型就可以迎刃而解。比如在面对a+1和&a+1的区别时,由于a表示数组首元素首地址,其类型为char *,因此a+1相当于数组首地址值+sizeof(char);而&a的类型为char (*)[3],代表整个数组的首地址,因此&a+1相当于数组首地址值+sizeof(a)。(sizeof(a)代表整个数组大小,前文第7条说明,但是无论数组大小如何,sizeof(&a)永远等于一个指针变量占用空间的大小,具体与系统平台有关)。

二维数组与数组指针

      假如有如下二维数组:

char a[3][2];

由于实际上并不存在多维数组,因此,可以将a[3][2]看成是一个具有3个元素的一维数组,只是这三个元素分别又是一个一维数组。实际上,在内存中,该数组的确是按照一维数组的形式存储的,存储顺序为(低地址在前):a[0][0]、a[0][1]、a[1][0]、a[1][1]、a[2][0]、a[2][1]。(此种方式也不是绝对,也有按列优先存储的模式)

为了方便理解,我画了一张逻辑上的内存图,之所以说是逻辑上的,是因为该图只是便于理解,并不是数组在内存中实际的存储模型(实际模型为前文所述)。

145250_vVzp_2896894.png

如上图所示,我们可以将数组分成两个维度来看,首先是第一维,将a[3][2]看成一个具有三个元素的一维数组,元素分别为:a[0]、a[1]、a[2],其中,a[0]、a[1]、a[2]又分别是一个具有两个元素的一维数组(元素类型为char)。从第二个维度看,此处可以将a[0]、a[1]、a[2]看成自己代表”第二维”数组的数组名,以a[0]为例,a[0](数组名)代表的一维数组是一个具有两个char类型元素的数组,而a[0]是这个数组的数组名(代表数组首元素首地址),因此a[0]类型为char *,同理a[1]和a[2]类型都是char *。而a是第一维数组的数组名,代表首元素首地址,而首元素是一个具有两个char类型元素的一维数组,因此a就是一个指向具有两个char类型元素数组的数组指针,也就是char(*)[2]。

也就是说,如下的赋值是正确的:

char (*p)[2]  = a;//a为第一维数组的数组名,类型为char (*)[2]
char * p = a[0];//a[0]维第二维数组的数组名,类型为char *

同样,对a取地址操作代表整个数组的首地址,类型为数组类型(请允许我暂且这么称呼),也就是char (*)[3][2],所以如下赋值是正确的:

char (*p)[3][2] = &a;

三维数组与数组指针

假设有三维数组:

char a[3][2][2];

同样,为了便于理解,特意画了如下的逻辑内存图。分析方法和二维数组类似,首先,从第一维角度看过去,a[3][2][2]是一个具有三个元素a[0]、a[1]、a[2]的一维数组,只是这三个元素分别又是一个"二维"数组,a作为第一维数组的数组名,代表数组首元素的首地址,也就是一个指向一个二维数组的数组指针,其类型为char (*)[2][2]。从第二维角度看过去,a[0]、a[1]、a[2]分别是第二维数组的数组名,代表第二维数组的首元素的首地址,也就是一个指向一维数组的数组指针,类型为char(*)[2];同理,从第三维角度看过去,a[0][0]、a[0][1]、a[1][0]、a[1][1]、a[2][0]、a[2][1]又分别是第三维数组的数组名,代表第三维数组的首元素的首地址,也就是一个指向char类型的指针,类型为char *。

145423_pp6P_2896894.png

由上可知,以下的赋值是正确的:

char (*p)[3][2][2] = &a;//对数组名取地址类型为整个数组
char (*p)[2][2]  = a;
char (*p) [2]  = a[0];//或者a[1]、a[2]
char *p = a[0][0];//或者a[0][1]、a[1][0]...

多级指针

      所谓的多级指针,就是一个指向指针的指针,比如:

char *p = "my name is chenyang.";
char **pp = &p;//二级指针
char ***ppp = &pp;//三级指针

假设以上语句都位于函数体内,则可以使用下面的简化图来表达多级指针之间的指向关系。

多级指针通常用来作为函数的形参,比如常见的main函数声明如下:

int main(int argc,char ** argv)

因为当数组用作函数的形参的时候,会退化为指针来处理,所以上面的形式和下面是一样的。

int mian(int argc,char* argv[]) 

argv用于接收用户输入的命令参数,这些参数会以字符串数组的形式传入,类似于:

char * parm[] = {"parm1","parm2","parm3","parm4"};//模拟用户传入的参数
main(sizeof(parm)/sizeof(char *),parm);//模拟调用main函数,实际中main函数是由入口函数调用的(glibc中的入口函数默认为_start)

多级指针的另一种常见用法是,假设用户想调用一个函数分配一段内存,那么分配的内存地址可以有两种方式拿到:第一种是通过函数的返回值,该种方式的函数声明如下:

void * get_memery(int size){void *p = malloc(size);return p;}

第二种获取地址的方法是使用二级指针,代码如下:

int get_memery(int** buf,int size){ *buf = (int *)malloc(size);if(*buf == NULL)return -1;elsereturn 0;}int *p = NULL;get_memery(&p,10);

转载于:https://my.oschina.net/fileoptions/blog/1036644

相关文章:

信科c语言实验程序修改题_豆瓣评分 9.3,史上最好的 C 语言著作,竟然翻车了.........

上周,在小编的各种努力下(省略一万字),Kindle 官方终于答应给我一个广告位了。虽然只是开机屏,但我还是笑出了猪叫,毕竟上一次有这待遇还是 2018 年时的《算法图解》。所以错过了上次,这次我一定要亲眼见证这个时刻。我…

Nodejs Express dockerfile最佳实践

少啰嗦,先看代码 package.json {"name": "xxx","version": "0.0.0","private": true,"scripts": {"start": "node ./bin/www","forever": "node_modules/forever/…

Matlab编程与数据类型 -- 开关语句switch/end

本微信图文详细介绍了Matlab中switch/end开关语句。

安装ATi显卡驱动后增加的鼠标右键菜单的清理

一般最直接的方法是:一般位于注册表的:删除注册表HKEY_CLASSES_ROOT\Directory \Background\shellex\ContextMenuHandlers\ACE下 ab默认{5E2121EE-0300-11D4-8D3B-444553540000}办法一:刚才有朋友询问了ATi显卡在安装CATALYST Control Center…

15crmo焊接后多长时间探伤_15CrMo十五铬钼属于合金钢?、下面来解释一下

15CrMo十五铬钼属于合金钢​,主要用于石油、石化、高压锅炉等,专门用途的无缝管有锅炉用无缝管、地质用无缝钢管及石油用无缝管等多种。​一、15CrMo化学成分:C:0.12-0.18 Mn:0.40-0.70 Si:0.17-0.37 Cr:0.…

VTL-vm模板的变量用法

加载foot模块页 #parse("foot.vm") #foreach($item in $tables) #set($strEnd $item.Length - 1) #set($sheetName $item.Substring(0, $strEnd)) <option value"$item">$sheetName</option> #end $strEnd也可以看做一个字符串来操作 $it…

百度云磁盘CDS、对象存储BOS技术深度解析

在BAT中&#xff0c;百度在公有云也有很多技术创新。比如2013年引起广泛关注的ARM存储服务器就是一个很好的例子。最近两年&#xff0c;百度云开始发力&#xff0c;其云存储体系有诸多创新之处。目前百度云存储形成了以块存储、对象存储、文件存储为核心&#xff0c;VPN/专线、…

Matlab编程与数据类型 -- 出错处理语句try/catch/end

本微信图文详细介绍了Matlab中try/catch/end出错处理语句。

linux设置nexus开机自启动_在linux中使用nexus搭建maven私服

首先介绍下为什么要搭建maven私服&#xff0c;简单点说就是就是把项目工程中的Jar包放在一个服务器上&#xff0c;每次Jar包的修改都能去私服上面Down到本地。可以对整个项目组的人形成一个统一的管理。2、下载完之后就是这个了&#xff1a;我这个是目前最新的版本了&#xff0…

Lintcode42 Maximum Subarray II solution 题解

【题目描述】Given an array of integers, find two non-overlapping subarrays which have the largest sum.The number in each subarray should be contiguous.Return the largest sum.Notice:The subarray should contain at least one number给定一个整数数组&#xff0c;…

const用法详解

面向对象是C的重要特性. 但是c在c的基础上新增加的几点优化也是很耀眼的 就const直接可以取代c中的#define 以下几点很重要,学不好后果也也很严重 const 1. 限定符声明变量只能被读 const int i5; int j0; ... ij; //非法&#xff0c;导致编译错误 ji; //合法 2. 必…

Matlab编程与数据类型 -- continue、break和return语句

本微信图文详细介绍了Matlab中的continue、break和return语句。

mysql 修复_修复崩溃的Mysql

在mysql的配置文件my.cnf里找到 [mysqld]字段下&#xff0c;添加 innodb_force_recovery 1如果innodb_force_recovery 1不生效&#xff0c;则可尝试2——6几个数字然后重启mysql&#xff0c;重启成功。然后使用mysqldump或 pma 导出数据&#xff0c;执行修复操作等。修复完成…

window.open(url?param=+paramvalue) 服务端 乱码问题解决

window.open("url?param"paramvalue)传递参数出现乱码&#xff0c;在客房端显示是正常的&#xff0c;可是到服务端就是乱码。 1. 利用一个js在客户端转码的函数&#xff0c;escape(str);但是传到服务端仍然是乱码&#xff0c;所以必须在服务端进行解码。 2. 服务端执…

Matlab编程与数据类型 -- 数据类型概述

本微信图文详细介绍了Matlab中的数据类型&#xff0c;数值型和逻辑型举例介绍&#xff0c;其它类型在相应图文进行介绍。

初识mysql数据字段属性_初识mysql

# 经典sql语句 创建数据库- CREATE DATABASE database_name; 删除数据库- DROP DATABASE database_name; 创建备份数据库- USE masterEXEC sp_addupdevice disk,testBack ,c:\xxx\xxx.dat 开始备份- BACKUP DATABASE pubs TO testBack;--- 创建表- 创建新表 create table tab_n…

ceph存储引擎bluestore解析

原文链接&#xff1a;http://www.sysnote.org/2016/08/19/ceph-bluestore/ ceph后端支持多种存储引擎&#xff0c;以插件式的方式来进行管理使用&#xff0c;目前支持filestore&#xff0c;kvstore&#xff0c;memstore以及最新的bluestore&#xff0c;目前默认使用的filestor…

Matlab编程与数据类型 -- 字符型数组

本微信图文详细介绍了Matlab中的字符串类型。

最近想做个音乐共享的软件

准备分如下几部分&#xff1a; 1.配置文件xml读写 2.播放器部分&#xff1a;开始准备用mediaplay做&#xff0c;发现有个开源的播放器&#xff0c;可以考虑 3.网络部分&#xff1a;主要是种子搜索和更新 准备召唤有兴趣的达人一起开发转载于:https://www.cnblogs.com/donneymin…

精通mysql_《深入精通Mysql(五)》实战:Mysql实现主从复制

深入精通Mysql系列其他文章推荐&#xff1a;一、前言随着应用业务数据不断的增大&#xff0c;应用的响应速度不断下降&#xff0c;在检测过程中我们不难发现大多数的请求都是查询操作。此时&#xff0c;我们可以将数据库扩展成主从复制模式&#xff0c;将读操作和写操作分离开来…

一个开发团队、软件公司,团队工作氛围很重要,没有好氛围难出好产品、好项目...

接触软件行业很多年有些年头了&#xff0c;展望过去的岁月&#xff0c;总想写点儿东西&#xff0c;总结总结&#xff0c;我也不怕拍砖了&#xff0c;曾经也换过很多公司、跳过很多槽&#xff0c;现在想想&#xff0c;总结出来&#xff1a;“天下的乌鸦是一样黑的”&#xff0c;…

Matlab编程与数据类型 -- 奇数阶魔方矩阵的编程

本微信图文详细介绍了利用Matlab实现奇数阶魔方矩阵的编程。

Apache Hive 快速入门 (CentOS 7.3 + Hadoop-2.8 + Hive-2.1.1)

2019独角兽企业重金招聘Python工程师标准>>> 本文节选自《Netkiller Database 手札》 第 63 章 Apache Hive 目录 63.1. 安装 Apache Hive 63.1.1. MySQL 63.1.2. Hadoop 63.1.3. Hive 63.1.4. 启动 Hive 63.1.5. 访问 Hive 63.2. 管理 Hive 63.2.1. 表管理 63.2.1.…

mysql的profile_Mysql分析-profile详解

一。前言当我们要对某一条sql的性能进行分析时&#xff0c;可以使用它。Profiling是从 mysql5.0.3版本以后才开放的。启动profile之后&#xff0c;所有查询包括错误的语句都会记录在内。关闭会话或者set profiling0 就关闭了。(如果将profiling_history_size参数设置为0&#x…

2003網域升級到2008網域以及遷移DNS

2003網域升級到2008網域以及遷移DNS 如圖這是我們現在的拓撲&#xff0c;cc從現用的LCS2008網域升級到2008網域&#xff0c;並一步步截圖給大家示範說明。隨便抓了臺虛擬機&#xff0c;是以前做LCS試驗用的&#xff0c;現在不用了&#xff0c;正好給大家示範2003升級到2008網域…

FPGA管脚约束

Edit → language templates &#xff1a; 打开即可查看基本语法。 一、xilinx中的约束文件 1、约束的分类 利用FPGA进行系统设计常用的约束主要分为3类。 &#xff08;1&#xff09;时序约束&#xff1a;主要用于规范设计的时序行为&#xff0c;表达设计者期望满足的时序条件&…

Matlab数据的可视化 -- 线性图函数plot

本篇微信图文主要介绍Matlab数据可视化方面的内容。

日志文件和mysql同步到kafka_logstash_output_kafka:Mysql同步Kafka深入详解

0、题记实际业务场景中&#xff0c;会遇到基础数据存在Mysql中&#xff0c;实时写入数据量比较大的情景。迁移至kafka是一种比较好的业务选型方案。而mysql写入kafka的选型方案有&#xff1a;方案一&#xff1a;logstash_output_kafka 插件。方案二&#xff1a;kafka_connector…

TPYBoard自制微信远程智能温湿度计

2019独角兽企业重金招聘Python工程师标准>>> 智能时代一夜间什么都能远程了。创业者想着如何做智能产品&#xff0c;如何做远程控制。DIY爱好者也想着如何自制各种奇妙的工具。这里和大家一起学习制作一款廉价的智能温湿度计。说它廉价是因为共计花费不过40元&#…

Matlab数据的可视化 -- 简易线性函数图

本篇微信图文主要介绍Matlab数据可视化方面的内容。