C语言基础级——一维数组
转载请标明出处!
大家好,我叫Home,是有关于一维数组、二维数组与多维数组的基本知识点的讲解。OK,废话不多说,我们先来了解一维数组。
文章目录
一维数组
数组(array)是由一系列类型相同的元素构成的。数组的引入帮助我们更好地统一管理并处理相同类型的数据,就如同汽车上记录每天的里程数、仓库库存的清单等等。
1.1 声明
数组声明格式为:
[数据类型] [数组名][索引值];
它的作用就是告诉编译器,需要它去创建一个以数组下标([索引值]
)为长度的元素类型([数据类型]),如:
-
int arr[10];
那这样编译器就会按照数组的声明要求在内存空间上,开辟出一段内存空间,且这段内存空间是连续的,例如:
#include<stdio.h>
int main()
{
// 数组声明
int arr[5];
for(int i = 0; i < 5; i++)
{
// 打印5个数组元素的地址
printf("arr[%d] = %p\n", i, &arr[i]);
}
return 0;
}
这里要注意的地方有两点:
- 图中的内存地址是省略简写的,写全了
0x1de0
对应是0x7fff7a9f1de0
。 - arr[索引值]是从0开始的,也就是代表arr的第一个元素。
- arr[0] ~ arr[1] 的地址是间隔四个字节,这是因为arr数组是int类型,所以arr每个内存空间都占四个字节大小。
1.2 初始化
单单是默认有数组声明,一定是不够的。我们要初始化数组,不然我们开辟这段内存空间干啥子呢?
// 数组初始化
int arr[5] = {
10, 100, 1000, 10000, 100000};
这种初始化方法是最常见的和常用的写法,形式上,我们用一对{}
将数据包含起来,每个元素的数据之间以,
(逗号)进行隔开,后面不要忘了加;
(分号)哦。
在多提一嘴,在ANSI C 标准之前的编译器当中(旧标准),可能会报错,前面的版本还没有这种初始化的方式。
同样,我们还可以给全部元素赋相同的值。
// 数组初始化
int arr[0] = {
0};
1.2.1 其它初始化
1.2.1.1 常见初始化—1
- 第一种定义数组索引值要大于初始化个数。
// 数组初始化
int arr[5] = {
10, 100};
arr
数组索引值也就是长度有5
,而初始化只有arr[0] = 10; arr[1] = 100;
剩下的三个arr[2]
~arr[4]
,编译器会默认给未初始化的数组空间用0
来填充。我们来试一试:
1.2.1.1 常见初始化—2
- 第二种定义数组索引值小于所初始化个数。
// 数组初始化
int arr[5] = {
10, 100, 1000, 10000, 100000, 200000, 300000};
arr数组长度为5,而初始化个数要大于5的,这样的方式,在旧版本编译器里会直接进行报错,而新版本(gcc version 9.3.0),会报警告为超过元素初始化的范围值,因为所定义的长度(所开辟的内存空间)并不足以存放初始化值。
注意:
可能同学看到这边编译器不会直接报错误,而且程序还是能够正常的运行,觉得这个问题也还OK。其实,并不是这样的,程序可能会数组越界产生了不可预料的错误,这个到后面,Home
会做一章节内容来详细总结。
1.2.2 数组初始化规范
回归主题,那我们如何避免出现这样的错误,这个时候就是要拥有一个好的编程规范了,有两种方法,第一种是利用宏定义规定数组长度;第二种是利用sizeof
运算符计算出数组长度。两种方式,没有限定,应灵活运用。
引用宏定义
#include<stdio.h>
#define MAX_ARR 5
int main()
{
int arr[MAX_ARR] = {
10, 100, 1000, 10000, 100000};
for(int i = 0; i < MAX_ARR; i++)
{
printf("arr[%d] = %d\n", i, arr[i]);
}
return 0;
}
引用sizeof
利用sizeof
运算符计算操作数的大小,可以直接计算出
数 组 的 长 度 = 数 组 所 占 的 字 节 / 单 个 数 组 所 占 的 字 节 。 数组的长度 = 数组所占的字节 / 单个数组所占的字节。 数组的长度=数组所占的字节/单个数组所占的字节。
计算int arr[5] = {10, 100, 1000, 10000, 100000};
定义的数组arr
为int
类型,我们知道int
类型占4
个字节,我们可以通过sizeof
计算出整个数组占 20
个字节。那么可以计算出数组长度len = 5 (20 / 4)
,这里采用的方式是:
// 计算整个int类型数组所占的字节数
sizeof(arr);
// 计算单个int类型数组所占的字节数
sizeof(arr[0]);
// 也可以是
sizeof(int);
// 或者是
sizeof(*arr);
#include<stdio.h>
int main()
{
// 初始化arr数组
int arr[5] = {
10, 100, 1000, 10000, 100000};
// 计算出arr数组的长度
int len = sizeof(arr) / sizeof(arr[0]);
// 计算并打印整个int类型数组所占的字节数
printf("sizeof(arr) = %ld\n", sizeof(arr));
// 计算并打印单个int类型数组所占的字节数
printf("sizeof(arr[0]) = %ld\n", sizeof(arr[0]));
// 循环遍历数组
for(int i = 0; i < len; i++)
{
printf("arr[%d] = %d\n", i, arr[i]);
}
return 0;
}
1.3 赋值
C语言数组赋值,想要实现对数组的N个元素进行赋值操作,如果是一个int
数组,我们要采用逐个输入的方式。
#include<stdio.h>
int main()
{
int arr[5];
// 逐个元素输入
for(int i = 0; i < 5; i++)
{
scanf("%d", &arr[i]);
}
// 遍历输出元素
for(int i = 0; i < 5; i++)
{
printf("arr[%d] = %d\n", i, arr[i]);
}
return 0;
}
1.4 易错
我们本意上想要实现整体数组进行赋值,我们看下这种方式是否可行?
#include<stdio.h>
int main()
{
int arr_old[5] = {
10, 100, 1000, 10000, 100000};
int arr_new[5];
// 一. 数组名之间赋值,是错误的
arr_new = arr_old;
// 二. 第六个元素赋值, 也是错误的
arr_new[5] = arr_old[5];
// 三. 列表形式直接赋值, 也是错误的
arr_new[5] = {
10, 100, 1000, 10000, 100000};
return 0;
}
- 第一个错误,数组名之间直接赋值的方式,这种方式在C语言当中不允许的。此时的
arr_old
和old_new
是数组名,它代表的是当前数组的首地址,数组名相当于是一个常量。常量之间赋值是无法进行赋值的。 arr
和&arr[0]
它们都是代表着数组的首地址。
// 定义单个变量
int a;
// 取a的地址
&a;
// 定义一个数组
int arr[5];
// arr就是这个数组的首地址
arr;
// &arr[0] 也是代表着数组的首地址
&arr[0];
- 第二个错误,首先分为两部分:
arr_new[5]
数组代表的是第六
个元素,一共是开辟了五
个内存空间,不够存放元素,从而导致数组越界,是非常严重的错误。- 这样的方式相当于给第
六
个元素进行赋值,并不能达到预期效果,应该使用逐个赋值方式。 - 第二个会发现编译并没有报错,而我说这是一个很严重的错误,前后矛盾?
- 这和编译器机制有关系的,本身编译器默认不去检测用户所使用的数组边界,如果每个数组边界都去检测,对于编译器是麻烦的,是会导致效率降低。为此,编译器对程序员的绝对信任,相信你不会犯这样错误。。。所以就有了之后的结果,每次都犯错。。。
- 第三个错误在
C语言
当中是不允许。想要实现数组的赋值,除非在初始化过程中,可以直接进行赋值操作以外,其它要采用逐个赋值的方式。
二维数组
例子:公司每年都会提供给员工一次免费体检机会,体检的其中一个基本项目是身高、体重。
姓名 | 身高(cm) | 体重(kg) |
---|---|---|
小朱 | 156 | 40 |
中朱 | 183 | 50 |
大朱 | 193 | 60 |
在这里,我们就可以使用二维数组保存这里面的数据。
1.1 声明与初始化
- 声明并初始化二维数组,把三名员工的基本数据保存在二维数组当中。
// 初始化二维数组
int arr[3][2] = {
{
156, 40}, {
183, 50}, {
193, 60}};
- 可以把内部嵌套的
{}
去掉。
// 初始化二维数组
int arr[3][2] = {
156, 40, 183, 50, 193, 60};
- 把行索引值去掉,留下列索引值。
// 初始化二维数组
int arr[][2] = {
156, 40, 183, 50, 193, 60};
- 也可以部分进行初始化,默认未初始化赋值的数为
0
。
int arr[3][2] = {
{
156, 40}, {
183, 50}, {
193}};
2.1 内存排布
一维数组当中,我们知道一维数组在内存当中存放是连续的,我们认为二维数组也是连续的。我们按顺序打印每个元素的地址,来看看是否符合猜想的结果。
#include<stdio.h>
int main()
{
int arr[3][2] = {
{
156, 40}, {
183, 50}, {
193, 60}};
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 2; j++)
{
printf("arr[%d][%d] = %p\n", i, j, &arr[i][j]);
}
}
return 0;
}
N维数组
有一维数组,二维数组,那一定会有三维数组、四维数组、五维数组…
// 初始化三维数组
int arr[2][2][2] = {
1, 2, 3, 4, 5, 6, 7, 8};
// 初始化四维数组
int arr[2][2][2][2] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
超过二维的数组,不具有参考价值了,真正的工作当中几乎看不到,有兴趣的同学,可以自行研究~