二维数组的传递和返回

指针和二维数组 

指针存储的是内存单元的地址,当使用引用运算符  *,或者变址运算符 [ ] 时才能将指针所指向的内存单元中的值取出。

指针有两个关键属性:

1.它存储的是内存地址

2.它存储的是什么类型变量的内存地址,这一点非常重要,这将决定对指针解引用时如何对它所指向的内存单元进行解读。

如果有这样定义的数组和指针变量

int *p;

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

p=a;

那么它在内存中的图例是这样的:

                                             图一

变量名称实际就是内存地址的一个代号。

这里需要说明一下,数组名a其实不是一个变量,它是一个常量,即不可以进行加减操作,例如a++也就是a=a+1,这样的赋值操作是不允许的,这里只是为了说明方便称其为变量名。

数组地址的表达方式有以下几种:

a 表示数组a的首地址,也就是0x0000;

&a也可以表示数组的首地址,也是0x0000,

&a[0]也是数组元素的首地址,也是0x0000

例如:这些输出都将是数组a的首地址

 printf("%p\n",a);

printf("%p\n", &a);

printf("%p\n",&a[0]);

二维数组和指针

如果a是一个二维数组

int a[2][3]={{1,2,3},{4,5,6}};

并使用二级指针int **p指向它

int **p;

p=a;

二维数组a[2][3]是一个2行3列的矩阵,但是那只是方便人们理解,在计算机内存中没有二维,都是一维,它仍然是线性存储的。此时,内存中的分布是这样的。

                                           图二

       这样对指针p赋值的话,编译器会给出警告,因为p和a的类型不同,也就是p+1和a[1]指针向后移动的内存单元数不同。例如这里,p存储的是指针变量的地址也就是指向整形指针的指针变量,而整形指针占4个字节的位置,所以p+1将指向0x0004。而a是二维数组,它的元素是一个一维数组,长度为12个字节,a[1]将指向0x000C。

二维数组的首地址表示方法:

以下几种表示方法都可以表示首地址

a

&a

a[0]

&a[0]

但是要注意,二维数组的a[0]和一维数组中的a[0]不一样。

如图一所示,一维数组的元素是整形变量,它的a[0]是整形值1。

如图二所示,二维数组的元素是一个一维数组,也就是说,每个元素的长度是3*4=12个字节。a[0]表示的是一维数组的地址,也就是指向一维数组的指针,例如这里是0x0000,那么a[1]将是0x000C。

p是一个二级指针,将二维数组a的首地址赋值给它,那么它存储的地址将是0x0000。对p解引用一次*p,当然就取出了0x0000中的值,也就是1,如果执行语句printf(“%d”,(int)*p);  那么得到的结果是1,但这并不是二维数组的正确打开方式。

当对p再次解引用的时候,就出错了(*(*p)),它表示取出内存地址0x0001中的值,那将什么也不是,当然会出错。而且p每增加1,内存地址+4,a每增加1,内存地址+12,所以,无法直接使用二级指针p来正确操作二维数组a。

如何使用指针操作二维数组呢?

可以定义特殊的二级指针,int (*p)[3]来指向二维数组。它是一个二级指针,并且说明了一维数组中元素的个数是3个,这样p指针每+1,内存地址加3*4=12。()不能去掉,因为*比[]运算符优先级低。

p=a;   //p=0x0000

p++;   //p=0x000C

显示数组元素可以使用这几种写法:

p[行][列]

(* (p+行))[列]

*(* (p+行)+列)

以下程序段将可以正确打印二维数组

#include <stdio.h>


main()
{

	int i, j;
	int a[2][3] = { 
		{1,2,3},
	    {4,5,6} 
	};
	//定义一个特殊的二级指针
	int(*p)[3];

	p = a;

	printf("在主函数中打印数组a[2][3]\n");
	for (i = 0; i < 2; i++)
	{
		for (j = 0; j < 3; j++)
		{
			printf("% d ", p[i][j]);
		}
		printf("\n");
	}

}

如何将一个二维数组作为参数传递给函数:

形式参数要写明数组的数据类型,例如这里是int ,并且是指针变量,而且每行有3个数据,即:

int(*p)[3] ,这样内存每+1,内存单元增长3*4=12

然后,可以在函数中像使用普通数组那样使用指针变量p调用数组中的元素,例如p[i][j]

#include <stdio.h>


func(int(*p)[3])
{
	int i, j;

	printf("\n在函数func中打印数组a[2][3]\n");
	for (i = 0; i < 2; i++)
	{
		for (j = 0; j < 3; j++)
		{
			printf("% d ", p[i][j]);
		}
		printf("\n");
	}

}


main()
{
	int a[2][3] = { 
		{1,2,3},
	    {4,5,6} 
	};

	func(a);
}

如何返回一个二维数组

