C语言中二维数组和二维数组分析

news2025/1/6 18:44:00

问题

最近有个同事发现一个问题:一个二维数组,想把它传给一个函数,具体代码如下:

char array[3][128];
void fun(char** array)
{
	strcpy(array[0],"confirm");
}

当我试图直接把二维数组名传给函数的时候,fun(array)编译会报错,类型不匹配。于是我就直接强转成所需要的类型fun((char**)array),这样就不会报错了,但是编译运行后,发现程序还是挂了。

指针

指针是一个特殊的变量,他里面存储的数值被解释为内存里的一个地址。要搞清楚一个指针,需要搞清楚指针的四方面的内容:

1.指针的类型

只要把指针声明语句里的指针名字去掉,也就是把指针变量取消,剩下的类型就是指针类型。
例如:

intptr; //指针类型为int
charptr; //指针类型为char
int ** ptr; //指针类型为int**
int (ptr)[3];//指针类型为int()[3];

2.指针所指向的类型

只要把指针变量和其中的*去掉,剩下的就是指针指向的类型

int ptr; //指针所指向的类型是int
char
ptr;//指针所指向的类型是char
int**ptr; //指针所指向的类型为int*
int (*ptr);//指针所指向的类型是int()[3]

3.指针的值

在C语言中,只要是变量,那么他就有实际的值。指针也一样,既然他是一个变量(指针变量),那么他也有值,他的值可以用printf(“%p”,ptr);打印出来。
在32位平台中,所有类型的指针的值是一个32位的整数。指针本身也是需要占用内存的,在32位平台,指针本身占据了4个字节的长度。可以使用sizeof(ptr)测试。

一维数组

对于一个一维数组int array[10]。数组名代表一个常量地址,该指针指向第一个元素,一维数组还是比较好理解的。

二维数组

二维数组本质是是以数组作为数组元素的数组。即“数组的数组”。假设我们定义了一个二维数组:

int array[2][3] = {{1,2,3},{4,5,6}};
经过测试分别打印:
array,array[0],&array[0],以及&array[0][0]等的地址都是相同的。

虽然这几种写法输出的地址是相同的额,但是实际意义是有区别的。

int * p1_array = array[0];
int * p2_array = &array[0][0];
int (*p3_array)[3] = &array[0];
int (*p4_array)[3] = array;
printf("array=%p\n",array);//打印:0X404008
printf("p1_array=%p\n",++p1_array);//输出:0X40400C
printf("p2_array=%p\n",++p2_array);//输出:0X40400C
printf("p3_array=%p\n",++p3_array);//输出:0X404014
printf("p4_array=%p\n",++p4_array);//输出:0X404014

依据以上实验分析:array[0],与&array[0][0]指针类型相同,都是int*,地址存放的都是整型数据,当指针自增1时,地址都便宜一个int类型的大小。
&arra[0]与array指针类型相同,都是int(*)[3]。他是一个数组指针,这个指针指向一个数组,数组中的数据类型是整型。他指针自增1时,地址都是偏移了一个数组长度3个int数据的大小)。
二维数组的各个表达式的含义:

array :是一个数组指针,类型为int()[3]。指向二维数组中的第一个元素(元素是一位数组)。指针每+1偏移的内存大小为一维数组的长度。
array[0],是一个int
的指针,指向一维数组的第一个元素的地址,指针每+1偏移的内存大小为int的长度。
&array[0],与array是一致的。
&array[0][0],与array[0]是一致的。

二级指针

先定义一个二级指针int**p,首先p是一个指针,在这个地址中存放的数据是指向一个整型数据的地址,注意这个指针存放的数据的地址。

int array[2][3] = {1,2,3,4,5,6};
int main(int argc ,char **argv) {
  int **p_data = (int **)array;
  printf("%p, %p\r\n", p_data, *p_data);
}
打印输出为:
0x3bec28, 0x1

看上面的例子,array的地址为0x3bec28,当把一个数组强转成二级指针的时候,p_data地址中存放的数据为1,因为二维数据中的第一个数据就是1,然而1并不是数据的地址,还是数据本身,所以一旦访问这个地址,就会导致段错误。

二维数组当函数入参

通过以上的讲解,知道二维数组名就是一个数组指针,我们的函数就可以像下面声明方式

void fun(int array[][3], int row);
void fun(int (*p_array)[3], int row);
void fun(int row, int column, int array[row][column]);

实参与入参

最后在看下,应该如何定义与实参相对应的形参的数据类型。

含义实参形参
二维 数组int array[4][6]int (*array)[6]
指针数组int *array[6]int** arry
数组指针int (*array)[6]int(* arry)[6]
二级指针int **arrayint** array

