C语言中的数组(详解)

news2024/11/24 12:05:38

C语言中的数组(详解)

    • 一、一维数组
    • 1.一维数组的创建
    • 2.数组的初始化
    • 3.一维数组的使用
    • 4.一维数组在内存中的存储
    • 二、二维数组
    • 1.二维数组的创建
    • 2.二维数组的初始化
    • 3.二维数组的使用
    • 4.二维数组在内存中的存储
    • 三、数组越界
    • 四、数组作为函数参数
    • 1.冒泡排序
    • 2.数组名是什么?
    • 3.代码修正

  • 🎈个人主页:库库的里昂
  • 🎐CSDN新晋作者
  • 🎉欢迎 👍点赞✍评论⭐收藏
  • ✨系列专栏C语言初阶、代码小游戏
  • 🤝希望作者的文章能对你有所帮助,有不足的地方请在评论区留言指正,大家一起学习交流!🤗

【前言】

数组可以说是目前为止讲到的第一个真正意义上存储数据的结构。

虽然前面学习的变量也能存储数据,但变量所能存储的数据很有限。不仅如此,数组和指针(后续会讲)是相辅相成的,学习数组可以为学习指针打下基础。

注!!!
由于本文讲解的数组需要用到自定义函数的概念,没有学习的小伙伴可以查看函数的讲解:C语言中的函数

一、一维数组

1.一维数组的创建

一维数组的定义方式如下:

类型说明符 数组名[常量表达式];
例:int arr[5];

它表示定义了一个整型数组,数组名为 arr,定义的数组称为数组 arr。
注:数组创建,在C99标准之前, [] 中要给一个常量才可以,不能使用变量。在C99标准支持了变长数组的概念。(作者用的编译器是VS2019不支持C99标准)

2.数组的初始化

所谓数组初始化是指在创建数组的同时给数组的内容一些合理初始值。
下面举出数组初始化的情况:

//整形数组
int arr1[5] = { 1, 2, 3, 4, 5 };//完全初始化
int arr2[5] = { 1, 2 };//不完全初始化
int arr3[5] = { 1, 2, 3, 4, 5 };
int arr4[] = { 1, 2, 3, 4, 5 };
//字符型数组
char arr5[] = {'a','b','c'};
char arr6[] = "abcdef"

我们可以打印出来看一下

在这里插入图片描述

3.一维数组的使用

对于数组的使用我们之前介绍了一个操作符: [] ,下标引用操作符,即arr[0]为数组首元素,arr[4]为最后一个元素。
我们来做一道题目:输入十个数字,并将它们打印出来。

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	//计算数组的元素个数
	int sz = sizeof(arr) / sizeof(arr[0]);
	//对数组内容赋值,数组是使用下标来访问的,下标从0开始。所以:
	int i = 0;//做下标
	for (i = 0; i < 10; i++)
	{
		arr[i] = i;
	}
	for (i = 0; i < 10; ++i)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

代码中 sizeof(arr)表示计算整个数组arr的大小,而sizeof(arr[0])表示计算数组中首元素的大小(随便计算一个元素就行,因为每个元素的大小都是相等的,这里是选取了首元素),所以sz就是数组元素的个数。

4.一维数组在内存中的存储

接下来我们探讨数组在内存中的存储
代码

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);

	for (i = 0; i < sz; ++i)
	{
		printf("&arr[%d] = %p\n", i, &arr[i]);
	}
	return 0;
}

输出结果如下:

在这里插入图片描述
仔细观察输出的结果,我们知道,随着数组下标的增长,元素的地址,也在有规律的递增。
由此可以得出结论:数组在内存中是连续存放的。
在这里插入图片描述

二、二维数组

1.二维数组的创建

//数组创建
int arr[3][4];//创建一个3行4列的整形二维数组
char arr[3][5];//创建一个3行5列的整形二维数组
double arr[2][4];//创建一个2行4列的浮点型形二维数组

2.二维数组的初始化

//数组初始化
int arr[3][4] = {1,2,3,4};
int arr[3][4] = {{1,2},{4,5}};
int arr[][4] = {{2,3},{4,5}};//二维数组如果有初始化,行可以省略,
列不能省略

