06- 数组的基础知识详细讲解
一、基本概念
一次性定义多个相同类型的变量,并且给它们分配一片连续的内存。
int arr[5];
1.1 初始化
只有在定义的时候赋值,才可以称为初始化。数组只有在初始化的时候才可以统一赋值。
以下是一些示例规则:
int arr[5] = {1,2,3,4,5}; // 定义并初始化数组
int arr[5] = {1,2,3}; // 可以,不完全初始化
int arr[5] = {1,2,3,4,5,6,7,8,9}; // 错误(但可以用),越界初始化,越界部分将被编译器舍弃
int arr[] = {1,2,3,4,5,6,7,8,9}; // 可以,未指定大小,但有初始化,大小为9
int arr[]; // 错误,没有指定大小也没有初始化,内存大小无法确定
注意:
- 数组在定义时必须确定其大小。
- 中括号
[]
必须有数组的大小,如果没有则必须初始化。
1.2 数组元素引用
存储模式:一片连续的内存,按照数据的类型进行分割成若干个大小相同的格子。
元素的下标与偏移量:以数组开头为基础的偏移量(数据类型大小)。
int arr[5] = {1,2,3,4,5}; // 定义并初始化数组
printf("arr[0]:%d\n", arr[0]); // 输出第一个元素
arr[0] = 99; // 把数组的第1个元素(偏移量为0)修改为99
printf("arr[0]:%d\n", arr[0]); // 输出修改后的第一个元素
arr[5] = 250; // "错误" 越界访问,可能造成非法访问
printf("arr[5]:%d\n", arr[5]); // 越界访问的输出
arr = {9,8,7,6,5,4}; // 错误,整体赋值只允许在初始化中
arr = 100; // 错误,数组不能整体赋值为一个值
printf("sizeof(arr):%ld\n", sizeof(arr)); // 输出数组的大小
int len = sizeof(arr) / sizeof(int); // 求数组元素的个数
for (size_t i = 0; i < len; i++) {
printf("arr[%ld]:%d\n", i, arr[i]); // 输出每个元素
}
说明:
sizeof(arr)
:获取数组占用的内存大小(字节数)。sizeof(int)
:获取单个元素的大小(字节数)。len
:计算数组元素的个数。
注意事项:
- 数组的下标从0开始。
- 越界访问数组会导致未定义行为,可能导致程序崩溃或错误结果。
- 数组整体赋值只能在初始化时进行,不能在定义之后进行整体赋值。
二、字符数组
概念: 专门用来存放字符类型数据的数组,称为字符数组。
2.1 初始化+引用
- 定义一个字符类型的数组并把’H’,‘e’,‘l’,‘l’,'o’一个一个存进去:
char ch1[5] = {'H', 'e', 'l', 'l', 'o'};
- 定义一个字符型的数组,并把"Hello"字符串存放到数组中,因此该数组为字符串数组:
char ch2[6] = {"Hello"};
- 与ch2一样,大括号可以省略:
char ch3[6] = "Hello";
- 修改字符数组中的某个元素:
ch3[1] = 'E'; // 可以,把数组中第二个元素‘e’修改为‘E’
- 整体赋值只允许在初始化时进行:
ch3 = "Even"; // 不可以,只有在初始化的时候才能整体赋值
- 输出字符数组:
printf("%s\n", ch1); // 在访问ch1的时候并没有发现结束符,因此很有可能会把ch2的内容一并输出
注意:
- 字符数组的结束符:
ch1
为字符数组,但它没有结束符,因此在打印输出的时候应该避免使用%s
进行输出,否则可能会造成越界访问。字符串在C语言中以\0
作为结束符,确保字符数组输出安全。
char ch1[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; // 加上结束符
printf("%s\n", ch1); // 现在可以安全地使用 %s 输出
2.2 示例代码
#include <stdio.h>
int main() {
// 定义并初始化字符数组
char ch1[5] = {'H', 'e', 'l', 'l', 'o'};
char ch2[6] = {"Hello"};
char ch3[6] = "Hello";
// 修改字符数组中的某个元素
ch3[1] = 'E';
// 正确的打印方式
char ch1_with_terminator[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
printf("ch1 with terminator: %s\n", ch1_with_terminator);
printf("ch2: %s\n", ch2);
printf("ch3: %s\n", ch3);
// 错误的打印方式
printf("ch1 without terminator: %s\n", ch1); // 可能导致越界访问
return 0;
}
总结:
- 字符数组 用来存放字符数据。
- 初始化 时可以逐个字符赋值或使用字符串直接赋值。
- 修改 数组元素可以通过索引访问。
- 整体赋值 只能在初始化时进行。
- 结束符
\0
确保字符串的安全输出。
三、数组小细节
3.1 数组未初始化
结论: 当定义数组但未初始化时,数组中的元素将包含内存中的随机值(内存中原有的内容)。
示例代码:
#include <stdio.h>
int main() {
int arr[5];
// 输出未初始化的数组元素
for (int i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
return 0;
}
输出: 可能会显示随机值,因为数组未初始化时,包含的是内存中的原有内容。
3.2 部分初始化
结论: 部分初始化时,已初始化部分是已知值,未初始化的部分则为0。
示例代码:
#include <stdio.h>
int main() {
int arr[5] = {1, 2, 3}; // 部分初始化,只初始化前三个元素
// 输出部分初始化的数组元素
for (int i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
return 0;
}
输出:
arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[3] = 0
arr[4] = 0
未初始化的元素自动设为0。
总结:
- 未初始化数组: 包含随机值,来源于内存中的原有内容。
- 部分初始化数组: 已初始化部分设定为指定值,未初始化部分自动设为0。