【C语言初阶(12)】数组(超详解)

news2024/9/21 20:47:38

文章目录

  • 前言
  • 1. 一维数组
    • 1.1 一维数组的创建
    • 1.2 一维数组的初始化
    • 1.3 一维数组的访问
    • 1.4 一维数组在内存中的存储
  • 2. 二维数组
    • 2.1 二位数组的创建
    • 2.2 二维数组的初始化
    • 2.3 二维数组的访问
  • 3. 数组越界
  • 4. 数组作为函数参数
    • 4.1 冒泡排序介绍
    • 4.2 冒泡排序函数的设计
  • 5. 数组名
  • 6. 数组应用实例

前言

  • 有时候可能需要保存大量类型一致的数据,如一个班级里边所有学生的成绩,手机通讯录中所有联系人的电话,斐波那契数列的前 100 数……对于这些类型一致、数量庞大的数据,如果使用不同变量来存储,就会让人觉得变成是一件很痛苦的事情。
  • 例如,班级中有 50 名学生,那么总共就需要创建 50 个整形变量来存放他们的成绩,如果很不幸,恰好这次又是期末考试,总共考了 5 个科目,那么每一科要创建 50 个变量,总共就需要创建 250 个变量,然后再依次赋值。
#include <stdio.h>
int main()
{
	int a1, a2, a3, a4, a5, ..., a50;
	int b1, b2, b3, b4, b5, ...,b50;
	int c1, c2, c3, c4, c5, ..., c50;
	int d1, d2, d3, d4, d5, ..., d50;
	int e1, e2, e3, e4, e5, ..., e50;
	......
	scanf("%d", &a1);
	......
	scamf("%d", &a50);
	scanf("%d", &b1);
	......
	return 0;
}
  • 应该不会有人会写出这种鬼代码出来,所以,C 语言就引入了数组的概念。

1. 一维数组

1.1 一维数组的创建

  • 数组就是存储一批同类型数据的地方,定义一维数组的语法格式为:类型 数组名[常量表达式];
int a[6];//定义一个整形数组,总共存放 6 个元素,每个元素都是一个整型
char b[24];//定义一个字符型数组,总共存放 24 个元素,每个元素为一个字符
double c[3];//定义一个双精度浮点型数组,总共存放 3 个元素,每个元素为一个双精度浮点型
  • 在定义数组时,需要在数组名后面紧跟一对方括号,其中的数量用来指定数组中元素的个数。

数组的大小

  • 在 C99 标准之前,数组的大小必须是常来那个或者常量表达式;
  • 在 C99 标准之后,数组的大小可以是变量,为了支持变长数组。

1.2 一维数组的初始化

  • 在创建数组的同时对其各个元素进行赋值,称为数组的初始化。
  • 数组初始化得方式有很多,主要分为完全初始化不完全初始化两大类。

完全初始化

  1. 对数组中得每个元素都进行赋值。
int arr[10] = {1,2,3,4,5,6,7,8,9,10};

不完全初始化

  • 只对部分元素进行赋值,其余未被赋值的元素自动初始化为 0。
int arr[10] = {1,2,3};//对前 3 个元素进行赋值,其余 7 个元素系统自动初始化为 0

1.3 一维数组的访问

  • 对于数组的使用之前介绍了一个操作符:[ ] ,下标引用操作符。它其实就是数组访问的操作符。
  • 访问数组的的语法格式为:数组名[下标]
a[0];//访问 a 数组中的第一个元素
b[1];//访问 b 数组中的第二个元素
c[5];//访问 c 数组中的第三个元素
  • 注意:在数组中,下标为 0 的才是第一个元素

计算数组中的元素个数

  • 并不是所有的时候都能知道数组的大小,此时就需要让编译器自己去算数组中有多少个元素。
int sz = sizeof(数组名)/sizeof(数组名[首元素下标]);
//计算数组大小,并将结果返回给 sz
  • 数组最后一个元素的 下标就是 sz - 1。

访问数组中的每个元素

  • 既然已经知道了数组是通过下标来访问的,并且也知道了如何求数组大小,那么自然也能知道如何访问数组当中的每个元素。

在这里插入图片描述

总结

  1. 数组是使用下标来访问的,下标是从0开始。
  2. 数组的大小可以通过计算得到。
