数组是一组相同类型元素的集合,这些元素的类型必须是相同的,可同时存放一个或多个数据。
其中,数组包括一维数组和多维数组,一维数组和二维数组是我们今天要重点介绍的。
数组的语法形式为
type arr_name [常量值];
存放在数组的值被称为数组元素,数组在定义时也可以定义大小和类型
在这条语法形式里,type指的是内置类型,arr_name则是自定义的数组名,[]内的常量值代表着数组大小
我们在使用数组之前,需要将数组进行初始化,即将介绍的就是,数组初始化的方法
数组的初始化可以分为三种,我们只介绍完全初始化和不完全初始化
完全初始化可以简单理解为,定义的所有元素个数与定义的数组大小相同
如以下定义
int arr[5]={1,2,3,4,5};
在这个数组中,我们定义了一个数组大小为5,而我们把所有的5个元素都定义了一个具体值,这就是完全初始化
与完全初始化不同的是,不完全初始化则是元素个数与定义的数组大小不同,如
int arr[10]={1,2,3,4,5};
显然,大括号内的元素个数并不满足定义的数组大小10个,难道说剩下的空间就什么都不放吗?
其实不是,剩余的元素会自动初始化为0。
当然,我们还要掌握一种情况,如果数组初始化了,是可以省略数组大小的,就像以下定义
int num[]={1,2,3};
在num这个数组中,我们初始化了三个元素分别为1,2,3
数组是有类型的,是一种自定义类型,如果去掉自定义的数组名,剩下来的部分就称作数组的类型。如
int arr[50];
char ch[10];
上面数组的类型是int [50];,下面数组的类型则是char [10];
即都为去掉数组名后剩下来的部分
一维数组是可以用来储存数据的,那具体改怎么使用,是我们接下来要介绍的
在数组中,每个元素都对应着一个数组下标。
假如数组有十个元素
int arr[10]={1,2,3,4,5,6,7,8,9,10};
分别对应的下标如下
元素 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
显然,数组下标是从0开始记录的。那么,有n个元素,最后一个数的下标就是n-1。
我们需要记住的是:数组元素通过打印下标的方式来进行打印
具体该如何操作,假设我们要打印数组中的元素5
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d", arr[4]);
return 0;
}
很显然,打印数字5时我们用到的则是5的下标4。
为了找到下标,我们使用了C语言中的下标引用操作符,即[ ],在这段代码中,printf函数里的arr[4]
即引用下标为4的元素5,这样我们就能理解数组下标的作用,是帮助我们找到数组元素的了。
如果我们想要打印数组里面的所有元素,将是这样的
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;
}
输出的结果是
使用一个for循环,再用下标操作引用符引用0~9下标便能打印出数组1~10的数。
还是1~10的数组,我想要实现输入一个数组下标,找到对应的数组元素,要实现以下代码和结果
如果我们想要给数组输入自己想要的数据,可以用以下代码实现
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
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;
}
我们需要记住的是, int arr[10] = {1,2,3,4,5,6,7,8,9,10};这段代码只是将数组里的元素初始化了,什么叫初始化?如果后面的代码没有改变元素,输出的就是初始化的元素。但是在这段代码里,我们引用了scanf函数以此来输入我们想要的数组元素,来进行打印。
我们随机输入十个数字,得到的结果是这样的
为了能够表达数组的元素个数,我们需要先了解一维数组在内存中的储存,通过下面一条代码来看
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;
}
程序运行的结果则是
看得出来,每个连续的元素之间相差了四个字节(因为一个整型是4个字节),所以,我们能够得到数组在内存中是连续存放的这样一个结论。
在定义数组时,我们常常会定义数组大小,可以直接知晓数组里面的元素个数。
但是如果我们并没有定义数组大小,却想要应用数组的元素个数,就需要用到sizeof来计算数组元素个数了。
sizeof是C语言中的一个关键字,可以计算类型或变量大小的,我们先看看sizeof的使用
int main()
{
int arr[10] = { 0 };
printf("%d\n", sizeof(arr));
return 0;
}
看这组代码,我们定义了一组数组含有十个元素0,每个元素所占的内存是4个字节,所以,输出的数应该是40,那我们看看运行的结果是
结果在我们的预测之中,正是40.
40所代表的是数组内所有元素总共占的内存,如果我们想要知道数组的元素个数,则还需知道单个元素所占有的内存,我们只用选择数组的第一个元素即可,即arr[0] 。
接下来,我们就能计算出一个数组的元素个数了,需要用到的代码如下
int main()
{
int arr[10] = { 0 };
printf("%d\n", sizeof(arr)/sizeof(arr[0]));
return 0;
}
用数组占的总内存除去数组单个元素占的内存就是数组个数,在这条代码中的数组个数应该为10,那么我们运行一下看看结果是不是10
很容易就能得到,结果是10,这就是计算数组元素个数的方法,能够灵活应变。
一维数组的概念,大致就这么多,接下来要介绍的是二维数组
二维数组简单点概括就是把一维数组作为数组元素,从它的语法形式就能看出来
typr arr_name[常量值1][常量值2]
二维数组的创建其实和以为一维数组大差不差,就是两个常量值代表着不同的意义。
常量值1代表着行数,常量值2代表着列数,可以这么定义
int arr[3][5];
chae ch[4][6];
第一行代码:3代表有数组有3行,5则是数组有5列,int是内置类型,arr是数组名
二维数组的初始化就有很多讲究的地方,先介绍完全初始化,假设是定义以下一个数组
int arr[3][5];
从之前的讲解我们很清楚这数组的组成是3行5列,如果我们要将第一行填满1,2,3,4,5。第二行填满2,3,4,5,6。第三行则填3,4,5,6,7。那么数组应该初始化为
int arr[3][5]={1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
只需要按顺序填好元素,便能完成二维数组的完全初始化
1 | 2 | 3 | 4 | 5 |
2 | 3 | 4 | 5 | 6 |
3 | 4 | 5 | 6 | 7 |
另外还有一种初始化的方式,按照行进行初始化。
为什么要按照行初始化呢?
想一下,以上面的二维数组为例,如果我要在第一行只输入{1,2},第二行输入{3,4},第三行只输入{5,6}。这时,我们就要按照行来初始化了。
得用以下代码实现
int arr[3][5]={{1,2},{3,4},{5,6}};
如果按照这样初始化,那么得到的二维数组将是
1 | 2 | 0 | 0 | 0 |
3 | 4 | 0 | 0 | 0 |
5 | 6 | 0 | 0 | 0 |
这样,我们就能满足行的元素的初始化
还有一种初始化,是省略行但不省略列的情况,可以有以下几种定义方式
int arr1[][5]={1,2,3};
int arr2[][5]={1,2,3,4,5,6,7};
int arr3[][5]={{1,2},{3,4},{5,6}};
分别用表格形式来呈现不同的二维数组
首先是arr1
1 | 2 | 3 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
其中行数不一定只用3行,但是一定是有5列的,1,2,3三个数先按顺序排到数组的第一行,排够了以后接下来的元素都初始化为0
arr2的表现形式则是
1 | 2 | 3 | 4 | 5 |
6 | 7 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
排列时依旧是按照顺序1~7这么排的,但是由于数组的初始化只有5列,那么第一行放满五个数以后自动放在第二行,而行数没有定义也是无限的。
arr3的形式是
1 | 2 | 0 | 0 | 0 |
3 | 4 | 0 | 0 | 0 |
5 | 6 | 0 | 0 | 0 |
这是在不限定行数情况下分行的初始化,未进行初始化的元素默认为零。
那么,我们可以思考一个问题,为什么可以省略行,而不可以省略列呢?
假设在初始化的时候行数不能省略,列数可以省略,这时,我们可以输入10个元素、20个元素甚至是上亿个元素。由于这时候数组没有列数的限定,初始化再多的元素,会填满这一行吗?会不会自动填到下一行中去呢?答案肯定是不会的,如果省略列数的话,二维数组就像是一维数组一样,虽然有可能有其他行的存在,但是其他行里的元素都为0,这样,二维数组的初始化就没有意义了,因此行能省略,列不能省略。
二维数组中,行和列的下标是分开来的,但是行和列的下标都是从0开始的,如下表
数组下标 | 0 | 1 | 2 | 3 | 4 |
0 | 1 | 2 | 3 | 4 | 5 |
1 | 2 | 3 | 4 | 5 | 6 |
2 | 3 | 4 | 5 | 6 | 7 |
通过这张表格,我们就能像坐标一样,快速定位每个数的位置。
假设我们要找第二行的数字3,可以用以下代码实现
int main()
{
int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
printf("%d", arr[1][1]);
return 0;
}
在这条代码中,中括号内的1分别代表了行和列的下标,正是我们要找的3
所以,打印出来的结果如下
很显然,条件满足
我们还是以上面那个数组为例,通过循环的方法来实现二维数组的输入和输出。
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;
}
我们随机输入15个数,得到的结果是
这样,我们就能满足数组的输入
我们先通过一段代码来打印二维数组的内存
int main()
{
int arr[3][5] = { 0 };
int i, 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个字节,可见,二维数组在内存中也是连续存放的,如下图所示
下标 | 0 | 1 | 2 | 3 | 4 | 0 | 1 | 2 | 3 | 4 | 0 | 1 | 2 | 3 | 4 |
元素 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
这是将二维数组的每行元素头尾连续摆放的结果,显然元素连续存放的结论是成立的
由于VS中变长数组不能使用,暂不介绍。我们只需要记住一点不要用变量来指定数组大小,VS不支持。
数组的内容,大致就这么多了
The end