初阶C语言-数组

news2025/1/17 5:49:22

“少年没有偏旁,自己便是华章!” 今天我们继续一起来学习一下数组的相关知识点。

数组

  • 1.一维数组的创建和初始化
    • 1.1 数组的创建
    • 1.2 数组的初始化
    • 1.3 一维数组的使用
    • 1.4 一维数组在内存中的存储
  • 2. 二维数组的创建和初始化
    • 2.1二维数组的创建
    • 2.2二维数组的初始化
    • 2.3二维数组的使用
    • 2.4二维数组在内存中的存储
  • 3.数组越界
  • 4.数组作为函数参数
    • 4.2数组名是什么?
    • 4.3冒泡排序函数的正确设计

1.一维数组的创建和初始化

什么是数组呢? 数组是一组相同类型元素的集合。

1.1 数组的创建

//数组的创建
//type_t arr_name [const_n]
//type_t 是数组的元素类型
//arr_name是数组名
//const_n是一个常量表达式,用来指定数组的大小
//数组创建的示例:
//C99之前数组只能是常量指定大小,C99之后引用了变长数组的概念,数组的大小可以使用变量指定的
//但是VS2019不支持C99的变长数组的
#include <stdio.h>
int main()
{
	int arr1[10];
	int arr2[3 + 2];
	char arr3[8];
	return 0;
}

1.2 数组的初始化

数组的初始化是指:在创建数组的同时给数组的内容一些合理初始值(初始化)。

#include <stdio.h>
int main()
{
	int arr1[10] = { 1,2,3 };//不完全初始化,剩余元素初始化为0
	int arr2[4] = { 1,2,3,4 };//完全初始化
	char arr3[] = { 'a','b','c' };//数组在创建的时候如果想不指定数组的确定的大小就得初始化。数组的元素个数根据初始化的内容来确定。
	char arr4[] = { 'a',98,'c' };
	char arr5[] = { "abcdefgh" };
	return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里,我们要区分以下用字符给数组初始化和用字符串给数组初始化,通过监视,我们可以发现用字符串给数组初始化是有'\0'的。
在这里插入图片描述
在这里插入图片描述

1.3 一维数组的使用

对于数组的使用,我们之前介绍了一个操作符:[],下标引用操作符。它其实就是数组访问的操作符。

//一维数组的使用
#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	//            0,1,2,3,4,5,6,7,8,9
	//注意:数组的下标是从0开始的
	printf("%d\n", arr[6]);//相应的下标就会对应相应的数组元素
	return 0;
}

在这里插入图片描述
那如果我们想打印出数组的全部元素应该怎么做呢?难道要使用10个printf语句吗?这里,显然是不可能的,这个时候,我们就要想到使用for循环来解决问题。

#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	//            0,1,2,3,4,5,6,7,8,9
	int sz=sizeof(arr)/sizeof(arr[0])-1;
	int i = 0;//做下标
	for (i = 0; i <= sz; i++)//数组的元素是通过下标来访问的
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

在这里插入图片描述

刚刚我们只是用下标来打印数组的元素,如果我们想把数组的元素的值改掉,应该怎么做呢?
比如我们现在要把数组元素改为10 9 8 7 6 5 4 3 2 1,应该怎么改代码呢?

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

在这里插入图片描述

1.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;
}

在这里插入图片描述
注:通过仔细观察,我们知道,随着数组下标的增长,元素的地址,也在有规律的递增,因此,数组在内存中是连续存放的。
因此,我们只要知道了数组的首地址,通过遍历,就能访问数组的全部元素了。
在这里插入图片描述

2. 二维数组的创建和初始化

2.1二维数组的创建

char arr1[3][5]//第一个表示行第二个表示列
int arr2[3][5]int arr3[2][3]

2.2二维数组的初始化

//二维数组的初始化
#include <stdio.h>
int main()
{
	char arr1[3][5] = { 0 };
	int arr2[3][5] = { {1,2,3,4,5},{6,7,8,9, 8},{1,2,3,4,5}};
	int arr3[2][3] = { {1,2},{3,4} };
	int arr4[][4] = { {1,2},{1,2,3,4} };//二维数组如果有初始化,行可以省略,列不能省略
	return 0;
}

在这里插入图片描述

2.3二维数组的使用

二维数组的使用也是通过下标的访问。

int arr2[3][5] = { {1,2,3,4,5},{6,7,8,9, 8},{1,2,3,4,5}};

