C语言第九弹---二维数组

news2024/10/6 13:50:10

f0f757dbb25746d2a2f6b377c486b826.jpeg

 

 ✨个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】

二维数组

1、二维数组的创建

1.1、二维数组的概念

​1.2、⼆维数组的创建

2、二维数组的初始化

2.1、不完全初始化

​2.2、完全初始化

​2.3、按照行初始化

​2.4、初始化时省略行,但是不能省略列

​3、⼆维数组的使用

3.1、⼆维数组的下标

3.2、⼆维数组的输入和输出

4、⼆维数组在内存中的存储

5、C99中的变长数组

​6、数组练习

总结


 

 

1、二维数组的创建


1.1、二维数组的概念

前面学习的数组被称为⼀维数组,数组的元素都是内置类型的,如果我们把⼀维数组做为数组的元素,这时候就是⼆维数组,⼆维数组作为数组元素的数组被称为三维数组,⼆维数组以上的数组统称为多维数组。

22fc896a738b4117926a0f5549d80533.png

1.2、⼆维数组的创建


那我们如何定义⼆维数组呢?语法如下:
 

type arr_name[常量值1][常量值2];
  |      |       |       |
  |      |       |       |
类型名  数组名  行数     列数
例如:
int arr[3][5];
double data[2][8];


解释上述代码中出现的信息
• 3表示数组有3行
• 5表示每⼀行有5个元素
• int 表示数组的每个元素是整型类型
• arr 是数组名,可以根据自己的需要指定名字
data数组意思基本⼀致。

2、二维数组的初始化


在创建变量或者数组的时候,给定⼀些初始值,被称为初始化。
那⼆维数组如何初始化呢?像⼀维数组⼀样,也是使用大括号初始化的。


2.1、不完全初始化

int arr1[3][5] = {1,2};
int arr2[3][5] = {0};

88fcfe40f7954a708b8a2e599c9601dd.png
2.2、完全初始化

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

61778c8888cf4507896909230fb96ca7.png
2.3、按照行初始化

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

e602baf6228a4f4aa390652d9af76db4.png
2.4、初始化时省略行,但是不能省略列

int arr5[][5] = {1,2,3};
int arr6[][5] = {1,2,3,4,5,6,7};
int arr7[][5] = {{1,2}, {3,4}, {5,6}};

ee38b7eb620c4e0086e090854c44e3d9.png
3、 ⼆维数组的使用


3.1、⼆维数组的下标


当我们掌握了⼆维数组的创建和初始化,那我们怎么使用⼆维数组呢?
其实⼆维数组访问也是使用下标的形式的,⼆维数组是有行和列的,只要锁定了行和列就能唯⼀锁定数组中的⼀个元素。
C语言规定,⼆维数组的行是从0开始的,列也是从0开始的,如下所示:

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

3c8c79df07d7439f88eb3986ce6d1e56.png

此处也可以用大括号将一行的数值用大括号括起来,这样更容易理解。

#include <stdio.h>
int main()
{
	int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6} ,{3,4,5,6,7} };//大括号形式
	printf("%d\n", arr[2][4]);
	return 0;
}


二维数组中括号的第一个表示行号,第二个表示列号,比如,我们说:第2行,第4列,快速就能定位出7。

#include <stdio.h>
int main()
{
 int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
 printf("%d\n", arr[2][4]);
 return 0;
}


输出的结果如下:

fb93913d8dc647e188da8f3e9921b0b4.png

 

3.2、⼆维数组的输入和输出


访问⼆维数组的单个元素我们知道了,那如何访问整个⼆维数组呢?
其实我们只要能够按照⼀定的规律产生所有的行和列的数字就行;以上⼀段代码中的arr数组为例,行的选择范围是0 ~ 2,列的取值范围是0 ~ 4,所以我们可以借助循环实现生成所有的下标。 

#include <stdio.h>
int main()
{
	int arr[3][5] = {0};//初始化,全部初始化为0
	int i = 0;//遍历行
	//输入
	for (i = 0; i < 3; i++) //产生行号
	{
		int j = 0;
		for (j = 0; j < 5; j++) //产生列号
		{
			scanf("%d", &arr[i][j]); //输入数据
		}
	}
	//输出
	for (i = 0; i < 3; i++) //产生行号
	{
		int j = 0;
		for (j = 0; j < 5; j++) //产生列号
		{
			printf("%d ", arr[i][j]); //输出数据
		}
		printf("\n");
	}
	return 0;
}


输入和输出的结果:

3c29c56cfa2a4a429ccce10dd22e6c4f.png

4、 ⼆维数组在内存中的存储


像⼀维数组⼀样,我们如果想研究⼆维数组在内存中的存储方式,我们也是可以打印出数组所有元素的地址的。代码如下:

