《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介
暂时无法在飞书文档外展示此内容
1、引入
变量的出现使得我们可以存放单个的数据,那假设我们有⼀组数据,比如:某个班级的数学成绩有 30 个数据,我们就需要创建 30 个变量去存储码?如果是一个年段上千个数据,会不会太复杂了?
这时候 C 语⾔中给了⼀个数组的概念,可以让我们创建⼀块连续的空间来存放⼀组数据。
2、数组概念
数组是⼀组相同类型元素的集合
。
固定大小的
相同类型的
元素的顺序集合
数组的定义并不是声明一个个单独的变量,比如 runoob0、runoob1、...、runoob99
,而是声明一个数组变量,使用 runoob[0]、runoob[1]、...、runoob[99]
来代表一个个单独的变量。
我们把这样的一组数据的集合称为数组(Array)
,它所包含的每一个数据叫做数组元素(Element)
,所包含的数据的个数称为数组长度
。
3、数组声明
基本语法:
type arrayName [index]
type 为数据类型, arrayName 为数组名称,index 为下标
如下:
数据类型 数组名 [下标]
这个数组也叫做一维数组。数组在创建
的时候可以指定数组的大小和数组的元素类型。
下标
必须是一个大于零的整数常量
;数据类型
可以是任意有效的 C 数据类型,可以是 char、short、int、float 等,也可以⾃定义的类型;数组名
根据实际情况,起的有意义就⾏;
例如,要声明一个类型为 int 的包含 5 个元素的数组 balance
,声明语句如下:
int balance[5];
//现在 balance 是一个可用的数组,可以容纳 5 个类型为 int 的数字。
4、数组初始化
根据使用的用途不同,对数组赋值可以在:
- 先定义数组再给数组赋值;
- 也可以在定义数组的同时初始化赋值,称为初始化数组。
使用符号:
数组元素的值使用大括号,将数据放在大括号{ }
中,各个值之间以,
分隔。
简单举例:
把同一个类型为 int 的 5 个值 1,2,3,4,5
,存入 a 数组里,如下所示:
int a[5] = {1,2,3,4,5};
注意:大括号 { } 之间的值的数目不能大于我们在数组声明时在方括号 [ ] 中指定的元素数目。
底下这是错误的!
int a[5] = {1,2,3,4,5,6};
数组的初始化注意总结:
(1) 可以逐个初始化数组,也可以使用一个初始化语句,如下所示:
double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
与底下写法是等价
的:
double balance[5];
balance[0] = 1000.0;
balance[1] = 2.0;
balance[2] = 3.4;
balance[3] = 7.0;
balance[4] = 50.0;
上述的语句把数组中第五个元素的值赋为 50.0。所有的数组都是以 0 作为它们第一个元素的索引,数组的最后一个索引是数组的总大小减去 1。
以下是上面数组的图形表示:
(2) 只能给元素逐个赋值,不能给数组整体赋值。例如给 10 个元素全部赋值为 1,只能写作:
int a[10] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
而不能写作:
int a[10] = 1;//错误写法
(3) 如只给部分元素赋值。当{ }
中值的个数少于元素个数时,只给前面部分元素赋值。
例如:
int a[10] = {12,19,22,993,344};
表示只给 a[0]~a[4] 5 个元素赋值,而后面 5 个元素自动初始化为 0。
当赋值的元素少于数组总体元素
的时候,剩余的元素自动初始化为 0
:
- 对于 short、int、long,就是
整数 0
; - 对于 char,就是
字符 '\0'
; - 对于 float、double,就是
小数 0.0
。
我们可以通过下面的形式将数组的所有元素初始化为 0:
int nums[10] = {0};
char str[10] = {0};
float scores[10] = {0.0};
由于剩余的元素会自动初始化为 0,所以只需要给第 0 个元素赋值为 0 即可。
(4) 如给全部元素赋值,那么在定义数组时可以不给出数组长度。例如:
int a[] = {1, 2, 3, 4, 5};
等价于
int a[5] = {1, 2, 3, 4, 5};
也就是如果省略
掉了数组的大小,数组的大小则为初始化时元素的个数。
总结小举例:
//完全初始化
int arr[5] = {1,2,3,4,5};
//不完全初始化
//第⼀个元素初始化为1,剩余的元素默认初始化为0
int arr2[6] = {1};
//错误的初始化 - 初始化项太多
int arr3[3] = {1, 2, 3, 4};
//错误的初始化 - 初始化不是使用()
int arr4[] = (1,2,3,4);
5、数组下标
下标是从 0 开始的,假设数组有 n 个元素,最后⼀个元素的下标是 n-1,下标就相当于数组元素的编号
。
如下:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
可以看出:
下标从 0 开始,数组有 10 个元素,最后⼀个元素的下标是 9。
数组的访问提供了⼀个操作符 []
,这个操作符叫:下标引用操作符
。
比如我们访问下标为 7 的元素,我们就可以使用 arr[7] ,想要访问下标是 3 的元素,就可以使用 arr[3] 。
6、访问数组元素
存放在数组的值
被称为数组的元素(Element)
。
数组元素可以通过数组名称加索引(下标)进行访问。例如:
double salary = balance[9];
上面的语句将把数组中第 10 个元素的值赋给 salary 变量
。
在学习过程中,我们经常会使用循环结构将数据放入数组中(也就是为数组元素逐个赋值),然后再使用循环结构输出(也就是依次读取数组元素的值),下面我们就来演示一下如何将 0~4 这十个数字放入数组中:
#include <stdio.h>
int main()
{
int nums[5];
int i;
//将 0~4放入数组中
for (i=0; i<5; i++) {
nums[i] = i;
}
//依次输出数组元素
for (i=0; i<5; i++) {
printf("%d ", nums[i]);
}
return 0;
}
运行结果:
0 1 2 3 4
详细解释:
这里的 0、1、2、3、4
就是数组下标
,nums[0]、nums[1]、nums[2]、nums[3] 、nums[4]
就是数组元素
。
而且:
变量 i 既是数组下标,也是循环条件;将数组下标作为循环条件,达到最后一个元素时就结束循环。数组 nums 的最大下标是 4,也就是不能超过 5,所以我们规定循环的条件是 i<5,一旦 i 达到 5 就得结束循环。
7、数组的类型
去掉数组名留下的就是数组的类型。
int arr1[10];
int arr2[12];
char ch[5];
arr1 数组的类型是 int [10] ;
arr2 数组的类型是 int [12] ;
ch 数组的类型是 char [5] ;
8、数组的输入
根据某些需求,可以给数组输入想要的数据,如下:
注意:代码中 arr[i] 相当于一个变量
,所以 scanf 参数是 & + arr[i]
,别复合了就懵逼了亲。
#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++)
{
scanf("%d", &arr[i]);
}
for (i=0; i<10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
运行结果:
2 1 4 3 6 5 8 7 0 9
2 1 4 3 6 5 8 7 0 9
9、获取数组长度
数组长度可以使用 sizeof 运算符
来获取数组的长度
。
例如:
int numbers[] = {1, 2, 3, 4, 5};
int length = sizeof(numbers) / sizeof(numbers[0]);
实例:
#include <stdio.h>
int main() {
int array[] = {1, 2, 3, 4, 5};
int length = sizeof(array) / sizeof(array[0]);
printf("数组长度为: %d\n", length);
return 0;
}
输出结果:
数组长度为: 5
10、数组内存
所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。
数组是一个整体,它的内存是连续的;也就是说,数组元素之间是相互挨着的,彼此之间没有一点点缝隙。
如图:
打印数组元素的地址:
#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;
}
输出结果:
&arr[0] = 01558ED0
&arr[1] = 01558ED4
&arr[2] = 01558ED8
&arr[3] = 01558EDC
&arr[4] = 01558EE0
&arr[5] = 01558EE4
&arr[6] = 01558EE8
&arr[7] = 01558EEC
&arr[8] = 01558EF0
&arr[9] = 01558EF4
从输出的结果分析:
数组随着下标的增长,地址是由小到大变化的,并且我们发现每两个相邻的元素之间相差 4(因为⼀个整型是 4 个字节)。
得出结论:
数组在内存中是连续存放的,随着数组下标的增长,地址是由低到高变化的。这就为后期我们使用指针访问数组奠定了基础。
因此:
数组内存是连续的
这一点很重要,特别强调。
连续的内存为指针操作(通过指针来访问数组元素)和内存处理(整块内存的复制、写入等)提供了便利,这使得数组可以作为缓存(临时存储数据的一块内存)使用。
大家如果可能不理解是什么意思,等后边学了指针和内存自然就明白了。
11、初学注意项
(1)数组中每个元素的数据类型必须相同
,对于int a[4];
,每个元素都必须为 int。
(2)数组长度 length 是整数或者常量表达式
,例如 10、20*4
等,这样在所有编译器下都能运行通过;如果 length 中包含了变量,例如 n、4*m
等,编译时就会报错。
(3)访问数组元素时,下标的取值范围
为 0 ≤ index < length
,过大或过小都会越界,导致数组溢出,发生不可预测的情况。
《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介
每日一更!
公众号、优快云等博客:小菜狗编程笔记
谢谢点赞关注哈!目前在飞书持续优化更新~
日更较慢有需要完整笔记请私我,C/C++/数据结构-算法/单片机51-STM32-GD32-ESP32/嵌入式/Linux操作系统/uboot/Linux内核-驱动-应用/硬件入门-PCB-layout/Python/后期小程序和机器学习!