int arr[10];
int sz = sizeof(arr)/sizeof(arr[0]);

1.4 一维数组在内存中的存储

先说结论

  • 数组在内存中是连续存放的

在这里插入图片描述

举个栗子

在这里插入图片描述

  • 每个元素之间的地址都差了 4 个字节

2. 二维数组

  • 随着开发的深入,在有些情况下,一维数组难以满足开发的要求,引入二维数组的概念之后,问题就变得简单很多了。
  • 二维数组通常也被称之为矩阵,将二维数组写成行和列的形式表示

2.1 二位数组的创建

  • 定义二维数组的方法和一维数组类似,语法格式为:类型 数组名[常量][常量] ;
int a[5][5];//5*5,5行5列
char b[4][5];//4*5,4行5列
double c[6][3];//6*3,6行3列

在这里插入图片描述

  • 二维数组行列的下标都是从 0 开始的

  • 注意:这里需要强调的是几行几列我们是从概念模型上来看的,也就是说,这样来看待二维数组,我们可以更容易理解。但从物理模型上看,无论是二维数组还是更多维的数组,在内存中仍然是以线性的方式存储的。

  • 比如,定义了二维数组 int b[4][5];那么 b 在内存中的存放就如下图所示。

在这里插入图片描述

  • 从图中可以看出,二维数组事实上就是在一维数组的基础上,每个元素存放一个数组。同样道理,三维数组,四维数组都是以同样的方式实现。
  • 可以把二维数组理解为,一个一维数组,这个一维数组的每个元素都是一个一维数组。

2.2 二维数组的初始化

二维数组的初始化方式和一维数组类似,下面介绍二维数组的六种初始化方式。

  1. 二维数组在内存中是线性存放的,因此可以将所有的数据写在一个大括号内。
int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
//先将第一行的四个元素初始化,再初始化第二行的元素
  1. 为了更加直观地表示元素的分布,可以用大括号将每一行的元素括起来,会更加清晰。
int a[3][4] = {
				{1,2,3,4},
				{5,6,7,8},
				{9,10,11,12}
				};
  1. 二维数组也可以只对部分元素赋值,这样写是只对各行的第一列元素赋值,其余元素全部初始化为 0。
int a[3][4] = {{1},{5},{9}};
  1. 如果希望整个二维数组初始化为 0,那么直接在大括号里写一个 0 即可。
int a[3][4] = {0};
  1. C99 同样增加了一种新特性:指定初始化的元素。这样可以只对数组中得某些指定元素进行初始化赋值,而未被赋值的元素自动被初始化为 0。
int a[3][4] = {[0][0] = 1,[1][1] = 2,[2][2] = 3};
  1. 二维数组的初始化也能 “ 偷懒 ”,让编译器根据元素的数量计算数组的长度,但是只有第一维的元素个数可以不写,其他维度必须写上(可以省略行,不能省略列)。
int a[][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12};

2.3 二维数组的访问

  • 访问二维数组中得元素,同样是使用方括号 [ ]。语法格式为 数组名[下标][下标] ;
a[0][0];//访问 a 数组中第一行第一列的元素
b[1][3];//访问 b 数组中第二行第四列的元素
c[3][3];//访问 c 数组中第四行第四列的元素

举个栗子

  • 将二维数组的所有元素打印到屏幕上。

在这里插入图片描述

3. 数组越界

  • 在使用数组时,要防止数组下标超出边界。也就是说,必须确保下标是有效的值。
int arr[10];
  • 在使用该数组时,要确保程序中使用的数组下标在 0~9 的范围内;
  • 因为编译器不会检查出这种错误(但是,一些编译器会发出警告,然后继续编译程序)。

越界访问数组

  • 使用越界的数组下标会导致程序改变其他变量的值。

在这里插入图片描述

预防数组越界

  • 可以使用 sizeof 来让程序自己判断数组的大小,从而避免自己犯迷糊了导致数组越界。

在这里插入图片描述

4. 数组作为函数参数

  • 往往我们在写代码的时候,会将数组作为参数传个函数;
  • 比如:我们要实现一个冒泡排序函数将一个整形数组排序。

4.1 冒泡排序介绍

基本思想

  • 将两两相邻的元素进行比较,小的放左边,大的放右边(交换数据),按照递增来排序,不满足条件就交换数据,满足则不管。
  • 将某个数排到最终的位置,这一轮叫一趟冒泡排序