#include <stdio.h>
int main()
{
 int arr[3][5] = { 0 };
 int i = 0;
 int j = 0;
 for (i = 0; i < 3; i++)
 {
 for (j = 0; j < 5; j++)
 {
 printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
 }
 }
 return 0;
}


输出的结果:c9ae601878004c4cb1bc775540e7db74.png

 

从输出的结果来看,每⼀行内部的每个元素都是相邻的,地址之间相差4个字节,跨行位置处的两个元素(如:arr[0][4]和arr[1][0])之间也是差4个字节,所以⼆维数组中的每个元素都是连续存放的。
如下图所示:

9a86d5d16e674f8fa3550c82db017887.png

了解清楚⼆维数组在内存中的布局,有利于我们后期使用指针来访问数组的学习。

5、C99中的变长数组


在C99标准之前,C语言在创建数组的时候,数组大小的指定只能使用常量、常量表达式,或者如果我们初始化数据的话,可以省略数组大小。
如:

int arr1[10];//数组大小为常量
int arr2[3+5];//数组大小为常量表达式
int arr3[] = {1,2,3};//不指定数组大小


这样的语法限制,让我们创建数组就不够灵活,有时候数组大了浪费空间,有时候数组又小了不够用的。

C99中给⼀个变长数组(variable-length array,简称 VLA)的新特性,允许我们可以使用变量指定数组大小。
请看下面的代码:

int n = a+b;
int arr[n];//变量指定数组大小


上面示例中,数组 arr 就是变长数组,因为它的长度取决于变量 n 的值,编译器没法事先确定,只有运行时才能知道 n 是多少。


变长数组的根本特征,就是数组长度只有运行时才能确定,所以变长数组不能初始化。

它的好处是程序员不必在开发时,随意为数组指定⼀个估计的长度,程序可以在运行时为数组分配精确的长度。有⼀个比较迷惑的点,变长数组的意思是数组的大小是可以使用变量来指定的,在程序运行的时候,根据变量的大小来指定数组的元素个数,而不是说数组的大小是可变的。数组的大小⼀旦确定就不能再变化了。
遗憾的是在VS2022上,虽然支持大部分C99的语法,没有支持C99中的变长数组,没法测试;下面是在gcc编译器上测试,可以看⼀下

#include <stdio.h>
int main()
{
 int n = 0;
 scanf("%d", &n);//根据输⼊数值确定数组的⼤⼩
 int arr[n];
 int i = 0;
 for (i = 0; i < n; i++)
 {
 scanf("%d", &arr[i]);
 }
 for (i = 0; i < n; i++)
 {
 printf("%d ", arr[i]);
 }
 return 0;
}


第⼀次测试,我给n中输⼊5,然后输⼊5个数字在数组中,并正常输出
第⼆次测试,我给n中输⼊10,然后输⼊10个数字在数组中,并正常输出

af92cc9b8b2143b4bf2c99f7f0a9ac81.png
6、数组练习


练习1:多个字符从两端移动,向中间汇聚
编写代码,演示多个字符从两端移动,向中间汇聚

 

思想:

第一步把arr1头尾的字符拷贝到arr2头尾的位置,然后将arr2打印。

第二步把arr1第二个和倒数第二个位置字符拷贝arr2第二个和倒数第二个位置,然后打印arr2。

.....

用left控制左边下标,right控制右边下标。第一次拷贝完之后则left++,right--,直到左边定义的left > right则停止循环,即left<=right进入循环。

#include <stdio.h>
int main()
{
 char arr1[] = "welcome to bit...";
 char arr2[] = "#################";
 int left = 0;
 int right = strlen(arr1)-1;
 printf("%s\n", arr2);
 while(left<=right)
 {
 Sleep(1000);
 arr2[left] = arr1[left];
 arr2[right] = arr1[right];
 left++;
 right--;
 printf("%s\n", arr2);
 }
 retutn 0;
}


练习2:⼆分查找(前提为有序)
在⼀个升序的数组中查找指定的数字n,很容易想到的⽅法就是遍历数组,但是这种方法效率比较低。
比如我买了⼀双鞋,你好奇问我多少钱,我说不超过300元。你还是好奇,你想知道到底多少,我就让你猜,你会怎么猜?你会1,2,3,4...这样猜吗?显然很慢;⼀般你都会猜中间数字,比如:150,然后看大了还是小了,这就是⼆分查找,也叫折半查找。

思想:

第一次找中间位置,如果大于中间这个位置的值,则中间位置的下一个为第二次查找的左下标。如果小于中间这个位置的值,则中间位置前一个为第二次查找的右下标。

