文章目录
- 一、数组的概念
- 二、一维数组
- 1.一维数组的创建
- 2.一维数组的初始化
- 3.数组的类型
- 4.一维数组的使用
- 5.一维数组在内存中的存储
- 6.sizeof计算数组元素个数
- 三、二维数组
- 1.二维数组的概念
- 2.二维数组的创建
- 3.二维数组的初始化
- 4.二维数组的使用
- 5.二维数组的输入和输出
- 6.二维数组在内存中的存储
- 7.二维数组中对于数组名的理解
一、数组的概念
数组是一组相同类型元素的集合;从这个概念中我们就可以发现2个有价值的信息:
●数组中存放的是1个或者多个数据,但是数组元素个数不能为0。
●数组中存放的多个数据,类型是相同的。
数组分为一维数组和多维数组,多维数组一般比较常见的是二维数组。
二、一维数组
1.一维数组的创建
一维数组创建的语法如下:
存放在数组中的值被称为数组的元素,数组在创建的时候可以指定数组的大小和数组的元素类型。
●type指定的是数组中存放的数据的类型,可以是: char、short、int、float等,也可以自定义的类型。
●arr_name指的是数组的名字,这个名字根据实际情况,起的有意义就行。(注意不要跟关键字重名)
●[ ]中的常量值是用来指定数组的大小的(元素个数),数组的大小根据实际的需求指定就行。
需要注意在创建数组时,[ ]中要给的是一个常量才可以,不能给变量。[ ]可以直接使用常量,常量表达式或者宏定义都可以。示例:
#include<stdio.h>
#define NUM 6
int main()
{
int arr1[10];
int arr2[2+3];
char ch[NUM];
return 0;
}
2.一维数组的初始化
在创建数组的同时,给一些初始值,这种就称为数组的初始化。那数组如何初始化呢?数组的初始化一般使用大括号,将数据放在大括号中:
//完全初始化
int arr1[5]={1,2,3,4,5};
//不完全初始化
int arr2[5]={1};//第一个元素初始化为1,剩下的元素默认初始化为0
3.数组的类型
数组也是有类型的,数组算是一种自定义类型,去掉数组名留下的就是数组的类型。例如:
int arr[10];
char ch[5];
arr数组的类型为int [10],ch数组的类型为char [5]。
4.一维数组的使用
学习了一维数组的基本语法,一维数组可以存放数据,存放数据的目的是对数据进行操作,那我们如何使用一维数组呢?
(1)数组下标
C语言规定数组是有下标的,下标是从0开始的,假设数组有n个元素,最后一个元素的下标是n-1,下标就相当于数组元素的编号,如下:
int arr[10]={1,2,3,4,5,6,7,8,9,10};
在C语言中,对于数组的访问提供了一个操作符 [ ],这个操作符叫:下标引用操作符。
有了下标引用操作符,我们就可以轻松的访问到数组的元素了,比如我们访问下标为6的元素,我们就可以使用arr[6],想要访问下标是4的元素,就可以使用arr[4],如下代码:
#include<stdio.h>
int main()
{
int arr[10]={1,2,3,4,5,6,7,8,9,10};
printf("%d\n",arr[6]);
printf("%d\n",arr[4]);
return 0;
}
运行结果:
(2)数组元素的打印
如果想要打印数组的元素在屏幕上,就用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)数组元素的输入
可以根据自己的需要,用scanf函数给数组输入值,存入到数组中。给数组输入想要的数据:
#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;
}
运行结果:
5.一维数组在内存中的存储
一维数组在内存中是怎样存储的呢?我们通过下面一段代码来看:
#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;
}
运行结果:
从输出的结果可以发现,数组随着下标的增长,地址是由小到大变化的,并且我们发现每相邻两个元素之间相差4(因为一个整型是4个字节)。所以我们得出结论:数组在内存中是连续存放的。
6.sizeof计算数组元素个数
在遍历数组的时候,我们经常想知道数组的元素个数,那C语言中有办法使用程序计算数组元素个数吗?答案是有的。通过sizeof可以求元素个数。其实sizeof是一个操作符,是用来计算类型或者变量的大小的(单位字节)。sizeof可以用来计算数组的大小:
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
printf("%d\n", sizeof(arr));
return 0;
}
运行结果:
输出的结果为40,计算的是整个数组所占内存空间的大小,单位是字节(数组名单独放在sizeof中,计算的是整个数组的大小)。又因为数组中所有元素的类型是相同的,所以只要计算出一个元素所占字节的个数,那数组的元素个数就可以计算出来了。我们通常选择计算第一个元素的大小:
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
//计算数组中第一个元素的大小
printf("%d\n", sizeof(arr[0]));
//计算数组的元素个数
int sz = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", sz);
return 0;
}
运行结果:
可以看到,第一个元素的大小为4(字节),数组的元素个数为10。以后在代码中需要数组元素个数的地方就不用固定写死了,这种计算数组元素个数的方式,不管数组怎么变化,计算出的大小也会随着变化。
三、二维数组
1.二维数组的概念
上面学习的数组叫一维数组,数组的元素都是内置类型的。如果把一维数组做为数组的元素,这时候就是二维数组。二维数组作为数组元素的数组被称为三维数组,二维数组以上的数组统称为多维数组。
2.二维数组的创建
如何创建二维数组呢?语法形式是什么?如下:
例如:
int arr[3][5];
double data[2][7];
上面代码的第一行,就是一个整型的二维数组。其中:
●3表示有3行;5表示列数,即每一行有5个元素。
●int表示数组的每个元素是整型类型。
●arr是数组名,可以根据自己的需要指定名字(注意不能和关键字重名)。
第二行是一个双精度浮点型二维数组。
3.二维数组的初始化
在创建数组的同时,给一些初始值,就叫数组的初始化。二维数组的初始化也跟一维数组类似,使用大括号初始化:
(1)不完全初始化
int arr1[3][5]={1,2};
int arr2[3][5]={0};
在屏幕上打印这两个数组:
可以看到上面对于两个二维数组不完全初始化的打印结果,对于arr1数组,只初始化了两个元素,即从第一行的一维数组的第一个元素开始,从左往右依次初始化。如果一行的元素值给够了,就会从下一行一维数组的第一个元素开始从左往右初始化。对于没有给到值的元素会默认初始化为0。arr2数组只初始化了第一行的第一个元素为0,其余元素默认初始化为0。如下:
(2)完全初始化
int arr3[3][5]={1,2,3,4,5,2,3,4,5,6,3,4,5,6,7};
在屏幕上打印arr3数组的内容:
完全初始化就很好理解了:在创建二维数组的同时,对二维数组的所有元素都给一个初始值,就叫作完全初始化,对于{ }里的值,会从左往右,依次给到二维数组对应的元素。如果一行的值够了,就会从数组下一行的一维数组的第一个元素开始从左往右初始化。
(3)按照行进行初始化
什么叫按照行进行初始化?其实就是按照二维数组的每个一维数组进行初始化,在二维数组的大括号{ }内部,会明确的给出每个一维数组,对每个一维数组进行初始化。例如:
int arr4[3][5]={{1,2},{3,4},{5,6}};
打印出数组的内容,如下图样式:
可以看到上面的二维数组按照行进行初始化,在大括号的内部明确给出了二维数组的每个一维数组,因为一维数组的内容也是用大括号括起来的。所以在二维数组里对每一行进行初始化是遵循一维数组的初始化原则的。
(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}};
上面三个数组得到数组形式会是:
可以看到当数组给出列数却没有给出行数时,系统会根据你大括号里初始化数据的多少,自动计算数组的行数,确定数组是一个什么类型的数组。
4.二维数组的使用
二维数组的访问也是使用下标的形式进行的,二维数组是有行和列的,只要锁定了行和列就能唯一锁定数组中的一个元素。C语言规定:二维数组的行是从0开始的,列也是从0开始的,如下所示:
int arr[3][5]={1,2,3,4,5,2,3,4,5,6,3,4,5,6,7};
上图中,最左侧的灰色数字表示行号,最上面一行的橙色数字表示列号,可以发现下标都是从0开始。比如:行号为2,列号为3的元素,就是6:
#include<stdio.h>
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][3]);
return 0;
}
运行结果:
5.二维数组的输入和输出
上面讲过一维数组的访问,是通过下标进行的,用for循环产生对应的下标。二维数组也是一样的,也是通过下标来访问,只不过二维数组有行和列两个下标,如果要对二维数组进行输入输出的话,就要使用两个for循环,外层循环控制每一行的循环,内层的循环控制每一行里所有元素个数(列数)的循环。比如我们要输入和打印上面的arr数组在屏幕上,行的范围是0~2,列的范围是0~4,用两个for循环产生相应的行和列号:
#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;
}
输入数据后得到的结果:
6.二维数组在内存中的存储
与一维数组一样,如果想知道二维数组在内存中的存储方式,我们也是可以打印出数组所有元素的地址的。代码如下:
#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个字节,所以得到的结论是:二维数组中的每个元素在内存中都是连续存放的。
7.二维数组中对于数组名的理解
在二维数组中,数组名表示什么含义?我们之前讲过一维数组的数组名是表示数组首元素的地址,也就是数组中第一个元素的地址。那二维数组的数组名其实也表示数组首元素的地址,但是这个首元素是指那个呢?这里我们要把二维数组看成是一个一维数组。举个例子:
int arr[3][4]={0};
二维数组其实可以看作是由一维数组构成的数组,也就是把每行的一维数组整体看做是一个元素,则二维数组现在就相当于一个一维数组,数组的首元素就是第一行的一维数组,则数组名就是第一行一维数组的地址,它是一个数组指针。就像上面的arr[3][4]数组,数组名arr表示的是第一行一维数组的地址,它是一个 int(*)[4] 类型的数组指针:即 arr==&arr[0]。
二维数组去掉列下标部分也是数组名,如下:
数组名表示的是数组首元素的地址。则二维数组去掉列下标后的数组名,如上面的arr[0]、arr[1]和arr[2]分别表示二维数组中每行一维数组的首元素地址,即每个一维数组的第一个元素的地址,类型是int*的指针:arr[0]==&arr[0][0]、arr[1]==&arr[1][0]、arr[2]==&arr[2][0]。
所以在二维数组中要区分开上面的两种数组名,不能混淆,尤其是在sizeof中放有关数组名的各种表达式时,要特别区分上面的两种数组名。