在这里插入图片描述

  • 每一趟冒泡排序可以让 1 个元素走到最终位置.
    • 对于 6 个元素要进行 5 趟冒泡排序。
    • n 个元素要进行 n - 1 趟冒泡排序

在这里插入图片描述

冒泡排序过程(升序)

初始:21,25,49,25*,16,08 ;n = 6。

  1. 第 1 趟
    • 第 1 趟结束后:21,25,25*,16,08,49
    • 第 1 趟结束之后,49 已经有序了,那么下一趟就不用管它了。

在这里插入图片描述

  1. 第 2 趟
    • 第 2 趟结束后:21,25,16,08,25*,49
    • 继续下一趟,每一趟增加一个有序元素。

在这里插入图片描述

  1. 第 3 趟结果:21,16,08,25,25*,49
  2. 第 4 趟结果:16,08,21,25,25*,49
  3. 第 5 趟结果:08,16,21,25,25*,49

冒泡排序算法总结

  • n 个元素,总共需要 n - 1 趟冒泡排序
  • 第 i 趟需要比较 n - i - 1 次

4.2 冒泡排序函数的设计

1. 冒泡排序函数的错误设计

  • 错误的使用了数组名传参,在函数体内部利用数组名求数组元素个数。
//冒泡排序函数的错误设计
#include <stdio.h>
void bubble_sort(int arr[])//arr看似是数组,实则为指针
{
	int n = sizeof(arr) / sizeof(arr[0]);
	//数组名传参传过来的实际是个指针,32 位系统下指针为 4 个字节;
	//所以 n 的结果为 4 / 4 = 1,元素个数都算不对,下面的代码更不用说了
	
	//算出 n = 1 的话,n-1=0,循环压根就没进去,自然不会排序了
	for (int i = 0; i < n - 1; i++)
	{
		for (int j = 0; j < n - 1 - i; j++)
		{
			int tmp = 0;
			if (arr[j] > arr[j + 1])//交换数据
			{
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
int main()
{
	int i = 0;
	int arr[] = { 10,9,8,7,6,5,4,3,2,1 };

	bubble_sort(arr);//传过去的是数组首元素的地址
	for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

在这里插入图片描述

2. 冒泡排序函数的正确设计

  • 在函数体外部求出数组元素个数,然后将元素个数传参给函数。
//冒泡排序函数的正确设计
#include <stdio.h>
void bubble_sort(int arr[], int n)
{
	for (int i = 0; i < n-1; i++)//n 个元素,总共需要进行 n-1 趟冒泡排序
	{
		for (int j = 0; j < n - 1 - i; j++)//每一趟冒泡排序要比较 n-i-1 次
		{
			int tmp = 0;
			if (arr[j] > arr[j + 1])//交换数据
			{
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
int main()
{
	int i = 0;
	int arr[] = { 10,9,8,7,6,5,4,3,2,1 };
	int n = sizeof(arr) / sizeof(arr[0]);
	//使用数组名传参的话,如果要用到数组元素个数,必须在主函数中求出结果再传给函数

	bubble_sort(arr,n);//数组名传参传过去的是数组首元素的地址
	for (i = 0; i <n; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

在这里插入图片描述

5. 数组名

绝大多数情况下,数组名是数组首元素的地址,但有两种情况例外。

  1. sizeof(数组名):这里的数组名表示整个数组,计算的是整个数组的大小。
  2. &数组名:取出的是整个数组的地址。
#include <stdio.h>
int main()
{
	int arr[10] = 0;

	printf("%p\n", arr);//arr 就是首元素的地址
	printf("%p\n", arr + 1);//地址+1,跳过一个元素
	printf("---------------------\n");
	printf("%p\n", &arr[0]);// 取出首元素的地址
	printf("%p\n", &arr[0] + 1);//跳过一个元素
	printf("---------------------\n");
	printf("%p\n", &arr);//整个数组的地址的表现形式也是首元素地址
	printf("%p\n", &arr + 1);//但是数组地址+1会跳过整个数组

	return 0;
}

在这里插入图片描述

二维数组的数组名的理解

  • 二维数组的数组也表示首元素的地址,但二维数组的首元素和我们想的有点不太一样。
  • 二维数组的数组名表示的是第一行的地址
  • 对数组名+1会直接跳过一行。

在这里插入图片描述

二维数组行列数的计算

  1. 计算行数:总数组的大小 / 一行的大小
sizeof(数组名) / sizeof(数组名[0]);
//二维数组第一行的数组名是 数组名[0]
  1. 计算列数:一行的大小 / 一个元素的大小
sizeof(数组名[0]) / sizeof(数组名[0][0]);

在这里插入图片描述

6. 数组应用实例

  1. 三子棋游戏
  2. 扫雷游戏

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

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

相关文章

短视频矩阵管理系统私信群聊功能源码开发分享

短视频获客工具的兴起&#xff0c;也有越来越多的企业及商家在发现了更多商机。除了在做短视频推广获客的同时&#xff0c;也有不少意向客户潜藏在评论区需要我们深度挖掘&#xff0c;那么对于一些流量比较高的账号&#xff0c;想在成千上万的评论区里挖掘意向客户&#xff0c;…

C#一个开源跨平台的 HTTP 客户端库——RestSharp

一、RestSharp简介 GitHub - restsharp/RestSharp: Simple REST and HTTP API Client for .NETSimple REST and HTTP API Client for .NET. Contribute to restsharp/RestSharp development by creating an account on GitHub.https://github.com/restsharp/RestSharp …

SpringBoot实战(十九)集成Ribbon

目录 一、负载均衡的分类1.服务端负载均衡2.客户端负载均衡 二、定义和依赖1.Ribbon2.Spring Cloud Ribbon3.Spring Cloud Loadbalancer 三、搭建测试项目1.Maven依赖2.yaml配置3.配置类4.启动类5.接口类 四、测试五、补充&#xff1a;认识 Ribbon 的组件 一、负载均衡的分类 …

knife4j实现微服务swagger文档聚合

使用knife4j实现分布式swagger文档聚合 在项目开发过程中,接口文档的使用是在所难免的,但是在微服务场景下,多个服务之间的swagger是分散的,虽然swagger提供了微服务的聚合方式,配置过于繁琐,加之swagger本身的功能比较少,而且ui布局也比较蛋痛,此处推荐一款新框架用于增强swa…

RestTemplate中exchange发起请求

RestTemplate中exchange简单使用 简介什么是RestTemplate 常用方法实战 简介 在项目中&#xff0c;我们可能需要发起HTTP请求&#xff0c;请求目标URL来获取响应数据做一些处理。就需要用到HTTP请求工具&#xff0c;常用的Java类工具有&#xff1a;HttpUrlConnection、Apache …

[TIFS 2023] 用增强压缩感知做安全模型对比联邦学习

Secure Model-Contrastive Federated Learning With Improved Compressive Sensing | IEEE Journals & Magazine | IEEE Xplore摘要&#xff1a; 联邦学习&#xff08;FL&#xff09;已广泛应用于金融风险控制、电子政务、智慧医疗等各个领域。为了保护数据隐私&#xff0…

Leetcode每日一题:167. 两数之和 II - 输入有序数组(2023.7.8 C++)

目录 167. 两数之和 II - 输入有序数组 题目描述&#xff1a; 实现代码与解析&#xff1a; 暴力&#xff08;超时&#xff09; 双指针 原理思路&#xff1a; 二分 原理思路&#xff1a; 167. 两数之和 II - 输入有序数组 题目描述&#xff1a; 给你一个下标从 1 开始的…

MySQL性能瓶颈定位慢查询

目录 1 性能优化的思路2 引言3 MySQL慢查询日志3.1 慢查询参数3.2 开启慢查询日志&#xff08;临时&#xff09;3.3 开启慢查询日志&#xff08;永久&#xff09;3.4 慢查询测试 4 MySQL性能分析 EXPLAIN4.1 概述4.2 EXPLAIN字段介绍4.2.1 id字段4.2.2 select_type 与 table字段…

Leetcode-每日一题【21.合并两个有序链表】

题目 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4]输出&#xff1a;[1,1,2,3,4,4] 示例 2&#xff1a; 输入&#xff1a;l1 [], l2 []输出&#xff1a;…

1.Git使用技巧-常用命令1

Git使用技巧-常用命令 文章目录 Git使用技巧-常用命令一、git 创建仓库demo 二、本地仓库常用命令提交详解git commitgit commit --amend 三、 推送到远程分支git push 总结参考 一、git 创建仓库 创建远端仓库&#xff1a; git init – bare // 创建远端裸仓库&#xff1b; 远…

【华为机试】HJ16 购物单详解+完整源代码示例

从毕业到入职&#xff0c;忙于各种事情&#xff0c;所以博客一直也没有空更新。从入职到现在差不多整三个月了&#xff0c;刚刚在比亚迪这边转正。目前干的工作涉及到开发的工作不是很多&#xff0c;但是又怕之前的技能荒废了。所以最近有个想法&#xff0c;再把C算法和数据结构…

Android Zygote 启动流程

和你一起终身学习&#xff0c;这里是程序员Android 经典好文推荐&#xff0c;通过阅读本文&#xff0c;您将收获以下知识点: Android系统包含netd、servicemanager、surfaceflinger、zygote、media、installd、bootanimation 等基本服务&#xff0c;具体作用请看下图。 Android…

English Learning - L3 作业打卡 Lesson8 Day60 2023.7.5 周三

English Learning - L3 作业打卡 Lesson8 Day60 2023.7.5 周三 引言Part 1 总结&#x1f349;句1: 11 years ago, when I lost my legs, I had no idea what to expect.成分划分连读爆破语调 &#x1f349;句2: But if you ask me today, if I would ever want to change my si…

java+Mysql 图书管理系统(idea)

目录 前言 部分界面截图 登录界面 注册界面 图书管理界面 关于我们界面 部分代码 登录界面 数据库工具类 前言 jdk 版本&#xff1a;openjdk version "11.0.12" MySql版本&#xff1a;5.7.40 加&#xff08;vx&#xff1a;lixuanzi0521&#xff09;帮调试 …

递推--Fibonacci数列 II

描述 众所周知&#xff0c;Fibonacci数列是一个著名数列。它的定义是&#xff1a; 本题要求采用第二种方法&#xff1a;递推。 输入描述 每行一个整数 i &#xff0c;表示 Fibonacci 数列的第i项。 i ≤ 100000 对比前一题&#xff0c;本题的数据规模是 十万 &#xff01; …

css基础知识十九:让Chrome支持小于12px 的文字方式有哪些?区别?

一、背景 Chrome 中文版浏览器会默认设定页面的最小字号是12px&#xff0c;英文版没有限制 原由 Chrome 团队认为汉字小于12px就会增加识别难度 中文版浏览器 与网页语言无关&#xff0c;取决于用户在Chrome的设置里&#xff08;chrome://settings/languages&#xff09;把…

应用层:电子邮件

1.应用层&#xff1a;电子邮件 笔记来源&#xff1a; 湖科大教书匠&#xff1a;应用层概述 湖科大教书匠&#xff1a;电子邮件 声明&#xff1a;该学习笔记来自湖科大教书匠&#xff0c;笔记仅做学习参考 电子邮件系统采用客户/服务器方式&#xff08;C/S&#xff09; 电子邮件…

计算机视觉 3D点云极简概述

一、概述 点云是表示 3D 坐标系中的数字 3D 物理对象或空间的点数据库。它由数百万或者更多个单独的测量点组成,具有 x、y 和 z 坐标。3D点云是物体的高精度数字记录。点云用于生成用于 3D 建模的 3D 网格和其他模型。包括医学成像、3D 打印、制造、建筑、3D 游戏和虚拟现实 (…

NSS [NISACTF 2022]babyupload

NSS [NISACTF 2022]babyupload 源码给了提示&#xff0c;/source路径 访问后得到一个文件&#xff0c;是源码 from flask import Flask, request, redirect, g, send_from_directory import sqlite3 import os import uuidapp Flask(__name__)SCHEMA """CRE…

基于matlab使用PointNet深度学习进行点云分类(附源码)

一、前言 此示例演示如何训练 PointNet 网络以进行点云分类。 点云数据由各种传感器获取&#xff0c;例如激光雷达、雷达和深度摄像头。这些传感器捕获场景中物体的3D位置信息&#xff0c;这对于自动驾驶和增强现实中的许多应用非常有用。例如&#xff0c;区分车辆和行人对于…