c7eab837a2044cef85d3cbc60724f290.png

 

#include <stdio.h>
int main()
{
 int arr[] = {1,2,3,4,5,6,7,8,9,10};
 int left = 0;
 int right = sizeof(arr)/sizeof(arr[0])-1;
 int key = 7;//要找的数字
 int mid = 0;//记录中间元素的下标
 int find = 0;
 while(left<=right)
 {
 mid = (left+right)/2;//初始中间值
 if(arr[mid]>key)
 {
 right = mid-1;
 }
 else if(arr[mid] < key)
 {
 left = mid+1;
 }
 else
 {
 find = 1;
 break;
 }
 }
 if(1 == find )
 printf("找到了,下标是%d\n", mid);
 else
 printf("找不到\n");
}


求中间元素的下标,使用 mid = (left+right)/2 ,如果left和right比较大的时候可能存在问
题(left和right相加时超过该类型最大值),可以使用下面的方式:
 

mid = left+(right-left)/2;


总结


本篇博客就结束啦,谢谢大家的观看,如果公主少年们有好的建议可以留言喔,谢谢大家啦!
 

 

 

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

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

相关文章

C++实用教程(四):面向对象核心多态 笔记

推荐B站视频&#xff1a;C现代实用教程(四):面向对象核心多态_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV15v4y1M7fF/?spm_id_from333.999.0.0&vd_sourcea934d7fc6f47698a29dac90a922ba5a3 本项目通用的tasks.json文件和launch.json tasks.json {"versi…

TMS智慧园区物流系统:提升化工园区管理效率的最佳选择

在化工行业园区中&#xff0c;企业面临着诸多痛点&#xff0c;如人工管理流程复杂、园区堵车、园区安全管理不到位、设备资产管理缺失、环境管理混乱无章、数据无法追溯等。这些问题不仅影响企业的生产效率和经济效益&#xff0c;还可能对员工的生命安全和环境造成潜在威胁。为…

uniapp封装公共的方法或者数据请求方法

仅供自己参考&#xff0c;不是每个页面都用到这个方法&#xff0c;所以我直接在用到的页面引用该公用方法&#xff1a; 1、新建一个util.js文件 export const address function(options){return new Promise((resolve,reject)>{uni.request({url:"https://x.cxniu.…

C# 命名管道管道NamedPipeServerStream使用

NamedPipeServerStream 是 .NET Framework 和 .NET Core 中提供的一个类&#xff0c;用于创建和操作命名管道的服务器端。命名管道是一种在同一台计算机上或不同计算机之间进行进程间通信的机制。 命名管道允许两个或多个进程通过共享的管道进行通信。其中一个进程充当服务器&…

CentOS网络配置进阶:深入研究network服务和NetworkManager

前言 如果你正在使用CentOS系统,并且想要深入了解网络管理和配置,那么本文肯定适合你!在这篇文章中,作者深入探讨了CentOS中的两种网络管理方式:network服务和NetworkManager。通过详实的讲解和实用的示例,你将会学习到如何使用这两种工具来管理网络接口、配置IP地址、网…

外贸邮件群发软件有哪些?邮件群发的系统?

外贸邮件群发软件哪个比较好&#xff1f;外贸开发信软件推荐&#xff1f; 对于许多外贸企业来说&#xff0c;邮件营销是一种非常有效的推广方式。那么&#xff0c;外贸邮件群发软件就成为了必备的工具。蜂邮EDM将为你揭秘几款主流的外贸邮件群发软件&#xff0c;助你更好地开展…

用javadoc生成springboot的文档

概述&#xff1a;生成 Spring Boot 项目的 JavaDoc 文档与生成普通的 Java 项目类似。 目录 第一步&#xff1a;创建一个springboot项目 第二步&#xff1a;编写pom文件 第三步&#xff1a;运行 Maven 命令生成 JavaDoc 第四步&#xff1a;查看结果 第一步&#xff1a;创建…

海外媒体发稿:出口贸易媒体发稿推广8种方法让您事半功倍-华媒舍

通过出口贸易媒体发稿可以帮助企业拓展市场、提升知名度&#xff0c;从而取得更好的出口贸易业绩。在进行媒体发稿时&#xff0c;需要确定目标受众&#xff0c;编写吸引人的标题&#xff0c;提供有价值的内容&#xff0c;并选择合适的媒体平台和发布时间。通过持续改进和优化&a…

自然语言NLP学习

2-7 门控循环单元&#xff08;GRU&#xff09;_哔哩哔哩_bilibili GRU LSTM 双向RNN CNN 卷积神经网络 输入层 转化为向量表示 dropout ppl 标量 在物理学和数学中&#xff0c;标量&#xff08;Scalar&#xff09;是一个只有大小、没有方向的量。它只用一个数值就可以完全…

