C语言:二维数组的传递

news2024/11/19 8:24:47

       

目录

        一、从本质了解二维数组

        二、访问二维数组的方式

        1、指向元素的指针

        2、指向每一行的指针(指针数组)

        3、指向整个数组的指针(数组指针)

        三、3种二维数组的形参声明方式

        1、数组法

        2、数组指针法

        3、指针法


        在实践工程项目中,往往需要在函数形参中声明多维数组,特别是二维数组,本文介绍几种方法进行声明二维数组的形参。

        一、从本质了解二维数组

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

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

         从以上可知,二维数组声明时必须指定列数,否则报错,如下所示:

//函数声明时
void TwoDimensionalArray(int[][], int a);  //error
//变量定义时
int a1[][];//error
int a2[2][];//error
int a3[1][2]; //right
int a4[][3];//right

        二、访问二维数组的方式

        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、指向每一行的指针(指针数组)

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

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

       实际上,二维数组实际上是一维数组中每个元素都为一个一维数组,那么此时定义了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)[4]=a;

        在这种定义方式下,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是以指针作为元素的数组,也就是指针数组。

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

        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)了。

        三、3种二维数组的形参声明方式

        1、数组法

        该方法需要指定行数

void display2DArray(int arr[][5],int row);//需要指定行数row

        注意:需要指定行数,但是以下指定方式是无效的:

//以下方式指定行数无效
void display2DArray(int arr[3][5]);

        原因:如同一维数组在函数形参中声明一样,数组被弱化为指针,因此函数体内部无法获取该值。如下所示:

//以下两种声明方式是等效的:
void display(int array[5])//5在这里是无效的
void display(int array[])//5在这里是无效的

        2、数组指针法

        该方法需要指定行数

void display2DArray(int (*arr)[5],int row);

       注意:切记以指针数组声明,该声明是错误的,如下:

void display2DArray(int *array[5]);	  //error

        3、指针法

        该方法需要同时指定列数与行数,以下展示了该方法的声明与调用过程:

void display2DArray(int *array,int rows,int cols)	  //error
{
	for (int i=0;i<rows;++i)
	{
		for (int j=0;j<cols;++j)
		{
			printf("%d ", *(array + rows * i + j));
		}
	}
}

参考文献:https://blog.csdn.net/qq_28114615/article/details/86434837 

                《深入理解C指针》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/11173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构笔记5】-哈夫曼树

哈夫曼树 结点的权&#xff1a;有某种显示含义的数值&#xff08;如&#xff1a;表示结点的重要性等&#xff09; 结点的带权路径长度&#xff1a;从树的根到该结点的路径长度&#xff08;经过的边数&#xff09;与该节点上权值的乘积。 数的带权路径长度&#xff1a;树种所有…

人工智能如何赋能智能安防落地?

作为当下最热门的技术&#xff0c;人工智能基本覆盖了所有的行业&#xff0c;也开始成为了安防行业的“大金矿”。 人工智能赋能安防行业的确是好事&#xff0c;但技术同质化、产品同质化等问题开始凸显出来&#xff0c;并显得越发严重。人工智能将以怎样的新姿态赋能智能安防落…

广东长荣科技有限公司-Java笔试题

Java工程师笔试题目&#xff08;限30分钟完成&#xff09; 一、请参考图片回答以下问题。 二、如何理解面向对象编程&#xff1f; 三、String s new String("Hello");s s " world!";这两行代码执行后&#xff0c;内存是如何变化的&#xff1f; 四、…

ASEMI代理力特二极管LSIC2SD120A05,肖特基LSIC2SD120A05

编辑-Z 力特碳化硅肖特基二极管LSIC2SD120A05参数&#xff1a; 型号&#xff1a;LSIC2SD120A05 重复峰值反向电压&#xff08;VRRM&#xff09;&#xff1a;1200V 连续正向电流&#xff08;IF&#xff09;&#xff1a;5A 非重复正向浪涌电流&#xff08;IFSM&#xff09;&…

Java#7(this关键字和构造方法)

目录 一.就近原则和this关键字 二.构造方法 1.构造方法的格式: 2.构造方法的特点: 有参构造和无参构造​编辑 三.标准的Javabean类 一.就近原则和this关键字 func里的age离System.out.println(age);比较近,所以输出的是10;这就是就近原则,但如果我想使用的是成员变量age前…

OceanBase 首席科学家阳振坤博士入选2022 年度“CCF王选奖”

11 月 14 日&#xff0c;2022 年度“CCF王选奖” 评选结果公布&#xff0c;蚂蚁集团副总裁、 OceanBase 首席科学家阳振坤博士 入选。 “CCF王选奖” 由中国计算机学会&#xff08;简称 CCF&#xff09;设立于 2005 年&#xff0c;以我国著名计算机科学家王选先生命名&#…

高精度定时器学习(通过官方手册学习)

高精度定时器学习功能描述一般说明HRTIM引脚和内部信号时钟Timer A..E timing units翻转事件功能描述 一般说明 HRTIM可以划分为几个模块&#xff1a; •主定时器 •计时单元&#xff08;定时器A至定时器E&#xff09; •输出级 •突发模式控制器 •所有定时器共享的外部事件…

