目录
一、数组的概念
数组:一组相同类型元素的集合。
- 数组中的元素个数不能为0
- 数组中存放的多个数据类型是相同的。
数组可分为一维数组和多维数组,其中比较常见的是一维数组。
二、一维数组的创建和初始化
2.1 数组的创建
数组的创建方式:
type arr_name[const_n];
存放在数组中的值被称为数组的元素,数组在创建的时候可以指定数组的大小和数组的元素类型。
type:指定的是数组中存放数据的类型,可以是:char,short,int,float等,也可以是自定义类型。
arr_name:指的是数组名的名字,这个名字根据实际情况,起的有意义即可。
注意:数组名只是一个符号,不是变量。
[ ]中的const_n:用来指定数组的大小的,这个数组的大小根据实际的需求指定即可。
2.2 数组的初始化
数组的初始化指的是,在创建数组的同时给数组的内容一些合理初始值。
初始化分为完全初始化和不完全初始化。
如下图所示:
注意:如果未初始化数组,则需要写入数组的大小。
如果初始化了,可忽略不写,编译器会根据后面初始化内容来开辟多少个空间。
2.3 数组的类型
数组也是有类型的,数组算是一种自定义类型,去掉数组名剩下的就是数组的类型。
int arr1[10]; //类型为int [10]
char arr2[5]; //类型为char [5]
可用以下方式来测出数组的类型:
注意:当使用数组的类型的时候,数组的类型是必须加上元素个数的,它的元素个数也是类型的一部分,如果不加元素个数,就会报错。
例如下面代码:
三、一维数组的使用
3.1 数组下标
数组的每个元素都是有下标的,下标是从0开始。
数组 | 1 | 2 | 3 | 4 | 5 |
下标 | 0 | 1 | 2 | 3 | 4 |
假如有n个数组,那么最后一个数组的下标就是n-1。
c语言中数组的访问提供了一个操作符[ ],叫下标引用操作符。
数组是使用下标来访问的,下标是从0开始的。
注意:如果未初始化数组,则需要写入数组的大小。如果初始化了,可忽略不写,编译器会根据后面初始化内容来开辟多少个空间。
3.2 数组的输入和输出
如何输入和输出整个数组的元素,我们看如下代码:
#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;
}
运行结果如图所示:
利用for循环遍历数组内的元素。
四、一维数组在内存中的存储
随着数组下标的增长,元素的地址也是有规律的递增,由此得出规律:
数组在内存中是连续存放的。
五、二维数组的创建
5.1 二维数组的概念
如果我们把一维数组作为数组的元素,这时候就是二维数组;二维数组作为数组元素的数组被称为三维数组,二维数组以上的数组统称为多维数组。
5.2 二维数组的创建
二维数组的语法结构如下:
数组元素类型 数组名 [ ] [ ]
第一个括号表示行数 ,第二个括号表示列数。
例如:char arr[3] [5]; double arr[2] [4];
5.3 二维数组的初始化
5.3.1不完全初始化
int arr1[3][5] = {1,2};
int arr2[3][5] = {0};
5.3.2完全初始化
int arr3[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
5.3.3按照行初始化
int arr4[3][5] = {{1,2},{3,4},{5,6}};
5.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}};
二维数组如果有初始化,那么行可以省略,列不可以省略。
注意:前提是得初始化,才能省略行。
如果没有列的话,就相当于一维数组了。
六、二维数组的使用
6.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,代码如下:
6.2 二维数组的输入和输出
如何输入输出整个二维数组呢?我们看如下代码:
#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;
}
用两个for循环,外层表示行,内层表示列。
七、二维数组在内存中的存储
可以把二维数组理解为一维数组的数组。
int arr [3] [4] ;和 int arr [12]; 这两个数组在内存中的体现(布局)是一模一样的。只是两种的访问形式不一样,一个是以一维数组的形式来访问,一个是以二维数组的形式。
由下图可知,二维数组中的每个元素在内存中是连续存放的。
八、C99中的变长数组
在C99标准之前,C语言在创建数组的时候,数组大小的指定只能使用常量、常量表达式。
如果初始化数据的话,可以省略数组大小。
如下:
int arr1[10];
int arr2[3+5];
int arr3[ ] = {1,2,3};
由于语法的限制,使得创建数组空间的大小不够灵活,所以C99引入了变长数组,规定了可以使用变量来指定数组的大小。
变长数组:意思是数组的大小是通过变量来指定的。
变长数组的根本特征:就是数组长度只有运行时才能确定,所以变长数组不能初始化。
注意:变长数组的意思是数组大小是可以使用变量来指定,在程序运行的时候,根据变量的大小来指定数组的元素个数,而不是数组的大小是可变的。数组的大小一旦确定就不能再变化了。
九、数组越界
数组的下标是有范围限制的。
数组的下标规定是从0开始,如果数组有n个元素,最后一个元素的下标就是n-1
所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。
c语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的,所以程序员写代码时,最好自己做越界的检查。
9.1 二维数组的越界
二维数组越界:二维数组不管行列也有越界的存在,它们会堆到最后输出,最终访问到非自己空间内部的元素。
看如下图代码:
[0][4]越界后读到了[1][0]的位置。
arr[0][4]和[1][0](即两个5)地址一样。两个9也是如此,没有越界。但是最后一个越界了。