对于这样的一个二维数组,我们假想中它的排列是这样的:
在这里插入图片描述
那么我们可以看到,通过对应的行号和列号的下标就能访问到对应的元素了。那么,如果我们想打印出二维数组的全部元素,应该怎么做呢?

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

在这里插入图片描述

2.4二维数组在内存中的存储

像一维数组一样,我们可以尝试打印二维数组每个元素的地址。

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

在这里插入图片描述
注:通过仔细观察,我们知道,随着数组下标的增长,元素的地址,也在有规律的递增,因此,二维数组在内存中是连续存放的。

因此,二维数组在内存中的存储应该是这样的:也可以将二维数组理解为一维数组的数组。如下图所示的a[0]a[1]可以理解为二维数组拆分成的两个一维数组名。
在这里插入图片描述

3.数组越界

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

#include <stdio.h>
int main()
{
	int arr[2][3] = { {1},{2,3} };
	int i = 0;
	for (i = 0; i < 2; i++)
	{
		int j = 0;
		for (j = 0; j <= 3; j++)//我们发现这里列存在越界行为,但是编译器并没有报错
		{
			printf("arr[%d][%d] = %d\n", i, j, arr[i][j]);
		}
	}
	return 0;
}

在这里插入图片描述
正确的写法是什么样的呢?

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

在这里插入图片描述
注:二维数组的行和列也可能存在越界。

4.数组作为函数参数

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

冒泡排序的思想:两两相邻的元素进行比较。
假设我们这里现在有10 9 8 7 6 5 4 3 2 1这十个数,如果我们希望通过冒泡排序实现升序应该怎么做呢?
在这里插入图片描述
不难发现,想要排十个数,我们最多要冒泡九次,那么我们一起来用代码演示一下这个过程吧!

//冒泡排序
#include <stdio.h>
int main()
{
	int arr1[] = { 10,9,8,7,6,5,4,3,2,1 };
	int i = 0;
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	for (i = 0; i < sz - 1; i++)
	{
		int j = 0;
		for (j = 0; j <sz-i-1 ; j++)
		{
			if(arr1[j]>arr1[j+1])
			{
				int t = arr1[j];
				arr1[j] = arr1[j + 1];
				arr1[j + 1] = t;
			}
		}
	}
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

在这里插入图片描述
前面我们也学习了函数,这里我们能不能设计一个冒泡排序的函数呢?

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

可能我们一开始想到的代码是这样的,那么这样写对不对呢?
在这里插入图片描述
我们发现,这并没有帮我们实现升序的功能!那么,到底是哪里出现问题了呢?
在这里插入图片描述
通过调试,我们发现在冒泡函数里求数组元素个数sz方面出现了问题,这到底是为什么呢?这就是涉及到用数组作为函数的参数,到底传的是什么呢?传的是整个数组吗?这里,我们就需要来认识一下数组名!

4.2数组名是什么?

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

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

在这里插入图片描述

注:通常的说,数组名就是数组的首地址。但是,存在两个例外:
1.sizeof(数组名),这里的数组名就表示整个数组,计算的是整个数组的大小,单位是字节。
2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
除此之外,所有遇到的数组名都是数组的首地址。</font

同样,对上面的知识有所了解之后,我们就可以发现刚刚冒泡排序出问题的地方:

//数组名作为函数参数(错误)
#include <stdio.h>
//应该使用指针来接收
void bubble_sort(int arr[])//本质是指针
{
	int i = 0;
	//数组名作为函数的参数传过去的是数组的首地址,没办法求数组元素个数。
	int sz = sizeof(arr) / sizeof(arr[0]);//4/4=1
	for (i = 0; i < sz - 1; i++)
	{
		int j = 0;
		for (j = 0; j < sz - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int t = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = t;
			}
		}
	}
}
int main()
{
	int arr1[] = { 10,9,8,7,6,5,4,3,2,1 };
	bubble_sort(arr1);//这里的arr1不是两种特殊的情况,就是数组首元素的地址
	int i = 0;
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

4.3冒泡排序函数的正确设计

当数组传参的时候,实际上只是把数组的首元素的地址传过去了。所以即使在函数的参数部分写成数组的形式:int arr[]表示的依然是一个指针:int *arr.所以,这里我们考虑直接在主函数内部求出sz,在冒泡排序的函数内直接用就行。

//数组名作为函数参数(正确)
#include <stdio.h>
//void bubble_sort(int *arr,int sz)
void bubble_sort(int arr[],int sz)
{
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		int j = 0;
		for (j = 0; j < sz - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int t = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = t;
			}
		}
	}
}

