目录
引言:
1.数组的定义
2.一维数组
2.1创建与初始化
(1)创建
(2)初始化
2.2数组输入和输出
(1)数组下标
(2)输入
(3)输出
2.3 数组的内存存储
(1)内存存储
1.数组名
2.数组元素的存储
2.4 例题
3. 二维数组
3.1创建与初始化
(1)创建
(2)初始化
3.2数组的输入和输出
(1)数组下标
(2)输入
(3) 输出
3.3 二维数组的存储
(1)数组名
(2)二维数组元素的存储
3.4 例题
4.变长数组
4.1概念
4.2用法
结言:
前面贝蒂给大家介绍了选择结构与循环结构,今天呢,贝蒂准备给大家介绍C语言中一个非常重要的结构——数组
数组到底是什么呢,顾名思义就是很多数的集合,那这些数有什么要求呢,当然是有哒~
大致满足下面两个条件:
1. 这些数的类型必须相同。
2. 这些数在内存中必须是连续存储的。
换句话说,数组是在内存中连续存储的具有相同类型的一组数据的集合。
一维数组的定义方式如下:
类型说明符 数组名[常量表达式];
1. 类型说明符就是我们常用的存储类型(char int float double....),当然也可以自定义类型。
2. 数组名就是我们为其取的名字,最好简单易懂,方便别人阅读
3. [] 中的常量值是⽤来指定数组的⼤⼩的,这个数组的⼤⼩是根据实际的需求指定就⾏
贝蒂说:“当然在C99之后,C语言就支持变长数组了,之后贝蒂会为大家详细介绍哒~”
例如:
int arr[5];//表示此时数组arr中有 5 个元素,每个元素都是 int 型变量
有时候,数组在创建的时候,我们需要给定⼀些初始值,这种就称为初始化。那数组如何初始化呢?数组的初始化⼀般使⽤⼤括号,将数据放在⼤括号中。
初始化分为两种:完全初始化和不完全初始化
int arr1[4] = { 1,2,3,4 };//完全初始化
int arr2[4] = { 1,2,3 };//不完全初始化,剩余元素默认为0
char arr3[10] = "hello ";//初始化字符串
int arr4[];//错误初始化
贝蒂说:“如果进行初始化,可以不在[]声明有几个元素,数组会默认初始化几个元素,数组大小就是几个元素,但是不初始化就一定要声明有几个元素哦~,否则就会报错”
C语⾔规定数组是有下标的,下标是从0开始的(而不是1),假设数组有n个元素,最后⼀个元素的下标是n-1,例如:int arr[10]={1,2,3,4,5,6,7,8,9,10}
arr | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
其实和我们平常输入差不多,只是输入对象换成了数组啦~
int main()
{
int arr[10];
int i = 0;
for (i = 0; i < 10; i++)
{
scanf("%d", &arr[i]);//循环像数组中输入元素
}
return 0;
}
输出也是同理,循环输出就好啦~
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;
}
输出结果: 1 2 3 4 5 6 7 8 9 10
C语言规定数组名表示首元素地址,也就是说arr==&arr[0],我们可以通过以下代码来证明:
int main()
{
int arr[2] = { 1,2 };
if (arr == &arr[0])
{
printf("地址相同\n");
}
else
{
printf("地址不相同");
}
return 0;
}
输出结果:地址相同
我们也可以调试起来,找到监视,看看他的内存是否相同。
无论哪种方法都可以证明数组名就是数组首元素地址
我们知道了数组名表示首元素的地址,那么数组每个元素在内存中又是怎样存储的呢,接着跟贝蒂通过这段代码来看看吧~
#include
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;
}
输出结果:
从上述地址(16进制)观察,地址是由⼩到⼤变化的,98,9C,A0......每次的增量是4,而我们又知道一个int的大小为4个字节(byte),就可以很容易推理出数组在内存中存储是连续的,理解到这一点,就能为以后指针的学习打好基础哦~
arr | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
贝蒂说:“因为每次执行程序,系统都会为数组重新分配内存,所以大家实验时候,数值可能不同,但是规律是不变的”
1.求任意十个整数的和与平均数。
思路:我们可以先将十个数输入一个数组中,然后循环求其和,在求平均数
代码参考如下:
int main()
{
int arr[10];
int i = 0;
for (i = 0; i < 10; i++)
{
scanf("%d", &arr[i]);//循环输入
}
int sum = 0;//和
for (i = 0; i < 10; i++)
{
sum += arr[i];
}
float avr = sum / 10.0;
printf("这十个数和为%d\n平均数为%.1f", sum,avr);
return 0;
}
输入:1 2 3 4 5 6 7 8 9 10
输出:这十个数和为55
平均数为5.5
前⾯我们学习的数组被称为⼀维数组,数组的元素都是内置类型的,如果我们把⼀维数组做为数组的元素创建数组,这时候就是⼆维数组,⼆维数组作为数组元素的数组被称为三维数组,⼆维数组以上的数组统称为多维数组。
二维数组定义的一般形式为:
1. 类型说明符 数组名[ 常量表达式][ 常量表达式];
2. 类比一维数组的定义,只不过二维数组第一个常量表达式表示行,第二个常量表达式表示列。
例如:
int arr[5][5];//创建五行五列的二维数组
二维数组的初始化和一维数组的初始化类似,但也有些不同。让贝蒂带大家来看看吧~
int arr1[3][3] = { 1,2 };//不完全初识化
示意图:
1 | 2 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
int arr2[3][3] = { 1,2,3,4,5,6,7,8,9 };//完全初始化
示意图:
1 | 2 | 3 |
4 | 5 | 6 |
7 | 8 | 9 |
int arr3[3][3] = { {1,2},{2,3} };//按照行初始化
示意图:
1 | 2 | 0 |
2 | 3 | 0 |
0 | 0 | 0 |
int arr4[][3] = { 1,2,3 };//省略行
示意图:
1 | 2 | 3 |
int arr5[3][];//错误初始化
int arr6[][];//错误初始化
贝蒂说:“类似一维数组,二维数组在初始化时,可以省略行,但不能省略列哦~,并且如果要省略一定要赋值哦~”
⼆维数组访问和一维数组类似,也是使⽤下标的形式的,⼆维数组是有⾏和列的,只要锁定了⾏和列就能唯⼀锁定数组中的⼀个元素。C语⾔规定,⼆维数组的⾏是从0开始的,列也是从0开始的,例如:int arr[3][3]={1,2,3,4,5,6,7,8,9,10};
示意图:
行/列 | 0 | 1 | 2 |
0 | 1 | 2 | 3 |
1 | 4 | 5 | 6 |
2 | 7 | 8 | 9 |
分别循环输入行和列,思路大致和输入一维数组相同。
int main()
{
int arr[3][3] = {0};
int i = 0;
for (i = 0; i < 3; i++)//输入行
{
int j = 0;
for (j = 0; j < 3; j++)//输入列
{
scanf("%d", &arr[i][j]);
}
}
return 0;
}
输出自然也与一维数组大致相同啦~
int main()
{
int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 3; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");//输出一行后换行
}
return 0;
}
输出:1 2 3
4 5 6
7 8 9
二维数组的数组名也是一个地址,那和一维数组的数组名有何不同呢,其实二维数组的数组名表示的是第一行的地址,但可能大家还是有下面的疑惑:
int main()
{
int arr[3][3] = { 0 };
printf("%p,%p\n", arr,&arr[0][0]);
return 0;
}
输出:0000006A998FF828,0000006A998FF828
为什么明明代表第一行的地址,那么为什么和第一个元素的地址相同呢,其实和字符串的存储一样,如果将所有地址表示出来,太浪费内存,而数组在内存中是连续存储的,所以找到首元素的地址,就能找到一行中所有元素的地址。所以就以首元素地址代表第一行的地址啦。
贝蒂说:“当然,当我们学习完指针,就可以对其加深理解,并且证明了~,所以大家一下子不能理解也是没关系的~”
像⼀维数组⼀样,我们如果想研究⼆维数组在内存中的存储⽅式,我们也是可以打印出数组所有元素的地址的。代码如下:
int main()
{
int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 3; j++)
{
printf("arr[%d][%d]=%p ",i,j, &arr[i][j]);
}
printf("\n");//输出一行后换行
}
return 0;
}
输出如下:
通过对上面地址的观察,我们知道二维数组也是在内存中连续存储的,并且arr[0][2]和arr[1][0]的地址之间也差4个字节(byte),所以内存存储如下:
arr | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
下标 | 0,0 | 0,1 | 0,2 | 1,0 | 1,1 | 1,2 | 2,0 | 2,1 | 2,2 |
输入六个数到2行3列的二维数组arr中, 将二维数组arr1中的数组元素转置,即行列互换,存储到3行2列的二维数组arr2中,输出二维数组arr2中的数组元素。
思路:就是循环输入,在转置(行与列交换),最后输出。
代码如下:
int main()
{
int arr1[2][3];
int arr2[3][2];
int i = 0;
int j = 0;
for (i = 0; i < 2; i++)
{
for (j = 0; j < 3; j++)
{
scanf("%d", & arr1[i][j]);
}
}
for (i = 0; i < 2; i++)
{
for (j = 0; j < 3; j++)
{
arr2[j][i] = arr1[i][j];//转置
}
}
for (i = 0; i < 3; i++)
{
for (j = 0; j < 2; j++)
{
printf("%d ", arr2[i][j]);
}
printf("\n");
}
return 0;
}
在C99标准之前,C语⾔在创建数组的时候,数组⼤⼩的指定只能使⽤常量、常量表达式,或者如果我们初始化数据的话,可以省略数组⼤⼩。
例如:
int arr1[10];
char arr2[4];
int arr3[] = {1,2,3};
但是这样的语法限制,让我们创建数组就不够灵活,有时候数组⼤了浪费空间,有时候数组⼜⼩了不够⽤,所以在C99中给⼀个变⻓数组(variable-length array,简称VLA)的新特性,允许我们可以使⽤变量指定数组⼤⼩。
例如:
int n;
scanf("%d",&n);
int arr1[n];
贝蒂说:“变⻓数组的根本特征,就是数组⻓度只有运⾏时才能确定,所以变⻓数组不能初始化。”
听了贝蒂对数组的讲解,相信“小小数组”已经对你来说不足为虑了~,现在就需要你不断地去复习和练习巩固已学的知识啦~