第四讲:数组

1.数组的概念

什么是数组?它是相同类型的类型的集合,它可以是一组数字,也可以是一组字符。但是它的元素个数绝对不能是0。
数组可以是一维的,也可以是多维的,一般我们常用的是二维数组。

2.一维数组

2.1一维数组的创建

一维数组的创建语法如下:

type arr_name[常量值];

存放在数组中的值被称为数组的元素,数组创建的时候可以指定数组的元素类型和元素的个数。
在这里插入图片描述

  • type是指定数组中存放的数据的类型,可以是 char类型,也可以是 int类型,或者 short类型,当然它也可以是自定义的类型,比如枚举、联合体、结构体。
  • arr_name是指定义的数组名称,一般情况下,名称的定义要有一定的意义。
  • []中的常量值是用来指定数组的大小,它的大小根据实际情况的使用来指定就可以,没必要设置的非常大,这样会浪费很多的内存空间。
    比如,我们现在想要存放20个人的数学成绩,那么我们可以创建一个数组,如下:
int math[20];

我们也可以创建其他类型的数组:

double num[10];
char ch[5];

2.2 数组的初始化

数组在创建时,有三个状态,即:

  • 未初始化:此时数组中存放的是一些乱七八糟的数据,如上面的代码 int math[20];
  • 未完全初始化:只初始化部分数组中的元素,其余元素默认初始化为0。如:int arr[5] = {1,2};
  • 完全初始化:全部初始化为我们想要的值。int arr[5] = {1,2,3,4,5};

那么数组如何初始化呢?一般使用大括号 {},将数据放在大括号中。
下面我们举例看下在编译时的情况:

#include <stdio.h>

int main()
{
	int arr[5];
	int i = 0;
	for (i = 0;i < 5;i++)
	{
		printf("%d\n", arr[i]);
	}
	return 0;
}

上面代码数组没有初始化,它的运行结果为:
在这里插入图片描述
我们在试一下未完全初始化看下效果:

#include <stdio.h>

int main()
{
	int arr[5] = { 1,2};
	int i = 0;
	for (i = 0;i < 5;i++)
	{
		printf("%d\n", arr[i]);
	}
	return 0;
}

运行结果如下所示:
在这里插入图片描述
至于完全初始化我们就不在展示了,但是这里要强调一下如果初始化项多余数组定义时的个数,编译器会报错。如下面代码:

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

2.3数组的类型

数组也是有类型的,我们在第二讲数据类型中介绍过,自定义类型中除了枚举,结构体,联合体,还有一个是数组。
在数组中,去掉数组名留下的就是数组的类型。
如下:

int arr1[10];
int arr2[12];
char ch[5];
  • arr1数组的类型是 int [10]
  • arr2数组的类型是 int[12]
  • ch 数组的类型是 char [5]

3.一维数组的使用

上面我们介绍了一维数组的定义,它可以用来存放数据,那么我们怎么使用一维数组呢?

3.1数组的下标

在C语⾔中数组的访问提供了⼀个操作符 [] ,这个操作符叫:下标引⽤操作符
我们在定义数组的时候,[]中的常量值就是数组的最大下标,表示它能存放的最大的元素个数,我们存放数据时,不能超过这个数量。
我们如何用数组中的元素呢?我们可以把下标理解为数组的索引数,它是从0开始的,假设定义一个数组arr[10],那么它的最后一个元素的下标就是10-1个数,即n-1个个数。我们举例说下:

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

这段代码我们存放了从1到10一共10个数字,它的下标表现为:
在这里插入图片描述
此时我们如果想访问下标为7的元素,我们就
可以使⽤ arr[7] ,想要访问下标是3的元素,就可以使⽤ arr[3] ,如下代码:

#include <stdio.h>

int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9,10}; 
 printf("%d\n", arr[7]);
 printf("%d\n", arr[3]);
 return 0;
}

结果如下:
在这里插入图片描述

如果想要一次性打印出所有数组内的数据,只要我们产⽣数组所有元素的下标就可以了,那我们使用for循环产生0~9的下标,接下来使用下标访问就⾏了。

#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 ", arr[i]);
 }
 return 0;
}

执行效果如下:
在这里插入图片描述

3.2 数组的输入

学会了数组中元素的调用,但是我们要怎么给数组中输入我们想要的数据呢?我们还是结合for循环来实现数组的数值输入:

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

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

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

