前言:为什么需要数组?

想象一下,你需要存储100个学生的考试成绩。你会创建100个变量吗?score1, score2, score3… 这显然不现实!这时候,数组就派上了用场。数组是C++中最基础且强大的数据结构之一,让我们一起来探索它的奥秘。

什么是数组?

数组是一组相同类型的数据元素的集合,这些元素在内存中连续存储,并通过一个共同的名称和不同的索引来访问。

简单来说,数组就像一排连续编号的储物柜:

数组可视化:一排连续储物柜
储物柜表示内存位置
索引表示位置
locker 0
索引 0
locker 1
索引 1
locker 2
索引 2
locker 3
索引 3
locker 4
索引 4

每个"储物柜"存储一个数据元素,而索引就是它们的编号。

声明和初始化数组

基本语法

在C++中声明数组需要指定三要素:类型、名称和大小:

// 语法:数据类型 数组名[元素个数];
int scores[5]; // 声明一个包含5个整数的数组

初始化数组

数组有多种初始化方式:

// 方式1: 先声明后赋值
int numbers[5];
numbers[0] = 10;
numbers[1] = 20;
// ...

// 方式2: 声明时初始化
int primes[5] = {2, 3, 5, 7, 11};

// 方式3: 省略大小,编译器自动计算
int primes[] = {2, 3, 5, 7, 11}; // 自动创建大小为5的数组

// 方式4: 部分初始化,其余为0
int values[5] = {1, 2}; // [1, 2, 0, 0, 0]

访问数组元素

数组元素通过索引访问,索引从0开始

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

cout << numbers[0]; // 输出第一个元素: 10
cout << numbers[2]; // 输出第三个元素: 30

// 修改元素
numbers[1] = 25; // 第二个元素变为25

数组的内存布局

理解数组的内存布局非常重要。数组元素在内存中是连续存储的:

数组内存布局
地址 1000
numbers 0
地址 1004
numbers 1
地址 1008
numbers 2
地址 1012
numbers 3
地址 1016
numbers 4

假设一个int占4字节,数组从内存地址1000开始,那么:

  • numbers[0] 在地址 1000
  • numbers[1] 在地址 1004
  • numbers[2] 在地址 1008
  • 以此类推…

这种连续存储特性使得数组访问非常高效。

遍历数组

遍历数组是常见操作,通常使用for循环:

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

// 方法1: 使用常规for循环
for (int i = 0; i < 5; i++) {
    cout << numbers[i] << " ";
}

// 方法2: 使用范围for循环(C++11)
for (int num : numbers) {
    cout << num << " ";
}

数组的注意事项

1. 数组越界

非常重要:C++不会检查数组索引是否有效:

int arr[3] = {1, 2, 3};
cout << arr[5]; // 不可预测的行为!可能崩溃或输出垃圾值

访问越界元素会导致未定义行为,可能导致程序崩溃或安全漏洞。

2. 数组大小固定

传统数组的大小在创建时就确定了,不能动态改变:

int arr[5]; // 永远只能存放5个元素

3. 数组名是指向首元素的指针

数组名实际上是指向数组第一个元素的指针:

int arr[3] = {1, 2, 3};
int* ptr = arr; // 等价于 int* ptr = &arr[0]

cout << *ptr; // 输出1

数组与函数

数组可以作为参数传递给函数,但需要注意一些细节:

// 函数接收数组参数
void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
}

int main() {
    int numbers[] = {1, 2, 3, 4, 5};
    printArray(numbers, 5); // 传递数组和大小
    return 0;
}

注意:数组作为参数传递时,会退化为指针,函数内部无法知道数组的实际大小,所以需要额外传递大小参数。

实战示例:统计学生成绩

让我们用一个完整示例展示数组的实际应用:

#include <iostream>
using namespace std;

int main() {
    const int NUM_STUDENTS = 5;
    int scores[NUM_STUDENTS];
    int total = 0;
    
    // 输入成绩
    cout << "请输入" << NUM_STUDENTS << "个学生的成绩:\n";
    for (int i = 0; i < NUM_STUDENTS; i++) {
        cout << "学生 " << i+1 << ": ";
        cin >> scores[i];
        total += scores[i];
    }
    
    // 计算平均分
    double average = static_cast<double>(total) / NUM_STUDENTS;
    
    // 输出结果
    cout << "\n平均分: " << average << endl;
    cout << "所有成绩: ";
    for (int i = 0; i < NUM_STUDENTS; i++) {
        cout << scores[i] << " ";
    }
    
    return 0;
}

数组的局限性及替代方案

虽然数组很重要,但也有局限性:

  • 大小固定
  • 缺乏边界检查
  • 不支持动态调整

在现代C++中,可以考虑使用:

  • std::array (C++11):固定大小,更安全
  • std::vector:动态大小,最常用

但这些高级容器都基于数组的基本概念,所以理解数组仍然至关重要。

总结

一维数组是C++编程的基础构建块:

  • 存储相同类型的元素集合
  • 元素在内存中连续存储
  • 通过索引访问元素(从0开始)
  • 高效但需要小心越界问题
  • 作为参数传递给函数时会退化为指针

掌握数组是学习更复杂数据结构的第一步。希望这篇指南帮助你扎实地理解C++一维数组!

更多推荐