首先,函数的返回值类型要是一个二级指针的形式:

int **func2()

然后,函数的返回值用一个特殊的二级指针接收,改指针指出了每行元素的个数,例如:

int (*p)[3];

表示是一个整型的二级指针,它每行的数据是3个,也就是p每加1,内存单元增长12个。

#include <stdio.h>

int **func2()
{
	static int a[2][3] = {
	{1,2,3},
	{4,5,6},
	};

	return a;
}


main()
{

	int i, j;
	int a[2][3] = { 
		{1,2,3},
	    {4,5,6} 
	};
	//定义一个特殊的二级指针
	int(*p)[3];


	p = func2();
	printf("\n在主函数中打印函数传递过来的数组\n");
	for (i = 0; i < 2; i++)
	{
		for (j = 0; j < 3; j++)
		{
			printf("% d ", p[i][j]);
		}
		printf("\n");
	}

}

其实这里用一级指针也可以正确返回二维数组的首地址,但是要在主函数中用带有维度的特殊二级指针正确转化一下。

但是这种返回方式编译器会给出警告,如果不想看到警告信息,可以这样返回二维数组:

#include <stdio.h>

int  (*func3())[3]
{
	static int a[2][3] = {
	   {1,2,3},
	   {4,5,6},
	};

	return a;
}

main()
{

	int i, j;
	int a[2][3] = { 
		{1,2,3},
	    {4,5,6} 
	};
	//定义一个特殊的二级指针
	int(*p)[3];

	p = func3();

	printf("\n在主函数中打印函数传递过来的数组\n");
	for (i = 0; i < 2; i++)
	{
		for (j = 0; j < 3; j++)
		{
			printf("% d ", p[i][j]);
		}
		printf("\n");
	}

}

这样,在返回值中指出了数组的维度,在接收值中也有相同的类型和维度,也就是指针类型完全相同,编译器就不会给出警告了。

传递二维数组,关键是要传递正确的数组首地址,并正确解读其中包含的维度。

参考链接:

https://blog.csdn.net/qq_33573235/article/details/79530792

https://www.cnblogs.com/zhixin/articles/3396789.html

https://blog.csdn.net/qq_39090164/article/details/79425247

https://www.cnblogs.com/qingergege/p/6917913.html

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Ubuntu】原生Ubuntu-dock 栏 安装与卸载

1.查看是否安装 Ubuntu-dock&#xff08;新版本的Ubuntu自带Ubuntu-dock version> 18.04&#xff09; gnome-extensions list 2.安装Ubuntu-dock sudo apt install gnome-shell-extension-ubuntu-dock 3.重启&#xff0c;一定要重启&#xff01;&#xff01;&#xff01;…

蓝桥杯真题讲解:填充(贪心)

蓝桥杯真题讲解&#xff1a;填充&#xff08;贪心&#xff09; 一、视频讲解二、正解代码 一、视频讲解 蓝桥杯真题讲解&#xff1a;填充&#xff08;贪心&#xff09; 二、正解代码 //填充&#xff1a;贪心 #include<bits/stdc.h> #define endl \n #define deb(x) c…

Spring Boot Configuration Processor使用

一、功能介绍 spring-boot-configuration-processor的作用就是将自己的配置你自己创建的配置类生成元数据信息&#xff0c;这样就能在你自己的配置文件中显示出来非常的方便。在META-INF目录下生成spring-configuration-metadata.json文件&#xff0c;从而告诉spring这个jar包…

2024年春招程序员个人简历范本(精选5篇|附模板)

HR浏览一份简历也就25秒左右,如果你连「好简历」都没有,怎么能找到好工作呢? 如果你不懂得如何在简历上展示自己,或者觉得怎么改简历都不出彩,那请你一定仔细读完。 Java开发工程师简历范本> 性别 男 年龄 24 学历 本科 张三 专业 计算机科学与技术 毕业院校 …

10 个高质量 AI 助手工具站点,你值得拥有的哦

以下 10 个 AI 助手工具站点&#xff0c;博主已全部验证&#xff0c;小伙伴们可放心使用的哈 说明&#xff1a; 博主倾向使用 1、2、3 这三款&#xff0c;尤其是 1 小程序真的很方便&#xff0c;手机就能操作&#xff0c;你懂的 文章目录 0. sora1. 微信小程序&#xff1a;AI 写…

聚道云软件连接器3月新增应用/产品更新合集

3月更新概要 新增应用&#xff1a; 应用1&#xff1a;华为云welink 应用2&#xff1a;易宝支付 应用3&#xff1a;励销云CRM 应用4&#xff1a;分贝通 应用5&#xff1a;灵当CRM 新增&更新功能 1、【流程】中增加流程树状管理 新增应用 应用1&#xff1a;华为云wel…

【C语言】【时间复杂度】Leetcode 153. 寻找旋转排序数组中的最小值

