【C语言修炼手册】(五)数组

当有非常多个数据时,我们不能为每一个数据定义一个变量。这时,我们就想能不能有一种方法-----创建一个空间,能够存放多个数据。这种方法就是使用数组
一组相同类型数据的集合称为数组

数组又分为很多种,有一维数组,二维数组,三维数组,多维数组等等。我们用到最多的就是一维数组和二维数组。


一维数组的创建和初始化

创建

Type  arr_name[const_n];
  • Type - 数组元素类型
  • arr_name - 数组名
  • const_n - 数组中的元素序号,为常量表达式,指定数组大小,称为下标切记!数组下标从0开始,而不是从我们熟悉的1开始)
    在这里插入图片描述

这是一个非常常见的错误。数组元素只能是常量表达式。 不过,有些编译器对于此种情况是不会报错的(比如一些初学者刚开始会使用的devc++)为什么呢?是因为它是C99语法支持的变长数组,即数组大小可以是变量。但是,VS2019是不支持C99的。 最好不用变量

初始化

int a = 1; // 初始化
int a[4] = { 1, 2, 3, 4 }; //完全初始化
int a[10] = { 1, 2, 3, 4, 5 }; //不完全初始化
int a1[ ] = { 1, 2, 3, 4, 5 };
//相当于 int a1[5] = { 1, 2, 3, 4, 5 };
(根据初始化内容来确定数组个数)
//1.
char ch[5] = { 'a','b','c' };
char ch[ ] = { 'a','b','c' };

//2.字符串初始化
char ch3[5] = "abc"; //a b c \0 0
char ch4[ ] = "abc"; //a b c \0

//3.
char ch5[] = "abc";
char ch6[] = { 'a','b','c' };

printf("%s\n", ch5);
printf("%s\n", ch6);

//4.
printf("%d\n", strlen(ch5));
printf("%d\n", strlen(ch6));
  • 数组元素的值由{ }包围,各个值之间以,分隔。
    1.在这里插入图片描述

2.在这里插入图片描述

3.在这里插入图片描述
在这里插入图片描述

4.在这里插入图片描述
// 15为随机值(由第3点可知ch6的\0不知道在哪出现,故打印出随机值)

注意

  • 赋值的元素少于数组总体元素的时候,剩余的元素自动初始化为 0

  • 对于short、int、long,就是整数 0;
    对于char,就是字符 ‘\0’;
    对于float、double,就是小数 0.0。

  • ch6数组长度还是3,只是求字符串长度是不确定的。要明确这一点。数组长度和字符串长度是两个不同的概念。

  • 给全部元素赋值时,在定义数组时可以不给出数组长度。即int a1[ ]

  • 数组大小可以通过计算得到。
    int sz = sizeof(arr) / sizeof(arr[0]);

一维数组在内存中连续存储

补充知识 -> 敲黑板!(〃‘▽’〃)
1.%p - 按地址的格式打印 - 十六进制的打印
在这里插入图片描述
2.数组名是首元素的地址

打印int a[4]数组
在这里插入图片描述

下面画出int a[4]在内存中存储情形
在这里插入图片描述

  • 数组是一个整体,它的内存是连续的;也就是说,数组元素之间是相互挨着的,彼此之间没有一点点缝隙。
  • 随着数组下标的增长,数组地址是从低到高变化的。
  • 连续的内存为指针操作(通过指针来访问数组元素)提供了便利

二维数组的创建和初始化

创建

dataType arrayName[length1][length2];
  • 和一维数组形式相似,比如int arr[3][4]
    在这里插入图片描述
    我们可以将int arr[3][4]看作一个三行四列的矩阵, 一共有 3×4=12 个元素。每个元素的类型都是整型。
  • 和一维数组一样,二维数组行,列下标也是从0开始的。

初始化

