C++ 数组

一、数组的本质:连续存储的同类型数据集合

在 C++ 中,数组是一种内置的数据结构,用于存储固定大小的同类型元素,这些元素在内存中连续排列。这种存储特性使得数组具有以下关键特点:

  • 随机访问高效:通过下标(索引)可直接定位元素,时间复杂度为 O(1)。
  • 内存占用固定:声明时需指定大小,一经创建长度不可改变。

1.1 数组的声明与初始化

语法格式
数据类型 数组名[元素个数];
  • 示例
    int scores[5];       // 声明一个包含5个整数的数组,元素默认值未初始化(值为随机数)
    double prices[3] = {10.5, 20.0, 30.8};  // 初始化数组
    char vowels[] = {'a', 'e', 'i', 'o', 'u'};  // 省略大小,编译器自动计算(元素个数为5)
    
特殊初始化场景
  • 全零初始化
    int nums[10] = {0};  // 所有元素初始化为0
    
  • 部分初始化:未显式初始化的元素自动填充为 0(内置类型)或默认值(类类型)。

1.2 数组的内存布局

假设定义 int arr[3] = {1, 2, 3};,其在内存中的存储如下:

内存地址(假设从 0x7fff 开始) 存储值
0x7fff 1
0x7fff + 4(int 占 4 字节) 2
0x7fff + 8 3
  • 关键结论
    • 数组名在多数情况下会隐式转换为指向首元素的指针(&arr[0])。
    • 下标访问等价于指针偏移,如 arr[i] 等价于 *(arr + i)

二、数组的核心操作:遍历、访问与指针关联

2.1 数组遍历的三种方式

方式 1:传统 for 循环
int arr[5] = {1, 3, 5, 7, 9};
for (int i = 0; i < 5; i++) {
    cout << arr[i] << " ";  // 输出:1 3 5 7 9
}
方式 2:范围 for 循环(C++11 特性)
for (int num : arr) {
    cout << num << " ";  // 输出同上
}
方式 3:指针遍历
int *ptr = arr;
for (int i = 0; i < 5; i++) {
    cout << *(ptr + i) << " ";  // 输出同上
}

2.2 数组与指针的区别与联系

  • 本质区别
    • 数组是对象,有固定大小和内存地址。
    • 指针是变量,存储内存地址,可指向任意同类型数据。
  • 容易混淆的场景
    void func(int arr[10]) {  // 等价于 void func(int* arr)
        cout << sizeof(arr) << endl;  // 输出4/8(指针大小),而非10*4=40
    }
    

    结论:函数参数中的数组会退化为指针,无法通过 sizeof 获得原始数组大小。

三、多维数组:从一维到二维及以上

3.1 二维数组的声明与初始化

语法格式
数据类型 数组名[行数][列数];
  • 示例
    int matrix[2][3] = {
        {1, 2, 3},  // 第0行
        {4, 5, 6}   // 第1行
    };
    
内存存储方式

二维数组在内存中按行优先顺序连续存储,等价于一维数组的嵌套。例如 matrix 的存储顺序为:1→2→3→4→5→6

3.2 多维数组的指针表示

  • 二维数组名 matrix 是指向一维数组(含 3 个 int)的指针,类型为 int (*)[3]
  • 访问元素 matrix[i][j] 等价于 *(*(matrix + i) + j)

四、数组的常见应用场景与注意事项

4.1 典型应用场景

  1. 数据缓存:如缓冲区存储网络数据。
  2. 数学计算:矩阵运算、向量操作等。
  3. 字符串处理:C 风格字符串(以\0结尾的字符数组)。

4.2 易犯错误与规避

  1. 下标越界:访问超过数组长度的索引(如 arr[5] 对长度为 5 的数组),会导致未定义行为。

    • 规避:使用 sizeof(arr)/sizeof(arr[0]) 获取数组长度(仅适用于原始数组,非指针)。
  2. 数组传参退化问题

    void printArray(int arr[], int size) {  // 显式传递size参数
        for (int i = 0; i < size; i++) { ... }
    }
    int main() {
        int arr[3] = {1,2,3};
        printArray(arr, sizeof(arr)/sizeof(int));  // 传递正确长度
    }
    
  3. 与 vector 的对比

    • 数组:固定大小,性能高,适合已知数据量的场景。
    • std::vector:动态扩容,安全性高,推荐优先使用(需包含头文件)。

五、实战案例:使用数组实现简单统计功能

需求:输入 10 个学生成绩,统计及格率(≥60 分)。

#include 
using namespace std;

int main() {
    int scores[10];
    int passCount = 0;

    // 输入成绩
    cout << "请输入10个学生成绩:" << endl;
    for (int i = 0; i < 10; i++) {
        cin >> scores[i];
        if (scores[i] >= 60) passCount++;
    }

    // 计算及格率
    double passRate = static_cast(passCount) / 10 * 100;
    cout << "及格率:" << passRate << "%" << endl;

    return 0;
}

六、总结:数组的优缺点与现代 C++ 的选择

  • 优点
    • 内存连续,访问高效。
    • 底层实现简单,适合性能敏感场景。
  • 缺点
    • 大小固定,灵活性差。
    • 缺乏边界检查,安全性低。
  • 现代开发建议
    • 优先使用 std::vector 或 std::array(C++11 提供,封装了数组,支持迭代器和大小查询)。
    • 仅在需要与 C 语言接口兼容或极致性能优化时使用原始数组。

通过本文,你已掌握 C++ 数组的核心概念、操作技巧及实战应用。在实际开发中,需根据场景选择合适的数据结构,兼顾性能与安全性。

你可能感兴趣的:(C++ 数组)