文章目录 题目时间复杂度概念时间复杂度的计算 解题思路代码呈现 题目 链接: link 时间复杂度 概念 时间复杂度是一种函数&#xff0c;定量地描述了该算法运行的时间。既然是一种函数&#xff0c;就涉及到自变量与因变量。因变量代表是时间复杂的规模&#xff0c;自变量是…

【Python】科研代码学习:二 dataclass,pipeline

【Python】科研代码学习&#xff1a;二 dataclass&#xff0c;pipeline 前言dataclasspipeline 前言 后文需要学习一下 transformers 库&#xff0c;必要时会介绍其他相关的重要库和方法。主要是从源代码、别人的技术文档学习&#xff0c;会更快些。 dataclass Python中的数…

AHU 汇编 实验五

实验名称&#xff1a;实验五 分支与循环程序设计 二、实验内容&#xff1a;从键盘输入一个四位的16进制数&#xff08;其中字母为大写&#xff09;&#xff0c;将其转化为二进制数提示输出。 实验过程&#xff1a; 源代码: data segmentbuff1 db Please input a number(H):$b…

CSS 02

1.复合选择器 &#xff08;1.1&#xff09;后代选择器 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0&q…

C++实现引用计数(二)

实现引用计数 引言实现集成开发环境项目结构实现代码运行结果 注意 引言 C中经常使用智能指针来管理内存。对于共享指针shared_ptr的原理&#xff1a;每当有一个指针指向这块内存&#xff0c;引用计数的值加一&#xff0c;每当一个指针不再指向这块内存&#xff0c;引用计数的…

CircuitBreaker断路器(服务熔断,服务降级)

分布式系统面临的问题: 复杂分布式体系结构中的应用程序有数十个依赖关系&#xff0c;每个依赖关系在某些时候将不可避免地失败。 1.服务雪崩 多个微服务之间调用的时候&#xff0c;假设微服务A调用微服务B和微服务C&#xff0c;微服务B和微服务C又调用其它的微服务&#xff…

【代码随想录】【二叉树】day18:二叉树的左下角的值,路径总和、构造二叉树

1二叉树左下角的值 左下角的值&#xff1a;最后一层最左侧的节点的值 递归 from collections import deque class TreeNode:def __init__(self,val,leftNone,rightNone):self.val valself.left leftself.right rightclass solution:def leftBottomNode(self,root):self.m…

计算机网络-第4章 网络层(1)

主要内容&#xff1a;网络层提供的两种服务&#xff1a;虚电路和数据报&#xff08;前者不用&#xff09;、ip协议、网际控制报文协议ICMP、路由选择协议&#xff08;内部网关和外部网关&#xff09;、IPv6,IP多播&#xff0c;虚拟专用网、网络地址转换NAT&#xff0c;多协议标…

C++作业day1

2> 试编程 提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数 要求使用C风格字符串完成 #include <iostream> #include <string.h>using namespace std;int main() {string str;cout << "请输…

文档版面分析数据集整理

版面分析数据集 这里整理了常用版面分析数据集&#xff0c;持续更新中&#xff1a; publaynet数据集CDLA数据集TableBank数据集D4LA 数据集DocLayNet文档布局分割数据集M6Doc数据集 版面分析数据集多为目标检测数据集&#xff0c;除了开源数据&#xff0c;用户还可使用合成工…

应用方案丨 D55125ADA A型漏电保护芯片

一、应用领域 新能源充电桩&#xff08;充电枪&#xff09;、智能空开&#xff08;智能微断开关&#xff09;等工业产品&#xff0c;以及电热水器、电烤箱、电烤炉等小家电产品。 二、功能介绍 D55125ADA 是一款高性能 CMOS 漏电保护器专用电路。芯片内部包含稳压电源、放大电…

【CSP试题回顾】201609-3-炉石传说

CSP-201609-3-炉石传说 解题思路 1.类和结构定义 Servant&#xff1a;定义了随从的结构&#xff0c;包含攻击力&#xff08;attack&#xff09;和生命值&#xff08;health&#xff09;。 MyPlayer&#xff1a;定义了玩家的类&#xff0c;包含玩家英雄的生命值&#xff08;h…

GRC宝石实验室鉴定证书,你真的读懂了吗?

随着人们审美需求的提升,兼具审美价值和收藏价值的彩色宝石成为越来越多人的心头好,市面上也随之涌现出许多宝石鉴定机构。在众多选择中,GRC宝石实验室以其高速度、专业化和高标准等诸多优势,成为许多宝石爱好者信赖的选择。 熟悉彩石圈的人,几乎都知道GRC宝石实验室,其总部位于…

网络模块使用Hilt注入

retrofit的异步回调方法已经做了线程切换&#xff0c;切换到了主线程 <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android"><uses-permission android:name"andr…