Android核心技术—内核(Linux) 的IO栈

简述 Linux的IO路径可能是Linux系统中最纷繁复杂的模块了&#xff0c;而它又是如此的重要&#xff0c;直接决定了系统的性能。 接下来我们来看一张熟悉的老图&#xff1a; 由图可见&#xff0c;从系统调用的接口再往下&#xff0c;Linux下的IO栈致大致有几个层次&#xff1a…

【Spring】——3、自定义TypeFilter指定@ComponentScan注解的过滤规则

&#x1f4eb;作者简介&#xff1a;zhz小白 公众号&#xff1a;小白的Java进阶之路 专业技能&#xff1a; 1、Java基础&#xff0c;并精通多线程的开发&#xff0c;熟悉JVM原理 2、熟悉Java基础&#xff0c;并精通多线程的开发&#xff0c;熟悉JVM原理&#xff0c;具备⼀定的线…

Java中的IO流

Java中的IO流 Java中的4大IO抽象类 InputStream/OutputStream 为字节输入输出流 Reader/Writer 为字符输入输出流 InputStream OutputStream Reader Writer Java中流的概念细分 二进制文件&#xff08;图片、影音&#xff09;用字节流 文本信息用字符流 IO流的体系 练手案例…

HTML入门

目录1 HTML快速入门1.1 HTML 的介绍1.1.1 HTML 的组成标签属性1.2 入门案例1.2.1 案例效果1.2.2 实现步骤1.3 总结2 HTML 基本语法2.1 HTML 的注释2.2 HTML 标签2.3 HTML 的属性2.4 HTML 的特殊字符3 HTML 案例 新闻文本3.1 案例效果3.2 案例分析3.2.1 div 样式布局3.2.2 文本标…

软件测试面试真题 | Selenium 的工作原理是什么?

搜索微信公众号&#xff1a;TestingStudio 霍格沃兹的干货都很硬核 Selenium 通常被我们用做测试web的自动化测试工具&#xff0c;其实 Selenium 不仅仅是个API&#xff0c;它是一组工具集合&#xff0c;它是由三大组件组成 WebDriver: 可以模拟真正的用户去操作浏览器页面&am…

机械转码日记【24】继承

目录 前言 1.继承的概念及定义 1.1继承的概念 1.2 继承定义 1.2.1定义格式 1.2.2继承关系和访问限定符 1.2.3继承基类成员访问方式的变化 2.基类和派生类对象赋值转换 3.继承中的作用域 4.派生类的默认成员函数 4.1构造函数 5.设计一个不能被继承的类 6.继承与…

瑞吉外卖(三) 分类管理

瑞吉外卖 分类管理瑞吉外卖 分类管理 需求分析自动填充 代码思想ThreadLocal 的 引入瑞吉外卖 分类管理 需求分析 对于当前的多个Model&#xff0c;存在了多个相同的字段 比如说&#xff1a;更新时间&#xff0c;创建时间&#xff0c; 更新人等 这些重复的业务可以通过统一的接…

已有项目eclipse开发配置步骤

已有项目eclipse开发配置步骤 前提&#xff1a;jdk8安装、tomcat8安装 1、eclipse打开已有项目 File->import->Existing Projects into Workspace 说明&#xff1a;我这里已经打开项目了 2、配置Properties 项目根目录右击->点击Properties Java Build Path -&…

【僵尸进程和文件系统调用】

目录虚拟空间物理空间僵尸进程僵尸进程产生僵尸进程的解决孤儿进程文件系统调用虚拟空间物理空间 内存与磁盘的运行速度1&#xff1a;20 x86 32位 4G–> 物理内存&#xff1a;寻址能力4G 4G供内核1G&#xff0c;用户态的3G&#xff0c; 虚拟空间4G&#xff0c;虚拟空间可以…

周阳老师JUC并发编程

1. 序章 1&#xff09;JUC是什么&#xff1f; java.util.concurrent在并发编程中使用的工具包 对JUC知识的高阶内容讲解和实战增强 2&#xff09;为什么学习并用好多线程极其重要&#xff1f; 硬件方面&#xff1a; 摩尔定律: 它是由英特尔创始人之一Gordon Moore(戈登摩尔…

Linux 下编译实现C/Fortran调用动态库

目录 FORTRAN语言 生成动态库Demo 查看动态库中的函数 Fortran语言 FORTRAN语言是Formula Translation的缩写&#xff0c;意为“公式翻译”。它是为科学、工程问题或企事业管理中的那些能够用数学公式表达的问题而设计的&#xff0c;其数值计算的功能较强。 FORTRAN语言是…

样式补充(精灵图、背景图片、阴影),项目前置认知、结构搭建

一、网页制作 根目录 图片文件夹&#xff1a;images 样式文件夹&#xff1a;CSS 首页&#xff1a;index.html <link rel"stylesheet" href"./CSS/index.css"> 二、项目样式补充 1. 精灵图 场景&#xff1a;项目中将多张小图片&#xff0c;合并…

基于粒子群算法训练常规自动编码器附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …