一、数组的基本概念
引言: 假设我们要存放一个班55个同学的成绩,并且规定这些成绩都是整数,那我们可以写出以下代码:
int grade1 = 99;
int grade2 = 98;
int grade = 97;
......
我们可以发现,假设我们这样一个一个定义,代码的行数十分的冗余,有着许多的重复语句。那么我们是否有那么一个东西可以像个箱子,把这些数据(成绩)存起来呢?当然是有的,那就是数组。
数组是什么?
数组是一种基本的数据结构,用于存储相同类型的多个元素(int char float 等等)。同时数组将相同类型的多个元素存储在一个连续的内存块中。数组中的每个元素都可以通过索引来访问。
二、数组的创建
1. 一维数组
※一维数组的创建语法
type arrayName[arraySize];
- type 数组
- arrayName 数组名
- arraySize 数字数据个数
- [ ] 下标引用操作符
在C语言中,我们可以这样定义一个一维数组
int grade[55];
如果我们在一开始可以定义数组的大小,编译器则会根据我们输入的值,计算数组的大小,比如下面这样写
int grade[] = {1,2,3,4,5};
此时grade数组的大小为 5 * 4 个字节
我们定义了一个整形、名为grade、长度为55的一维数组。
※一维数组元素的初始化
数组的初始化有三种情况:完全初始化、不完全初始化和错误初始化
//完全初始化
int arr[5] = {1,2,3,4,5};
//不完全初始化
int arr2[6] = {1}; //第一个元素初始化为1,剩余的元素默认初始化为0
//错误的初始化 - 初始化项太多
int arr3[3] = {1, 2, 3, 4};
※一维数组元素的访问
下面我们可以通过索引(或称下标)对数组中的内容进行访问与修改
注意:C语言中数组的第一个元素的下标为0,也就是说,C语言中数组的下标是从0开始的,而最后一个的下标是arraySize - 1
grade[0] = 99; //将数组第一个值赋值为99
grade[1] = 98;//将数组第二个值赋值为98
grade[2] = 97;//将数组三个值赋值为97
grade[4] = 96;//将数组第五个值赋值为96
※一维数组元素的内存储存
我们上面说过数组在内存中是连续存放的,所以我们可以简单的画出数组在内存中的存放结构图。
我们可以在VS上证明数组在内存是连续的空间,在VS输入以下代码:
printf("%p\n",&grade[0]);
printf("%p\n",&grade[1]);
printf("%p\n",&grade[2]);
printf("%p\n",&grade[4]);
四个元素的地址依次为:
000000DB76EFF920
000000DB76EFF924
000000DB76EFF928
000000DB76EFF930
我们知道,int类型的大小为4个字节,同时我们可以观察,一、二、三数据之间相差的值正是四个字节,而第四个数据的地址与第三个数据的地址的值相差8个字节,所以我们可以看出,数组在内存中确实是连续存放的一段数据。
2. 二维数组
※二位数组的创建语法
type arrayName[rows][columns];
- type 二维数组的数据类型
- arrayName 二位数组的数组名
- rows 二维数组的行数
- columns 二维数组的列数
在C语言中,我们可以这样定义一个二维数组
int grade[3][4];
我们定义了一个整形、名为grade、行为3、列为4的二维数组。
与一维数组的不同的是,我们定义二维数组的时候,我们可以不写行数,但是我们必须声明列数,编译器会根据列数来划分数据,例如:
int arr[][4] = {1,2,3,4,5,6,7,8,9,10};
※一维数组元素的初始化
//未完全初始化
int arr1[3][5] = {1,2};
int arr2[3][5] = {0};
//完全初始化
int arr3[3][5] = {1,2,3,4,5, 2,3,4,5,6, 1 3,4,5,6,7};
//按照行初始化
int arr4[3][5] = {{1,2},{3,4},{5,6}};
※二维数组元素的访问
下面我们可以通过索引(或称下标)对数组中的内容进行访问与修改
注意:C语言中二维数组的第一个元素的下标为[0][0]
grade[0][0] = 99; //将数组第一行第一列的值赋值为99
grade[1][0] = 98;//将数组第二行第一列的值赋值为99
grade[2][0] = 97;//将数组第三行第一列的值赋值为99
※二维数组元素的内存储存
二维数组在内存中也是连续存放的,即便它叫二维数组,同样的,我们可以在VS中输入以下代码:
printf("%p\n",&grade[0][0]);
printf("%p\n",&grade[1][0]);
printf("%p\n",&grade[2][0]);
我们可以得到以下结果
000000741CB7F7C8
000000741CB7F7D8
000000741CB7F7E8
我们知道,int类型的大小为4个字节,所以二维数组一行有4个数据,十二个字节,同时我们可以观察,一、二、三数据之间相差的值正是十二个字节,我们可以看出,二维数组在内存中确实是连续存放的一段数据。
3. C99中的变长数组
※变长数组是是什么?
C99引入的变长数组(Variable-Length Array,简称VLA)是一种在运行时确定大小的数组。这意味着你可以在函数内部或者任何代码块中声明一个数组,其大小由运行时的变量值决定。这对于需要动态数组大小的情况非常有用。变长数组不像数组那样子,在程序中就已经用常量或者常量表达式写死了,变长数组可以
※变长数组的语法
type arrayName[n];
- type 数组数据类型
- arrayName 数组名
- n 未规定的数组长度
我们可以在程序中设置n的值
VLA的特点
- 运行时大小: VLA的大小可以在运行时确定,这使得它们非常适合于需要动态数组大小的场景。
- 栈分配: VLA通常在栈上分配,这意味着它们的大小受到栈空间的限制。
- 自动存储期: VLA的生命周期与声明它们的代码块相同,它们在代码块结束时自动释放。
变长数组的实现
因为VS编译器不支持变长数组,所以我们使用GCC编译器在devC++中演示
#include <stdio.h>
int main(){
int n;
scanf("%d",&n);
int arr[n];
printf("创建了长度为%d的整形数组\n", n);
int i = 0;
for(i = 0; i < n; i++){
arr[i] = i + 1;
}
for(i = 0; i < n; i++){
printf("%d\n",arr[i]);
}
return 0;
}
结果如下:
变长数组的注意事项
- VLA的大小必须是一个在运行时已知的正整数。
- VLA的大小不能是负数或零。
- VLA通常在栈上分配,因此它们的大小受到栈空间大小的限制,这可能限制了它们的最大大小。
除去变长数组,我们也可以通过内存函数malloc,realloc等创建或修改大小可选择的数组
三、数组大小与元素个数的计算
计算一个数组的大小我们可以通过sizeof函数计算数组的大小
#include <stdio.h>
int main(){
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%zd\n", sizeof(arr));//求整个数组的大小
return 0;
}
此时数组有10个整形元素,大小应该为4 * 10 个字节
计算一个数组的元素个数我们可以通过sizeof函数计算,将数组的大小除于一个元素的大小就会得到元素个数,如下
#include <stdio.h>
int main(){
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%zd\n", sizeof(arr)/sizeof(arr[0]));//求整个数组的元素个数
return 0;
}
结果如下
四、End
小博主对数组的了解就到这里辣,谢谢大家的浏览,如有错误可以在评论区指出哦,希望对正在学习C语言的友友有帮助!