7. 数组基础:一维数组声明与初始化、数组遍历、数组越界问题

数组这东西,说白了就是一块连续的内存空间,用来存一堆相同类型的数据。我刚学C++那会儿,觉得数组太简单了,不就是个列表嘛。直到后来在项目里踩了越界的坑,才老老实实把这块啃透。

今天咱们就把一维数组的声明、初始化、遍历,还有那个让人头疼的越界问题,一次性说清楚。

7.1 一维数组的声明

声明数组其实就三步:告诉编译器你要存什么类型的数据、数组叫什么名字、要存多少个元素。

// 基本语法
类型 数组名[元素个数];

// 举个例子
int scores[5];          // 存5个int
double prices[10];      // 存10个double
char name[50];          // 存50个char

这里有个关键点:元素个数必须是常量。我见过不少新手这么写:

int n = 5;
int arr[n];  // 这样写,有些编译器能过,但这不是标准C++!

标准C++里,数组大小得是编译期就能确定的常量。如果你确实需要运行时才确定大小的数组,用 std::vector 才是正道。

我的习惯:只要数组大小在写代码时就能确定,我就用原生数组。如果大小不确定,或者需要动态增删,直接上 vector,省心。

7.2 数组的初始化

声明数组的时候,可以顺便给它赋初值。C++提供了好几种初始化方式,我挑常用的说。

7.2.1 完全初始化

int arr[5] = {1, 2, 3, 4, 5};  // 全部赋值

7.2.2 部分初始化

int arr[5] = {1, 2};  // 前两个是1和2,后面三个自动补0

嗯,这里要注意:没给值的元素,编译器会自动初始化为0。这个特性有时候挺有用,比如你想把整个数组清零:

int arr[100] = {0};  // 所有元素都是0

7.2.3 省略大小的初始化

int arr[] = {1, 2, 3, 4, 5};  // 编译器自动算出来大小是5

我个人挺喜欢这种写法,少算一个数,少一个出错的机会。不过要注意,只有在初始化的时候才能这么干。

重要:如果你声明了数组大小,又用初始化列表赋值,列表里的元素个数不能超过数组大小。否则编译器会报错。

7.3 数组的遍历

遍历数组,说白了就是把每个元素挨个儿过一遍。最经典的方式就是用 for 循环。

int arr[5] = {10, 20, 30, 40, 50};

// 传统for循环
for (int i = 0; i < 5; i++) {
    cout << arr[i] << " ";
}

// C++11 范围for循环(推荐)
for (int x : arr) {
    cout << x << " ";
}

范围for循环是C++11引入的,写起来简洁,而且不会越界。我现在的项目里,只要不需要下标,一律用范围for。

但有时候你需要知道当前元素的下标,比如你要修改某个位置的元素,那就得用传统for了:

for (int i = 0; i < 5; i++) {
    arr[i] = arr[i] * 2;  // 每个元素翻倍
}

7.4 数组越界问题

好,接下来这个坑,我估计每个C++程序员都踩过。数组越界,就是访问了数组范围之外的内存。

int arr[3] = {1, 2, 3};
cout << arr[3];  // 越界!arr只有下标0、1、2
arr[5] = 100;     // 越界!写到了别人的地盘上

为什么会这样?C++为了性能,不会在运行时检查数组下标是否合法。你写 arr[5],编译器就直接按地址偏移去访问那块内存了。至于那块内存里有什么,是别的变量还是系统数据,它不管。

我曾经在项目里遇到过:一个同事写了个数组越界,把相邻变量的值给改了。结果程序跑起来一会儿正常一会儿崩溃,查了两天才定位到问题。从那以后,我写循环遍历数组时,都会多看一眼边界条件。

越界的后果,轻则读到垃圾值,重则程序崩溃,甚至产生安全漏洞。所以记住几条铁律:

  • 下标从0开始,到 size-1 结束
  • 循环条件用 < 而不是 <=
  • 不确定大小时,用 vector 代替原生数组

7.5 知识结构图

下面这张图,把一维数组的核心知识点串起来了。你想想看,从声明到初始化,再到遍历和避坑,其实就这几件事。

一维数组 声明 类型 数组名[常量]; int arr[5]; 初始化 完全 / 部分 / 省略大小 int arr[] = {1,2,3}; 遍历 传统for / 范围for for(int x : arr) ⚠ 数组越界:访问下标超出范围 读到垃圾值 程序崩溃 安全漏洞 ✅ 下标从0开始 | 循环用 < | 不确定大小用 vector

7.6 避坑指南

最后,把我这些年踩过的坑总结一下,你写代码的时候多留个心眼:

  • 声明时别忘给大小int arr[]; 这种写法,编译器不知道要分配多少内存,直接报错。
  • 初始化列表别超长int arr[3] = {1,2,3,4}; 元素比数组大,编译不过。
  • 遍历时下标别越界:循环条件写成 i <= size 是经典错误,记住是 i < size
  • 数组名不是指针:虽然数组名可以当指针用,但 sizeof(arr) 返回的是整个数组的字节数,不是指针大小。
一个小技巧:sizeof(arr) / sizeof(arr[0]) 可以算出数组的元素个数。不过这只在数组定义的作用域内有效,传到函数里就不行了。那时候,老老实实把数组长度也传进去。

数组这块,说白了就是「声明-初始化-遍历-防越界」这四步。你写个三五次,自然就熟了。下次咱们聊二维数组,那个更贴近实际项目——比如图像处理、矩阵运算,都离不开它。


公众号:蓝海资料掘金营,微信deep3321