我们打印出来看一下:
在这里插入图片描述

3.二维数组的使用

二维数组的使用和一维数组一样也是通过下标的方式。
看代码:

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

运行结果:
在这里插入图片描述

4.二维数组在内存中的存储

和一维数组一样,这里我们试着打印二维数组的每个元素。

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

运行结果:
在这里插入图片描述

通过结果我们可以分析到,其实二维数组在内存中也是连续存储的。
在这里插入图片描述

三、数组越界

  • 我们知道数组的下标是有范围限制的。
  • 数组的下标规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。
  • 所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。
    - C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的,
  • 所以我们在写代码时,最好自己做越界的检查。

例:

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	for (i = 0; i <= 10; i++)
	{
		printf("%d\n", arr[i]);//当i等于10的时候,越界访问了
	}
	return 0;
}

注意:二维数组的行和列也存在越界。

四、数组作为函数参数

往往我们在写代码的时候,会将数组作为参数传个函数,比如:我要实现一个冒泡排序这里要讲算法思想)函数将一个整形数组排序。

补充:什么是冒泡排序?

它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。 走访元素的工作是重复地进行,直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
比如将10 9 8 7 6 5 4 3 2 1 这十个元素前后依此交换最后变成9 8 7 6 5 4 3 2 1 10为一次冒泡排序,重复此类操作,最后变成1 2 3 4 5 6 7 8 9 10就算完成了冒泡排序。

1.冒泡排序

我们来实现一个冒泡排序:输入十个数3 1 7 5 8 9 0 2 4 6,要求顺序打印。

函数定义

#include <stdio.h>
//自定义一个冒泡排序函数bubble_sort
void bubble_sort(int arr[])
{
	//设置整形变量sz即为数组元素的个数
    int sz = sizeof(arr) / sizeof(arr[0]);
    int i = 0;
    for (i = 0; i < sz - 1; i++)//所有元素顺序排完后要完成的次数
    {
        int j = 0;
        //每相邻两个元素比较的总次数(逐次递减,所以要-i)
        for (j = 0; j < sz - i - 1; j++)
        {
            if (arr[j] > arr[j + 1])
            {
            	//相邻两元素交换
                int tmp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = tmp;
            }
        }
    }
}

代码设计

int main()
{
    int arr[] = { 3,1,7,5,8,9,0,2,4,6 };
    bubble_sort(arr);//将实参arr传到形参arr[]进行函数的执行
    for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
    {
        printf("%d ", arr[i]);//依次打印顺序后数组的每个元素
    }
    return 0;
}

运行结果
在这里插入图片描述

惊不惊喜,意不意外。我们再检查检查代码!

有人就要说了,诶,这也没毛病呀!啥情况啊!

出问题,那我们找一下问题,调试之后可以看到 bubble_sort 函数内部的 sz ,是1。

难道数组作为函数参数的时候,不是把整个数组的传递过去?

2.数组名是什么?

数组名就是地址,通常来说:数组名是数组首元素的地址

代码示例

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	return 0;
}

运行结果

在这里插入图片描述
可以看出数组名就是数组首元素的地址

但是,如果是这样的话,那么sizeof(arr)的大小应该等于4或者8呀,我们看下是不是呢
在这里插入图片描述
很明显不是,那是为什么呢?

这里有两个例外

  1. sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。
  2. &数组名,取出的是数组的地址。&数组名,数组名表示整个数组

除此1,2两种情况之外,所有的数组名都表示数组首元素的地址。

3.代码修正

当数组传参的时候,实际上只是把数组的首元素的地址传递过去了。
所以即使在函数参数部分写成数组的形式: int arr[] 表示的依然是一个指针: int *arr 。
那么,函数内部的 sizeof(arr) 结果是4。

所以正确的代码应该是