int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };//完全初始化
int arr[3][4] = { 1, 2, 3, 4, 5, 6, 7 };//不完全初始化  
int arr[3][4] = { {1,2},{3,4},{5,6} };//按行分段赋值
int arr[ ][4] = { {1,2},{3,4},{5,6} };//
  • 完全初始化
  • 不完全初始化 - 未赋值的元素会自动补0(如果是字符数组,其实是补\0)
  • 按行分段赋值 ,赋值后各元素的值为
    在这里插入图片描述
  • 二维数组下标中,有几行是可以省略的,但是一行有几个元素是不可以省略的。为什么呢?我们等下来揭晓ヽ(^_−)ノ

注意

观察下面这张图片,你发现了什么?
在这里插入图片描述
没错!你说对了!

  • 二维数组在内存中是连续存放的。即使是跨行,也是连续的。为什么呢?因为二维数组的形式是我们假想出来的。它真正的形式其实也是按行排列的。
  • 这也解答了上面为什么一行有几个元素是不能省略的这一问题。因为如果元素个数不能确定,第一行无法确定,那么我们就无法确定第二行从哪里开始,最终导致数组长度无法确定。

在这里插入图片描述

  • 二维数组可以看作由几个一维数组组成,还是int arr[3][4],我们可以用arr[0]表示第一行,arr[1]表示第二行,arr[2]表示第三行。

数组作为函数参数

有时候,我们在写代码时要将数组作为参数传给函数。相信大家都听说过冒泡排序,在冒泡排序中,我们就要用到传参。

下面给出一张动图来介绍一下冒泡排序

在这里插入图片描述(该图片来源于网络)

冒泡排序的思想

  • 两两相邻,元素比较,交换。
  • 假如有n个数字,那么进行比较的趟数就有n-1趟。

下面是代码实现

void bubble_sort(int arr[],int sz)
{
	int i = 0;
	int t = 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])
			{
				t = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = t;
			}
		}
	}
}

int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//升序 - 冒泡排序
	bubble_sort(arr,sz);
	return 0;
}

有些同学可能会把数组长度的计算放在bubble_aort 函数里面实现,这是不正确的。我们要明白,数组名传参只是把首元素的地址传过去。bubble_aort 函数接收到的只是4个字节,因此在bubble_aort 函数内求到的数组长度是错误的。

那么我们平时所说“数组名传参只是把首元素的地址传过去”这一说法是否正确?,接下来我们验证一下。

int main()
{
	int arr[10] = { 0 };
	printf("%p\n", &arr[0]);
	printf("%p\n", arr);
	return 0}

在这里插入图片描述

很显然,这一说法是正确的。但是,有两个例外

  1. sizeof(数组名) - 数组名表示整个数组 - 计算的是整个数组的大小 - 单位是字节
  2. &数组名 - 数组名表示整个数组 - 取出的是整个数组的地址

当然,它们的意义肯定是不相同的。接下来我们来验证一下

int main()
{
	int arr[10] = { 0 };
	printf("%p\n", &arr);
	printf("%p\n", &arr+1);//数组加1
	printf("%p\n", arr);
	printf("%p\n", arr+1);//数组首元素加1
	return 0}

在这里插入图片描述
可见,数组加1和数组首元素加1其意义是不同的。

这样的代码显然不够高效,我们还可以再优化一下。当我们发现已经完成排序时,我们不必再进行后面的排序,避免浪费时间。

优化后

void bubble_sort(int arr[],int sz)
{
	int i = 0;
	int t = 0;
	for (i = 0; i < sz - 1; i++)
	{
		int j = 0;
		int flag = 1;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				t = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = t;
				flag = 0;
			}
		}
		if (flag == 1)
		{
			break;
		}
	}

}
int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//升序 - 冒泡排序
	bubble_sort(arr,sz);
	return 0;
}

形参的两种形式

  1. 数组形式
  2. 指针形式
//一维数组
//数组形式
void test1(int arr[10] {}
void test1(int arr[]) {}

//指针形式
void test1(int *arr) {}

//二维数组
//数组形式
void test2(char arr[3][5]  {}
void test2(char arr[][5])  {}

//指针形式 - 暂不介绍

数组的应用

编写一个实现三子棋的小程序。内容详见下一篇。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值