int main()
{
	int arr1[] = { 10,9,8,7,6,5,4,3,2,1 };
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	bubble_sort(arr1,sz);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

在这里插入图片描述
我们发现,这样就解决了刚刚的问题啦!

好啦,关于数组的知识点到这里就结束啦,后期会继续更新C语言相关知识点,欢迎大家持续点赞、关注和评论!大家多多支持团子呀!

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

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

相关文章

安达发|APS系统帮助家具行业建立精益生产计划

随着家具企业的业务量不断扩大&#xff0c;仅依靠传统的ERP系统和人工生产调度已经不能满足精益生产改进的要求。建立高效的精益生产计划模型及其对应的组织结构&#xff0c;提高整个供应链计划的效率&#xff0c;优化计划结果&#xff0c;从而提高供应链的运作效率&#xff0c…

VSCode C/C++ 分目录编译配置

分目录编译配置记录 launch.json文件 注释处为修改内容 {// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息&#xff0c;请访问: https://go.microsoft.com/fwlink/?linkid830387"version": "0.2.0","configur…

ChatGPT已打破图灵测试,新的测试方法在路上

生信麻瓜的 ChatGPT 4.0 初体验 偷个懒&#xff0c;用ChatGPT 帮我写段生物信息代码 代码看不懂&#xff1f;ChatGPT 帮你解释&#xff0c;详细到爆&#xff01; 如果 ChatGPT 给出的的代码不太完善&#xff0c;如何请他一步步改好&#xff1f; 全球最佳的人工智能系统可以通过…

MATLAB算法实战应用案例精讲-【自动驾驶】路径规划

目录 前言 几个高频面试题目 无人车运动规划&#xff0c;路径规划&#xff0c;轨迹规划的区别和联系&#xff1f; 算法原理 路径规划算法原理 1.建立轨迹规划坐标系 2、建立初始规划轨迹 3. 轨迹曲线插值 车辆路径规划跟随原理 运动规划 什么是Motion Planning Moti…

Vite首次启动慢的问题

前言 ::: warning ​ 众所周知&#xff0c;通常情况下Vite要比Webpack快&#xff0c;但经过实际感受&#xff0c;默认情况下&#xff0c;Vite项目的启动速度确实很快&#xff0c;但如果某个界面是第一次进入&#xff0c;且依赖比较多或者比较复杂的话&#xff0c;就会很慢&am…

记一次 .NET某培训学校系统 内存碎片化分析

一&#xff1a;背景 1. 讲故事 前些天有位朋友微信上找到我&#xff0c;说他们学校的Web系统内存一直下不去&#xff0c;让我看下到底是怎么回事&#xff0c;老规矩让朋友生成一个dump文件丢给我&#xff0c;看一下便知。 二&#xff1a;WinDbg 分析 1. 托管还是非托管 要…

elasticsearch 配置用户名和密码

无密码的其他配置项在&#xff1a;https://blog.csdn.net/Xeon_CC/article/details/132064295 elasticsearch.yml配置文件&#xff1a; xpack.security.enabled: true xpack.security.http.ssl.enabled: true xpack.security.http.ssl.keystore.path: /path/to/elastic-certi…

js实现左右列表对齐(左边点击时,右边滚动和左边对齐。反之右边点击时,左边滚动和右边对齐)

需求&#xff1a; js实现左右列表对其&#xff08;左边点击时&#xff0c;右边滚动和左边对齐。反之右边点击时&#xff0c;左边滚动和右边对齐&#xff09; 效果示意图&#xff1a; 点击6666的效果图如下&#xff1a; 实现代码&#xff1a; 思路&#xff1a; 1…需要一个…

日期类相关练习题

前言 本文记录一些有关日期类的oj题题解,实现过日期类小项目的可以练一下手,本文不做过多讲解. 目录 前言一、求123...n题目介绍:解题思路:代码实现: 二、计算日期到天数转换题目介绍:解题思路:代码实现: 三、日期累加题目介绍:解题思路:代码实现 四、日期差值题目介绍代码实…

W6100-EVB-PICO做DNS Client进行域名解析

前言 在上一章节中我们用W6100-EVB-PICO通过dhcp获取ip地址&#xff08;网关&#xff0c;子网掩码&#xff0c;dns服务器&#xff09;等信息&#xff0c;给我们的开发板配置网络信息&#xff0c;成功的接入网络中&#xff0c;那么本章将教大家如何让我们的开发板进行DNS域名解…

四、JVM-对象内存模型

Java对象内存模型 一个Java对象在内存中包括3个部分&#xff1a;对象头、实例数据和对齐填充 数据 内存 – CPU 寄存器 -127 补码 10000001 - 11111111 32位的处理器 一次能够去处理32个二进制位 4字节的数据 64位操作系统 8字节 2的64次方的寻址空间 指针压缩技术 JDK1.6出…

聚观早报 | iPhone 15 Pro系列有望成为苹果三年来最大升级

【聚观365】8月3日消息 苹果三年来最大升级 小米驰援北京河北暴雨救灾 印度要求特斯拉仿效苹果 比亚迪7月新能源车销量同比增长61% 富士康计划在印度新建两家零件工厂 苹果三年来最大升级 苹果将继续在今年9月举办一年一度的秋季新品发布会&#xff0c;届时全新的iPhone …

GC 深入(小白,对gc有一个进一步的了解)

垃圾回收器的搭配 一般固定 一般这年轻代垃圾回收器&#xff0c;老年代垃圾回收器&#xff0c;如上图搭配着使用 1.8呢默认就是最后边那哥俩 jvm调优 一个就是增加吞吐量 一个就是减少STW的时间。 三色标记算法&#xff08;理解根可达算法&#xff09; 并发的可达性分析 有…

8.2Jmeter5.1:察看结果树的响应结果乱码

【问题描述】 Jmeter察看结果树的响应结果乱码 原因&#xff1a;jmeter.properties未设置语言 【解决方案】 修改jmeter.properties的属性&#xff0c;然后重启Jmeter # The encoding to be used if none is provided (default ISO-8859-1) sampleresult.default.encodingut…

AB实验遇到用户不均匀怎么办?—— vivo游戏中心业务实践经验分享

作者&#xff1a;vivo 互联网数据分析团队 - Li Bingchao AB实验是业务不断迭代、更新时最高效的验证方法之一&#xff1b;但在进行AB实验效果评估时需要特别关注“用户不均匀”的问题&#xff0c;稍不注意&#xff0c;产出的研究结论就可能谬以千里&#xff0c;给业务决策带来…

百度搭台,千家打擂,文心杯创业大赛成投资人新宠?

“百模大战”打响&#xff0c;掀起大模型领域“创业热潮”。今年5月31日&#xff0c;百度启动“文心杯”创业大赛&#xff08;后简称“大赛”&#xff09;&#xff0c;不到1个月报名时间&#xff0c;吸引近1000个项目激烈角逐&#xff0c;在知名投资人和AI专家的权威评审和层层…

.Net6 Core Web API 配置 log4net + MySQL

目录 一、导入NuGet 包 二、添加配置文件 log4net.config 三、创建MySQL表格 四、Program全局配置 五、帮助类编写 六、效果展示 小编没有使用依赖注入的方式。 一、导入NuGet 包 ---- log4net 基础包 ---- Microsoft.Extensions.Logging.Log4Net…

go逆向符号恢复

前言 之前一直没怎么重视&#xff0c;结果发现每次遇到go的题都是一筹莫展&#xff0c;刷几道题练习一下吧 准备 go语言写的程序一般都被strip去掉符号了&#xff0c;而且ida没有相关的签名文件&#xff0c;没办法完成函数名的识别与字符串的定位&#xff0c;所以第一步通常…

HCIP——BGP反射器及联邦

BGP反射器及联邦 一、路由反射器1、路由反射器的角色2、路由反射规则3、路由反射器下的防环Originator_IDCluster_List应用举例配置方法 二、联邦1、联邦概念2、联邦的配置 路由反射器和联邦是两种专门针对IBGP水平分割设计的解决方案&#xff0c;我们依次来看下这两种技术 一…

基于 Llama2 和 OpenVINO™ 打造聊天机器人

点击蓝字 关注我们,让开发变得更有趣 作者 | 英特尔 AI 软件工程师 杨亦诚 指导 | 英特尔 OpenVINO 布道师 武卓博士 排版 | 李擎 基于 Llama2 和 OpenVINO™ 打造聊天机器人 Llama 2是 Meta 发布了其最新的大型语言模型&#xff0c;Llama2 是基于 Transformer 的人工神经网络&…