#include<stdio.h>
void sort(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
int main()
{
	int arr[] = { 3,1,7,5,8,9,0,2,4,6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	sort(arr, sz);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

运行结果

当当当当,终于成功啦!!!🎉🎉🎉
在这里插入图片描述

  • 好了,关于C语言中的数组就讲到这里啦!
  • 在学完函数和数组之后我们就可以设计三子棋和扫雷程序代码了,后续我将会在代码小游戏专栏里面发布游戏代码设计,大家想看的可以订阅一下,敬请期待吧!
  • 拜拜啦!

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

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

相关文章

MySQL基础扎实——MySQL中有那些不同的表格

表格类型 在MySQL中&#xff0c;常见的表格类型有以下几种&#xff1a; MyISAM&#xff1a;是MySQL默认的表格类型&#xff0c;具有较高的性能和较小的存储空间占用。但是&#xff0c;MyISAM不支持事务、崩溃恢复和数据行级锁定。 InnoDB&#xff1a;是MySQL提供的一个更强大…

理解基本的Android编程 (1/2)

1、Android概述 Android 是一个开源的&#xff0c;基于 Linux 的移动设备操作系统。 Android开发优势 开放源代码 众多开发者及强大的社区 不断增长的市场 国际化的App集成 低廉的开发成本 更高的成功几率 丰富的开发环境 Android应用程序 Android 应用程序一般使用…

EtherNet/IP转Modbus网关以连接AB PLC

本案例为西门子S7-1200 PLC通过捷米特Modbus转EtherNet/IP网关捷米特JM-EIP-RTU连接AB PLC的配置案例。 网关分别从ETHERNET/IP一侧和MODBUS一侧读写数据&#xff0c;存入各自的缓冲区&#xff0c;网关内部将缓冲区的数据进行交换&#xff0c;从而实现两边数据的传输。 网关做为…

VMware NSX Advanced Load Balancer (NSX ALB) 22.1.4 - 负载均衡平台

VMware NSX Advanced Load Balancer (NSX ALB) 22.1.4 - 负载均衡平台 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-nsx-alb-22/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 负载均衡平台 NSX Advanced Load…

SpringBoot-6

Spring Boot 中的 MVC 支持 Spring Boot 的 MVC 支持主要来最常用的几个注解&#xff0c;包括RestController 用于声明控制器、RequestMapping用于实现方法映射地址、PathVariable 用于接受路径中的参数、RequestParam 用于接受 request 请求中的参数以及RequestBody 用于接受…

echarts 饼图中间添加文字

需求&#xff1a;饼图中间展示总量数据 方法一、设置series对应饼图的label属性 series: [{type: "pie",radius: [55%, 62%],center: ["67%", "50%"],itemStyle: {borderRadius: 10,borderColor: #fff,borderWidth: 2},// 主要代码在这里label: …

docker 的compose安装

1. Docker Compose 环境安装 Docker Compose 是 Docker 的独立产品&#xff0c;因此需要安装 Docker 之后在单独安装 Docker Compose 下载 curl -L https://github.com/docker/compose/releases/download/1.21.1/docker-compose-uname -s-uname -m -o /usr/local/bin/docker…

HBase有写入数据,页面端显示无数据量

写了一个测试类&#xff0c;插入几条数据&#xff0c;测试HBase的数据量。很简单的功能&#xff0c;这就出现问题了。。网页端可以看到&#xff0c;能够看到读写请求&#xff0c;但是不管是内存、还是磁盘&#xff0c;都没有数据。 于是就想到去HDFS查看&#xff0c;也是有数据…

VU3-02

1.一些小点 1.1 npm i -D less (安装less) -D 安装依赖到开发环境中 只在开发中生效 正式打包的时候没有它&#xff0c;只在开发时有效 1.2 父子组件传参 &#xff08;1&#xff09;子组件中定义自己的参数和事件 父传子&#xff1a;const props defineProps(["item&quo…

利用读时建模等数据分析能力,实现网络安全态势感知的落地

摘要&#xff1a;本文提出一种基于鸿鹄数据平台的网络安全态势感知系统&#xff0c;系统借助鸿鹄数据平台读时建模、时序处理、数据搜索等高效灵活的超大数据存储和分析处理能力&#xff0c;支持海量大数据存储、分类、统计到数据分析、关联、预测、判断的网络安全态势感知能力…

MySQL索引优化分析和锁详解

MySQL 1. 索引 1.1 索引的概述 索引&#xff08;index&#xff09;是帮助MySQL高效获取数据的数据结构&#xff08;有序&#xff09; 1.2 索引的优缺点 优点 提高数据检索效率,降低磁盘IO的成本通过索引列对数据进行排序, 降低数据排序的成本,降低CPU的消耗 缺点 索引是需要…

【使用回溯法求解八皇后问题(92个解)】

在每一个横列、竖列、斜列都只有一个皇后 解决的冲突 包括行、列和两条对角线规定每一行放置一个皇后&#xff0c;不会造成行上的冲突 当第col列被某个皇后占领之后&#xff0c;则同一列上的所有空格都不能再放置皇后&#xff0c;并且要把flag[col]置为被占领状态 对角线有两个…

【Docker】Docker的通信安全

Docker的通信安全 前言一、Docker 容器与虚拟机的区别1. 隔离与共享2. 性能与损耗 二、Docker 存在的安全问题1. Docker 自身漏洞2. Docker 源码问题 三、Docker 架构缺陷与安全机制1. 容器之间的局域网攻击2. DDoS 攻击耗尽资源3. 有漏洞的系统调用4. 共享 root 用户权限 四、…

OBS 迁移--华为云

一、创建迁移i任务 1. 登录管理控制台。 2. 单击管理控制台左上角的 在下拉框中选择区域。 3. 单击“ 服务列表 ”&#xff0c;选择“ 迁移 > 对象存储迁移服务 OMS ”&#xff0c;进入“ 对象存储迁移服务 ”页面。 4. 单击页面右上角“ 创建迁移任务 ”。 5. 仔细阅读…

卡尔曼滤波算法原理及示例

例程:物体做匀速运动每秒运动1m,观测器观测方差为1m

安全学习DAY06_抓包技术-HTTPHTTPS

抓包技术-HTTP&HTTPS HTTP&HTTPS抓包针对Web&APP&小程序&PC应用等 本节目的&#xff1a; 掌握几种抓包工具证书安装操作掌握几种HTTP&HTTPS抓包工具的使用学会Web&#xff0c;APP&#xff0c;小程序&#xff0c;PC应用等抓包了解本节课抓包是针对哪些…

大数据课程C5——ZooKeeper的应用组件

文章作者邮箱&#xff1a;yugongshiyesina.cn 地址&#xff1a;广东惠州 ▲ 本章节目的 ⚪ 掌握Zookeeper的Canal消费组件&#xff1b; ⚪ 掌握Zookeeper的Dubbo分布式服务框架&#xff1b; ⚪ 掌握Zookeeper的Metamorphosis消息中间件&#xff1b; ⚪ 掌握Zo…

Docker的安装与部署

Docker 基本概念介绍 通俗理解&#xff1a;镜像是类&#xff0c;容器是对象实例 仓库 应用商店、镜像 下载的应用安装程序、容器 应用程序 镜像(Image) 这里面保存了应用和需要的依赖环境 为什么需要多个镜像&#xff1f;当开发、构建和运行容器化应用程序时&#xff0c;我们…

【Postman】Newman安装与环境配置完整版(内含安装过程中遇到的问题与解决方案)

文章目录 概要Newman安装三步走一、nodejs安装与环境配置1、安装2、环境配置 二、安装newman1、步骤2、问题与解决方案 三、安装newman-reporter-html 概要 Newman&#xff1a;一款基于nodejs开发的可以运行Postman脚本的工具&#xff0c;并且可以生成测试报告。本文介绍了New…

【Linux】信号补充与总结

可重入函数 【分析】 mian函数正在调用insert函数向链表中插入节点。insert函数分为两步&#xff0c;刚刚执行完第一步时此时硬件发生中断&#xff0c;使进程切换到内核。中断处理完毕切换到用户态之前发现有信号未决&#xff0c;于是进入了信号的处理函数&#xff0c;信号的处…