IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> C语言(动态开辟二维数组 指针数组、数组指针、一维数组模拟开辟) -> 正文阅读

[数据结构与算法]C语言(动态开辟二维数组 指针数组、数组指针、一维数组模拟开辟)

有了malloc函数的基本素养,就能够开辟一个一维动态数组。

而一个二维数组需要如何开辟呢?好像之前的malloc素养不够用了。


?我们这里以开辟一个四行四列的二维数组为例。

指针数组开辟

先是开辟语句:?

int** p = (int**)malloc(sizeof(int*) * 4);
for (int i = 0; i < 4; i++)
{
	p[i] = (int*)malloc(sizeof(int)*4);
}

首先我们开辟了内含四个指针的指针数组:

随后我们通过一个循环依次开辟他们的每个地址后所跟随的长度为四的整型数组:

这样也就使得我们能够通过每一个指针数组里的地址访问到相应的行列,每一个地址可以找到对应的行开头,通过行开头能够找都后续的列元素,而与之对应的长度为四的整型数组就可以存储该行所有的列元素,一个二维动态数组也就这样建好啦!

直接用指针数组来进行开辟十分符合我们的思维习惯,所以非常好理解,但是他也同样具备释放较为麻烦,并且无法保证一行最后一个元素与下一行第一个元素是连续存储的问题。

用指针数组开辟二维数组,一行最后一个元素与下一行第一个元素并不是连续存储:

且具备内存较难释放的问题:

我们需要先释放存储列元素的数组,然后释放我们之前所开辟的行指针数组。

//先释放每行的元素
for(int i=0; i<4; i++)
{
	free(p[i]);
}
//最后释放二级指针
free(p);

?数组指针开辟

数组指针的开辟方法就解决了指针数组开辟释放难、行最后与下一行最前元素不连续的问题。

const int ROW = 4;
const int COL = 4;//数组指针列数可以用常量定义
int(*pp)[COL] = (int(*)[COL])malloc(ROW * COL * sizeof(int));

?我们告诉了编译器该数组的列数为COL,接下来在开辟过程他会为我们做如下事情。

当编译器检测到我们列元素达到COL时,他会知道需要开始下一列了,于是将我们的十六个元素划分为了四个行?。

由于我们数组一次动态分配完毕,那自然我们一行的最后一个元素也就与下一行的第一个元素对应上了。

整个释放过程也变得及其简单,直接一个free(p)就完了,确实比原先的指针数组开辟简化不少。

但我们仍然需要注意到:他的列数是需要给出固定值的,这也是他的缺陷所在。

一维数组模拟开辟

?其实这便是用二维数组的思维来管理一维数组,与其他的一维数组具体差异在于赋值与打印方面

int* ppp = (int*)malloc(ROW*COL*sizeof(int));
//赋值
for(int i=0; i<ROW ;i++)
	for (int j = 0; j < COL; j++)
	{
		ppp[i * ROW + j] = i * ROW + j;
	}
//打印
printf("一维数组模拟二维数组\n");
for  (int i= 0; i < ROW; i++)
	for (int j = 0; j < COL; j++)
	{
		printf("%-4d ", ppp[i * ROW + j]);
		if (j == COL - 1)
			printf("\n");
	}
free(ppp);

通过 i*ROW+j 的索引来映射他在二维数组中的位置

实验代码(供以调试)?

#include<stdio.h>
#include<stdlib.h>

//动态内存申请二维数组
//1.指针数组
//每一行元素地址连续   但是不能保证上一行的尾和下一行的头挨着
//int main()
//{
//	int** p = (int **)malloc(3*sizeof(int*));//竖的那个数组申请好了
//
//	for(int i=0; i<3; i++)
//	{
//		p[i] = (int*)malloc(4*sizeof(int));
//	}
//
//	for(int i=0; i<3; i++)
//	{
//		for(int j=0; j<4; j++)
//		{
//			printf("%p\n", &p[i][j]);
//		}
//	}
//	for(int i=0; i<3; i++)
//	{
//		free(p[i]);
//	}
//	free(p);
//	return 0;
//}

//2.用数组指针
//int main()
//{
//	int (*p)[4] = (int(*)[4])malloc(3*4*sizeof(int));
//
//	for(int i=0; i<3; i++)
//	{
//		for(int j=0; j<4; j++)
//		{
//			printf("%p\n", &p[i][j]);
//		}
//	}
//	free(p);
//
//	return 0;
//}

//3.用二维数组的思想去管理申请的一维数组
//int main()
//{
//	int *p = (int*)malloc(3*4*sizeof(int));
//
//	for(int i=0; i<3; i++)
//	{
//		for(int j=0; j<4; j++)
//		{
//			p[i*4+j] = 1;
//			printf("%p\n", &p[i*4+j]);	
//		}
//	}
//
//	free(p);
//
//	return 0;
//}

int main()
{
	//动态开辟二维数组
	//1  指针数组开辟
	// 释放较为麻烦,并且无法保证一行最后一个元素与下一行第一个元素是连续存储的
//	int** p = (int **)malloc(3*sizeof(int*));//竖的那个数组申请好了
//
//	for(int i=0; i<3; i++)
//	{
//		p[i] = (int*)malloc(4*sizeof(int));
//	}
	int** p = (int**)malloc(sizeof(int*) * 4);
	for (int i = 0; i < 4; i++)
	{
		p[i] = (int*)malloc(sizeof(int)*4);
	}
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			p[i][j] = j;
		}
	}
	printf("指针数组开辟二维数组\n");
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			printf("%d ",p[i][j]);
			if (j == 3)
				printf("\n");
		}
	}
	//先释放每行的元素
	for(int i=0; i<4; i++)
	{
		free(p[i]);
	}
	//最后释放二级指针
	free(p);

	//2. 数组指针开辟二维数组
	//	int (*p)[4] = (int(*)[4])malloc(3*4*sizeof(int));
//
//	for(int i=0; i<3; i++)
//	{
//		for(int j=0; j<4; j++)
//		{
//			printf("%p\n", &p[i][j]);
//		}
//	}
	//释放简单,一行最后一个元素与下一行第一个元素连续存储,但列数需固定,无法自定义列数
	const int ROW = 4;
	const int COL = 4;//数组指针列数可以用常量定义
	printf("数组指针开辟二维数组,打印地址\n");
	int(*pp)[COL] = (int(*)[COL])malloc(ROW * COL * sizeof(int));
	for(int i=0; i<4; i++)
	{
		for(int j=0; j<4; j++)
		{
			printf("%p\n", &pp[i][j]);
		}
	}
	free(pp);

	//3. 一维数组当作二维数组来管理
	//可使用变量来作为行数和列数,释放简单,但脑海里需要绕弯子易出错,赋值与打印十分麻烦

	int* ppp = (int*)malloc(ROW*COL*sizeof(int));
	//赋值
	for(int i=0; i<ROW ;i++)
		for (int j = 0; j < COL; j++)
		{
			ppp[i * ROW + j] = i * ROW + j;
		}
	//打印
	printf("一维数组模拟二维数组\n");
	for  (int i= 0; i < ROW; i++)
		for (int j = 0; j < COL; j++)
		{
			printf("%-4d ", ppp[i * ROW + j]);
			if (j == COL - 1)
				printf("\n");
		}
	free(ppp);
}

?实验结果:

(如有问题,欢迎指正)?

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-12-02 17:01:12  更:2021-12-02 17:01:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 14:31:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码