一维数组的调用和数据的输入我们了解过了,但是它在内存中是怎么存储的呢?为了更深入的了解一维数组的存储,我们先打印下数组每个元素在内存中的地址:

#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("arr[%d] = %p\n", i,&arr[i]);
	}
	return 0;
}

代码中printf中的%p的用法我们在printf与scanf函数中有介绍,它是一个指针占位符。
在这里插入图片描述
从输出的结果是十六进制数据,我们看到数组随着下标的增⻓,地址是由小到大变化的,而且相邻的两个元素的地址差值为4,为什么是4呢?因为一个int类型的数据就是4个字节。
在这里插入图片描述
由上面我们得出结论:数组在内存中是连续存放的

5.计算数组元素个数

在上面我们遍历数组的应用中,我们是知道数组实际的元素个数的,假如我们不知道数组的元素个数该怎么做呢?这时就用到了sizeof()来计算了。

sizeof()的应用我们在第二讲数据类型中有过介绍它的使用方法和作用,文中说到sizeof()是用来计算数据类型的大小的,那么我们怎么用sizeof()来计算数组的元素个数呢?
上代码我们看下:

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

这里运行后输出的结果是40,sizeof()在这里计算的是整个arr[]数组所占用的内存空间大小,单位是字节。
而我们是知道数组中存放的所有元素的数据类型是相同的,那只要计算其中任一个元素占用的字节个数,数组的元素个数不就能算出来了么。我们选择数组的第一个元素计算它的大小:sizeof(arr[0]),在代码中我们显示如下:

#include <stido.h>

int main()
{
	int arr[10] = { 0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("%zd\n", sizeof(arr));
	printf("%zd\n", sizeof(arr[0]));
	printf("%d\n", sz);
	return 0;
}

运行结果如下:
在这里插入图片描述
我们看到最后输出sz的值为10,它不就是表示arr[]数组中的元素个数么。

6.二维数组

6.1二维数组的概念

前⾯学习的数组被称为⼀维数组,数组的元素都是内置类型的,如果我们把⼀维数组做为数组的元素,这时候就是⼆维数组,⼆维数组作为数组元素的数组被称为三维数组,⼆维数组以上的数组统称为多维数组
这里可能讲解的比较抽象,初学者可能不太好理解,我们可以简单的理解为一维数组是一条直线,我们知道距离就能达到想要的位置,那么二维数组我们可以理解为一个表格,我们知道横向的距离,然后在根据纵向的距离就能到达我们想要的位置。
在这里插入图片描述

6.2二维数组的创建

二维数组的创建语法如下:

type arr_name[常量值1][常量值2]

例如:

int arr[8][5];
char ch[10][6];

上面代码中表示的信息是:

  • int表示数组的每个元素的数据类型是整数型。
  • 8代表的是数组有8行。
  • 5代表的是数组每行有5个元素。
  • arr是数组名,可以根据根据需要定义它的名字。

6.3二维数组的初始化

我们知道了一维数组的初始化,那么二维数组如何初始化呢?它和一位数组一样,也是用大括号{}初始化的。

6.3.1 不完全初始化

在一维数组中我们说到,不完全初始化的情况下,未被初始化的元素将被默认初始化为0,那么在二维数组中同样也是这个情况。如下示例:

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

这个代码表示我们对arr1数组第一行的第一个和第二个元素初始化数值为1和2,对arr2数组的第一行第一个元素的值初始化0。
在这里插入图片描述

6.3.2 完全初始化

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

数组arr3[]完全初始化后数据的存放。
在这里插入图片描述

6.3.3 按照行初始化

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

数组arr4[]按照行初始化后数据的存放。
在这里插入图片描述

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

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

在这里插入图片描述

7. 二维数组的使用

7.1 二维数组的下标

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

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

在这里插入图片描述
图中最左侧表示行号,第一行是列号,都是从0开始的,比如,我们说:第二行,第四列,能快速的定位到7。
我们用代码打印下看下:

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

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

7.2 二维数组的输入和输出

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

#include <stdio.h>

int main()
{
 int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
 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;
}

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

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

#include <stdio.h>

#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;
}

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

在这里插入图片描述
了解清楚二维数组在内存中的布局,有利于我们后期使用指针来访问数组的学习。

9.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,在VS2022上不支持C99中的变长数组,没有办法测试,大家可以自己用gcc自己测试下。

本博客只为学习使用,如有错误请大佬指出,感谢大家支持!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值