最后的分析

二维数组内存分配

在这里插入图片描述

二维数组是”数组的数组“,因而我们很容易产生二维数组名是一个二级指针的错觉,实际上并不是。实际上,不管是一维还是多维数组,都是内存中一块线性连续的空间,因此在内存级别上,其实都只是一维的,但是不同的定义使得表现形式不一样,从而有多维数组的概念。
访问数组元素其实非常简单,原因就在于元素在内存中的线性排列。这样对一维数组的访问:
arr1[index] = (arr1+indexsizeof(Type));
对二维数组的访问:
arr2[i][j]=(arr2+(icol+j)*sizeof(Type));

结论

为甚恶魔不能将二维数组名强制转换成二级指针

int main()
{
    int data[2][3] = {{3,8,4},{4,5,6}};
    int** ptr = (int **)data;
    printf("%p,%p\n",ptr,data);
    printf("%p\n",ptr[0]);
    return 0;
}

ptr和data本质上都是指针,在赋值后,他们指向了同一片内存空间
在这里插入图片描述64位机器中,int占4个字节,int *占8个字节,因此ptr[0]就是data[0][0]和data[0][1]拼接起来的结果,故ptr[0]的值为0x800000003。可以看到,这个值并非data数组首元素的地址。因此当进行如下调用fun(ptr,2,3)时,试图访问的是0x800000003的未知空间,因此发生段错误。

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

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

相关文章

接入淘宝API接口,获取店铺详情轻松迈入大数据时代

随着电商行业的飞速发展,API接口已经成为了一种不可或缺的技术。作为中国最大的电商平台,淘宝也拥有着自己的API接口。本文将重点讲解淘宝API接口技术,包括其基本原理、使用方法、优缺点等方面,帮助大家进一步了解淘宝API接口的奥…

年度发布 | MeterSphere一站式开源持续测试平台发布v2.10 LTS版本

2023年5月25日,MeterSphere一站式开源持续测试平台正式发布v2.10 LTS版本。这是继2022年5月发布v1.20 LTS版本后,MeterSphere开源项目发布的第三个LTS(Long Term Support)版本。MeterSphere开源项目组将对MeterSphere v2.10 LTS版…

一个完整的APP定制开发流程是怎样的?

随着移动互联网的发展,越来越多的 APP应用软件进入人们的生活,让我们的生活更便捷、更舒适。而随着互联网技术的进步,移动互联网应用软件开发行业也越来越成熟,为了适应市场需求,各种功能强大、性能良好的 APP应用软件…

电商API接口系列封装(提高工程师时效性,降低错误率)

API接口封装是指将原本分散在各个模块或系统中的API接口进行封装,形成一个可重用且独立的API库。通过API接口封装,可以提高系统的可维护性和可扩展性,降低开发成本和维护难度。 API接口封装通常分为两个步骤: 定义API接口&#x…

涨知识!一文带你读懂空气质量数据(附Java 和小程序接入示例代码)

空气污染对人类健康和环境造成了巨大的危害。据统计,每年因空气污染导致的早逝人数超过数百万人。长期暴露在污染物中,人们易患呼吸系统疾病、心血管疾病、癌症等。此外,空气污染还对生态系统、农作物和能源消耗产生负面影响。 在解决空气质…

首届百度商业AI技术创新大赛启动 点燃AIGC革新“星火”

随着生成式AI在全球范围的热议,AIGC前沿技术也在快速迭代,正如百度CEO李彦宏所说 “人工智能发生了方向性改变,从辨别式AI走向生成式AI,生成式AI会带来极大的效率提升” 。而这一领域的发展,将推动AI产品应用深化&…

Spark入门这篇就够了(万字长文)

本文已收录至Github,推荐阅读 👉 Java随想录 文章目录 Spark是什么Spark组件Spark的优势Word Count Spark基本概念ApplicationDriverMaster和WorkerExecutorJobTaskStageStage的划分 窄依赖 & 宽依赖ShuffleRDDDAG Spark执行流程Spark运行模式RDDRDD…

项目开发-依赖倒置、里式替换、接口隔离的应用深入理解

文章目录 前言依赖倒置定义不符合依赖倒置原则是什么样子😄完善 里式替换定义具体应用 接口隔离定义具体应用 前言 最近在做.net项目和学习这个设计模式中的依赖倒置和工厂方法,这个过程当中发现在开发这个.net项目中有很多不合理的地方,就是…

(转载)基于粒子群算法的多目标搜索算法(matlab实现)

