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

news/2024/11/24 2:09:32/

问题

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

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.ppmy.cn/news/101833.html

相关文章

游戏配音怎么弄的?分享三个游戏配音制作方法

随着时代的发展,人们对于配音的要求也越来越高,除了传统的文字配音外,现在又出现了游戏配音。其实游戏配音也是有一定门槛的,并不是人人都可以做得好的。但是如果你想要拥有一位自己喜欢的游戏角色,那么你就要学会游戏…

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

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

[转]Github进行fork后如何与原仓库同步

问题场景: 新公司要求所有的代码提交都要先通过自己的库提交到主repo上去,所以先在gitlab网页上fork出一个自己的库,在本地修改完代码后提交到远程自己库上,然后在gitlab网页上发起一个merge request请求,然后等待主r…

接口的讲解

在这里之前我想童鞋们都学习过了springmvc。mybatis-plus。Springboot等一些框架 那么下面我们就整合这些框架 我们通过写crud这些接口 写接口的第一步就是引入pom文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://m…

六级备考19天|CET-6|翻译练习|真题·青藏铁路|9:30~11:20

目录 1 中文 2 练习 ​ 3 答案​ 4 解析 5 订正 复习 1 中文 2 练习 3 答案 4 解析 铁路 railway/railroad 全长 with a total length of 其中xxx在海拔4000多米以上&#xff0c;非限制性定语从句&#xff0c;960 kilometers of which are over 400 me…

FFMPEG常用命令 音视频合并

目录 一、音频合并 1.获取音频时长 2.合并两段音频 3.合并音频插入空白 二、视频加背景图 三、音视频合成 1.保留视频声音 2.不保留视频声音 四、合并视频 本文将用几个实例&#xff0c;介绍ffmpeg命令的综合使用&#xff0c;主要涉及音频处理、视频处理和音视频合成。…

4种不改变格式将PDF转Word文档的方法

Microsoft Word 使用户能够按照自己的喜好创建和编辑文档。当用户发现一些PDF资源有助于补充他们的文书工作时&#xff0c;他们可能希望将PDF插入到Word文档中&#xff0c;特别是插入多页PDF文件&#xff0c;以进行编辑或其他目的。将 PDF 插入 Word 文档非常容易&#xff0c;只…

【*1900 DP+Tree】CF9D

Problem - 9D - Codeforces 题意&#xff1a; 思路&#xff1a; 计数问题&#xff0c;考虑计数DP 因为它是二叉树&#xff0c;比较特殊&#xff0c;所以可以考虑一下线性DP 按照题目最后要算的答案&#xff0c;状态可以这样设计&#xff1a; 设dp[i][j]表示树高为i&#x…