docker之部署青龙面板

青龙面板是一个用于管理和监控 Linux 服务器的工具&#xff0c;具有定时运行脚本任务的功能。在实际情况下也可以用于一些定期自动签到等任务脚本的运行。 本次记录下简单的安装与使用&#xff0c;请提前安装好docker&#xff0c;参考之前的文章。 一、安装部署 1、拉取镜像 # …

小迪安全21WEB 攻防-JavaWeb 项目JWT 身份攻击组件安全访问控制

#知识点&#xff1a; 1、JavaWeb 常见安全及代码逻辑 2、目录遍历&身份验证&逻辑&JWT 3、访问控制&安全组件&越权&三方组件 Java&#xff1a;大部分都是第三方插件出现漏洞 webgoat的搭建&#xff1a;——java靶场 JDK版本要求&#xff1a;11.0…

图形绘制QGraphicsView、QGraphicsScene、QGraphicsItem、Qt GUI

QGraphicsView、QGraphicsScene、QGraphicsItem 和 Qt GUI&#xff08;QGuiApplication&#xff09;可以用来构建和管理基于图形的用户界面。 一、它们之间的关系&#xff1a; QGuiApplication 作为应用程序的基础&#xff0c;提供了窗口和事件管理等功能。 QGraphicsView 则…

15- OpenCV:模板匹配(cv::matchTemplate)

目录 1、模板匹配介绍 2、cv::matchTemplate 3、模板匹配的方法&#xff08;算法&#xff09; 4、代码演示 1、模板匹配介绍 模板匹配就是在整个图像区域发现与给定子图像匹配的小块区域。 它可以在一幅图像中寻找与给定模板最相似的部分。 模板匹配的步骤&#xff1a; &a…

中移(苏州)软件技术有限公司面试问题与解答(4)—— virtio所创建的设备2

接前一篇文章&#xff1a;中移&#xff08;苏州&#xff09;软件技术有限公司面试问题与解答&#xff08;4&#xff09;—— virtio所创建的设备1 在上一篇文章中&#xff0c;对于面试所提出的问题“virtio会创建哪些设备&#xff1f;”&#xff0c;有了初步答案&#xff0c;即…

基于python和定向爬虫的商品比价系统实现

目录 前言 一、系统设计 1. 系统需求分析 2. 系统设计思路 二、系统实现 1. 爬虫部分 2. 比价部分 3. 完整系统代码 三、系统优化 1. 多线程爬取 2. 引入数据库 四、总结 前言 商品比价系统是一种可以帮助用户快速找到最优价格商品的系统。本文将介绍如何使用pyth…

开源的API Gateway项目- Kong基于OpenResty(Nginx + Lua模块)

Kong 是一个在 Nginx 内运行的开源 API 网关和微服务抽象层。它是用于处理 API 流量的灵活、可扩展、可插入的工具。 Kong 提供了以下功能&#xff1a; 用户登录&#xff1a;Kong 提供了多种认证插件&#xff0c;像 JWT、OAuth 2.0 等&#xff0c;可以满足用户登录需求。Toke…

Linux---文件系统

在基础IO中&#xff0c;我们所讲的都是对被打开文件的管理&#xff0c;但是不是所有的文件都是被打开的&#xff0c;对那些在磁盘中保存的没有被打开的文件&#xff0c;我们同样也需要管理&#xff0c;这个就像是快递站中等待被人取走的快递&#xff0c;我们需要将它们分门别类…

Java项目:15 springboot vue的智慧养老手表管理系统

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本系统共分为两个角色&#xff1a;家长&#xff0c;养老院管理员 框架&#xff1a;springboot、mybatis、vue 数据库&#xff1a;mysql 5.7&…

Fink CDC 1.0 至3.0的从古至今

本文主要分享Flink CDC 1.0 至3.0的发展历程,了解其背后的关键特性和发展趋势,探讨其在大数据领域的影响和价值。 一、CDC概述 CDC是一种用以掌控数据变化的软件架构(技术思路),用于捕获和传递数据库中发生的数据变化。当数据库中发生增(INSERT)/删(DELETE)/改(UPD…

#GPU|LLM|AIGC#集成显卡与独立显卡|显卡在深度学习中的选择与LLM GPU推荐

区别 核心区别&#xff1a;显存&#xff0c;也被称作帧缓存。独立显卡拥有独立显存&#xff0c;而集成显卡通常是没有的&#xff0c;需要占用部分主内存来达到缓存的目的 集成显卡&#xff1a; 是集成在主板上的&#xff0c;与主处理器共享系统内存。 一般会在很多轻便薄型的…