1 理论基础 在实际工程优化问题中,多数问题是多目标优化问题。相对于单目标优化问题,多目标优化问题的显著特点是优化各个目标使其同时达到综合的最优值。然而,由于多目标优化问题的各个目标之间往往是相互冲突的,在满足其中一个…

KD7742交直流耐压绝缘分析仪

一、产品简介 KD7742交直流耐压绝缘分析仪具有交/直流耐压、绝缘电阻等项目的测试分析功能,能显示电压、电流和电阻的波形图以及趋势图,以便更直观的监测分析绝缘性能和绝缘崩溃时的各项指标,适用于高要求的测试分析场合。 产品具有测试参数范…

vue实现二维码识别功能 读取二维码内容

我们可以访问 https://www.wwei.cn/?frombdtp 在输入框中输入文本 然后 点击生成二维码 他就会给我生成一个对应信息的二维码图片 我们可以复制到本地 打开vue项目 先引入依赖 npm install canvas jsqr然后组件编写代码如下 <template><div><input type&qu…

首届中国元宇宙应用场景大赛成果发布暨河畔元宇宙论坛圆满落幕

5月26日下午&#xff0c;首届中国元宇宙应用场景大赛成果发布暨河畔元宇宙论坛在北京城市副中心圆满落幕。活动在通州区委、区政府指导下&#xff0c;由北京大数据协会元宇宙专业委员会主办&#xff0c;中国质量认证中心、绿色智能新经济产业联盟、中关村元宇宙产业发展联盟协办…

【大数据处理与可视化】八、文本数据分析

【大数据处理与可视化】八、文本数据分析 实验目的实验内容实验步骤一、案例——商品评价分析1、读取数据&#xff0c;并转换成DataFrame对象进行展示。2、从输出的结果看&#xff0c;多条评价信息是没用且重复的&#xff0c;所以&#xff0c;要用pandas中的drop_duplicates()方…

Java笔记039-多用户即时通信系统

目录 多用户即时通信系统 项目介绍 项目演示 项目结构 涉及到Java的技术 项目开发流程 需求分析 界面设计 功能实现-用户登录 1、功能说明 2、思路分析程序框架图 3、代码实现 功能实现-拉去在线用户列表 1、功能说明 2、思路分析程序框架图 3、代码实现 功能…

什么是LIS系统?LIS系统的优势有哪些?

一、LIS系统 LIS系统(Laboratory Information System) 即 实验室&#xff08;检验科&#xff09;信息系统&#xff0c;它是医院信息管理的重要组成部分之一。 LIS系统是实验室信息管理系统&#xff0c;是医院信息管理的重要组成部分。它采用智能辅助功能&#xff0c;自动接收检…

【分布式文件存储】MinIO部署及实现文件上传下载

目录 概述 MinIO集群部署 准备docker-compose.yml 测试启动 MinIO用户管理 Buckets管理 创建Buckets MinIO客户端 引入依赖 文件上传下载Demo 调用API碰到的问题 概述 MinIO | 高性能, Kubernetes 原生对象存储 MinIO是全球领先的对象存储先锋&#xff0c;目前在全世…

TCP协议的RST标志

下文中的内容多数来自【参考】中的文章&#xff0c;这边进行一个整理和总结&#xff0c;后续会慢慢增加出现各个 RST 包的测试代码&#xff0c;便于理解。 TCP的 “断开连接” 标志 RST 标志 Reset&#xff0c;复位标志&#xff0c;用于非正常地关闭连接。它是 TCP 协议首部里…

企业产品操作手册,真的很有必要吗?

产品操作手册是一种对于产品使用者而言非常重要的工具。它是一份向用户介绍产品使用方法和功能的文档&#xff0c;可以提供关于产品的详细信息&#xff0c;解答用户的疑问&#xff0c;并帮助用户快速上手使用产品。 产品操作手册的必要性&#xff1a; 一、提高用户使用体验 …

Matlab论文插图绘制模板第95期—双向柱状图

在之前的文章中&#xff0c;分享了很多Matlab柱状图的绘制模板&#xff1a; 进一步&#xff0c;再来看一种特殊的柱状图&#xff1a;双向柱状图。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中&#xff0c;加群的朋友请自行下载。…

抖音seo源码如何开发部署?

前言&#xff1a;抖音seo源码&#xff0c;抖音矩阵系统源码搭建&#xff0c;抖音矩阵同步分发。抖音seo源码部署是需要对接到这些正规接口再来做开发的&#xff0c;目前账号矩阵程序开发的功能&#xff0c;围绕一键管理多个账号&#xff0c;做到定时投放&#xff0c;关键词自动…