当前位置: 首页 > news >正文

C++ 数组:基础与进阶全解析

数组是 C++ 中最基础也最常用的数据结构之一,它是相同类型元素的有序集合,通过连续的内存空间存储,支持快速随机访问。本文将从数组的基本概念、声明使用、内存特性到高级应用,全面解析 C++ 数组的特性与实战技巧。

一、数组的基本概念

1.1 定义与本质

数组(Array)是一种固定大小的序列容器,用于存储相同数据类型的元素。其核心特性包括:

  • 同质性:所有元素类型必须相同(如 intdouble 或自定义类型)。
  • 连续性:元素在内存中连续存储,地址依次递增。
  • 固定大小:数组一旦声明,大小不可修改(编译期确定)。
  • 随机访问:通过下标(索引)可直接访问任意元素,时间复杂度 O (1)。

示意图int arr[5] = {1, 2, 3, 4, 5} 在内存中的存储(假设起始地址为 0x1000):

plaintext

地址:0x1000  0x1004  0x1008  0x100C  0x1010
元素:1       2       3       4       5
下标:0       1       2       3       4

1.2 与其他容器的区别

容器类型大小特性内存连续性随机访问动态扩容
数组(Array)固定(编译期)连续支持不支持
std::vector动态(运行期)连续支持支持
std::list动态不连续不支持支持

选择建议

  • 需固定大小、追求极致性能时用数组。
  • 需动态调整大小、频繁增删元素时用 vector

二、一维数组的声明与初始化

2.1 声明方式

数组声明的基本语法:数据类型 数组名[元素个数];

cpp

运行

#include <iostream>
using namespace std;int main() {// 1. 声明时指定大小(元素个数必须是常量表达式)int arr1[5];  // 大小为5的int数组,元素默认初始化(局部变量为随机值)// 2. 声明并初始化(部分初始化,未指定的元素为0)int arr2[5] = {1, 2, 3};  // 等价于 {1,2,3,0,0}// 3. 声明时省略大小(由初始化列表长度决定)int arr3[] = {1, 2, 3, 4};  // 大小为4// 4. C++11 列表初始化(可省略等号)int arr4[]{1, 2, 3, 4, 5};  // 大小为5return 0;
}

注意:数组大小必须是编译期常量(如 5const int n=10),不能是变量(C99 支持变长数组,但 C++ 标准不支持)。

2.2 数组的访问与遍历

通过下标运算符 [] 访问数组元素(下标从 0 开始),遍历可使用循环或范围 for 循环(C++11)。

cpp

运行

int main() {int arr[] = {10, 20, 30, 40, 50};int n = sizeof(arr) / sizeof(arr[0]);  // 计算数组长度(通用方法)// 1. 下标访问cout << "arr[0] = " << arr[0] << endl;  // 10arr[2] = 300;  // 修改元素cout << "arr[2] = " << arr[2] << endl;  // 300// 2. 普通for循环遍历cout << "普通循环遍历:";for (int i = 0; i < n; ++i) {cout << arr[i] << " ";}// 输出:10 20 300 40 50 // 3. 范围for循环遍历(C++11,适合只读或修改元素)cout << "\n范围for循环:";for (int num : arr) {cout << num << " ";}// 输出:10 20 300 40 50 return 0;
}

计算数组长度sizeof(arr) / sizeof(arr[0]) 是通用方法,但仅对数组名有效(对指针无效)。

三、多维数组

C++ 支持多维数组(如二维、三维),本质上是数组的数组(内存仍为连续存储)。

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

cpp

运行

int main() {// 1. 声明3行4列的二维数组int matrix1[3][4];  // 未初始化,元素为随机值// 2. 初始化(按行初始化)int matrix2[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}};// 3. 部分初始化(未指定的元素为0)int matrix3[3][4] = {{1}, {5,6}, {9}};// 4. 省略第一维大小(由初始化列表行数决定)int matrix4[][4] = {{1,2}, {3,4}, {5,6}};  // 3行4列return 0;
}

3.2 二维数组的访问与遍历

通过双重下标 arr[i][j] 访问第 i 行第 j 列的元素,遍历需嵌套循环。

cpp

运行

int main() {int matrix[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}};int rows = sizeof(matrix) / sizeof(matrix[0]);  // 行数:3int cols = sizeof(matrix[0]) / sizeof(matrix[0][0]);  // 列数:4// 访问元素cout << "matrix[1][2] = " << matrix[1][2] << endl;  // 7// 遍历二维数组cout << "二维数组遍历:" << endl;for (int i = 0; i < rows; ++i) {for (int j = 0; j < cols; ++j) {cout << matrix[i][j] << "\t";}cout << endl;}return 0;
}

内存布局:二维数组在内存中按行优先存储(连续的一维空间),例如 matrix[3][4] 的元素顺序为:matrix[0][0], matrix[0][1], ..., matrix[0][3], matrix[1][0], ..., matrix[2][3]

四、数组与指针的关系

在 C++ 中,数组名通常会隐式转换为指向首元素的指针,这是数组操作的核心特性之一。

4.1 数组名与指针的转换

cpp

运行

int main() {int arr[] = {1, 2, 3, 4, 5};int* p = arr;  // 数组名隐式转换为指向首元素的指针(等价于 &arr[0])cout << "arr = " << arr << endl;       // 数组首地址(如 0x7fff5fbff7c0)cout << "&arr[0] = " << &arr[0] << endl;  // 与 arr 相同cout << "p = " << p << endl;           // 与 arr 相同// 通过指针访问元素(等价于数组下标访问)cout << "p[0] = " << p[0] << endl;  // 1(等价于 *p)cout << "p[2] = " << p[2] << endl;  // 3(等价于 *(p+2))return 0;
}

关键结论arr[i] 等价于 *(arr + i),指针的算术运算与元素类型相关(p+1 指向 next 元素,而非 next 字节)。

4.2 数组作为函数参数

数组作为函数参数时,会退化为指针(丢失大小信息),因此需额外传递数组长度。

cpp

运行

// 错误示例:函数内无法通过 sizeof 获取数组真实长度
void printArray1(int arr[]) {int n = sizeof(arr) / sizeof(arr[0]);  // 错误!arr 是指针,sizeof(arr)=8(64位系统)for (int i = 0; i < n; ++i) {cout << arr[i] << " ";}
}// 正确示例:显式传递数组长度
void printArray2(int arr[], int n) {for (int i = 0; i < n; ++i) {cout << arr[i] << " ";}
}int main() {int arr[] = {1, 2, 3, 4, 5};int n = sizeof(arr) / sizeof(arr[0]);printArray1(arr);  // 行为未定义(可能输出乱码)printArray2(arr, n);  // 正确输出:1 2 3 4 5 return 0;
}

传递多维数组:需指定除第一维外的所有维度大小:

cpp

运行

// 二维数组作为参数(必须指定列数)
void printMatrix(int matrix[][4], int rows) {for (int i = 0; i < rows; ++i) {for (int j = 0; j < 4; ++j) {cout << matrix[i][j] << " ";}cout << endl;}
}

五、数组的常见操作与算法

5.1 查找元素

  • 线性查找:遍历数组逐一比较,时间复杂度 O (n)。
  • 二分查找:适用于有序数组,时间复杂度 O (log n)(需先排序)。

cpp

运行

// 线性查找
int linearSearch(int arr[], int n, int target) {for (int i = 0; i < n; ++i) {if (arr[i] == target) {return i;  // 返回索引}}return -1;  // 未找到
}// 二分查找(需数组有序)
int binarySearch(int arr[], int n, int target) {int left = 0, right = n - 1;while (left <= right) {int mid = left + (right - left) / 2;if (arr[mid] == target) return mid;else if (arr[mid] < target) left = mid + 1;else right = mid - 1;}return -1;
}

5.2 排序算法

数组排序是最常用的操作之一,C++ 标准库提供 std::sort(基于快速排序的优化版本)。

cpp

运行

#include <algorithm>  // 包含 std::sortint main() {int arr[] = {3, 1, 4, 1, 5, 9};int n = sizeof(arr) / sizeof(arr[0]);// 升序排序(默认)sort(arr, arr + n);  // 排序范围 [arr, arr+n)// 输出:1 1 3 4 5 9 // 降序排序(使用 greater 比较器)sort(arr, arr + n, greater<int>());// 输出:9 5 4 3 1 1 return 0;
}

5.3 数组逆置

cpp

运行

void reverseArray(int arr[], int n) {int left = 0, right = n - 1;while (left < right) {// 交换元素int temp = arr[left];arr[left] = arr[right];arr[right] = temp;left++;right--;}
}

六、数组的局限性与替代方案

6.1 局限性

  1. 大小固定:编译期确定大小,无法动态调整(如需动态扩容,需手动管理内存)。
  2. 传递不便:作为函数参数时退化为指针,丢失大小信息。
  3. 缺乏边界检查:访问越界(如下标为负数或超出范围)时,行为未定义(可能崩溃或产生垃圾值)。

6.2 替代方案:std::array 与 std::vector

  • std::array(C++11):封装固定大小数组,保留数组性能的同时提供容器接口(如 size()begin()/end())。

    cpp

    运行

    #include <array>  // 需包含头文件int main() {array<int, 5> arr = {1, 2, 3, 4, 5};  // 大小为5的arraycout << "大小:" << arr.size() << endl;  // 5for (int num : arr) {  // 范围for循环cout << num << " ";}return 0;
    }
    
  • std::vector:动态数组,支持自动扩容,是最常用的数组替代方案。

    cpp

    运行

    #include <vector>int main() {vector<int> vec = {1, 2, 3};  // 初始大小3vec.push_back(4);  // 动态添加元素(大小变为4)cout << "大小:" << vec.size() << endl;  // 4return 0;
    }
    

选择建议

  • 大小固定且需高性能 → std::array(比原生数组更安全)。
  • 大小动态变化 → std::vector(功能最丰富)。
  • 与 C 代码交互 → 原生数组(兼容性好)。

七、常见错误与最佳实践

7.1 常见错误

  1. 下标越界

    cpp

    运行

    int arr[5] = {1,2,3,4,5};
    cout << arr[5] << endl;  // 越界访问(下标最大为4),行为未定义
    
  2. 数组名直接赋值

    cpp

    运行

    int arr1[5] = {1,2,3,4,5};
    int arr2[5];
    arr2 = arr1;  // 错误!数组名是常量指针,不能直接赋值
    
  3. 误用指针计算数组长度

    cpp

    运行

    void func(int arr[]) {int n = sizeof(arr) / sizeof(arr[0]);  // 错误!arr是指针,n计算错误
    }
    

7.2 最佳实践

  1. 使用常量定义数组大小

    cpp

    运行

    const int SIZE = 10;  // 用const定义大小,便于修改和维护
    int arr[SIZE];
    
  2. 优先使用标准库容器用 std::array 或 std::vector 替代原生数组,减少手动管理的错误。

  3. 避免裸指针操作数组与指针结合时易出错,尽量使用范围 for 循环或迭代器遍历。

  4. 边界检查访问数组时确保下标在 [0, n-1] 范围内,必要时添加断言:

    cpp

    运行

    #include <cassert>
    int getElement(int arr[], int n, int index) {assert(index >= 0 && index < n);  // 断言检查下标合法性return arr[index];
    }
    

八、总结

数组是 C++ 中存储同类型元素的基础结构,依托连续内存实现 O (1) 随机访问,适合需要快速读写的场景。其核心特性包括固定大小、同质性和内存连续性。

在实际开发中:

  • 简单固定大小场景可使用原生数组或 std::array
  • 动态大小场景优先使用 std::vector
  • 操作数组时需注意下标越界和指针退化问题。

掌握数组的使用是学习更复杂数据结构(如链表、栈、队列)的基础,理解其内存模型和性能特性,能帮助开发者写出更高效、更安全的代码。

http://www.dtcms.com/a/607094.html

相关文章:

  • 化妆品手机端网站模板织梦网站模板视频
  • 长沙优化网站技巧wordpress邮箱配置stmp
  • leetcode 3228 将1移动到末尾的最大操作次数
  • 贵州最好的网站建设推广公司天津建设
  • 能源企业 网站建设学校门户网站建设的优势
  • RunLoop 深度解析
  • 如何来建设网站青岛建设集团招工信息网站
  • 1688采购系统:批量下单自动下单功能实现
  • 网站服务器cpu占用多少要升级工业信息化部网站备案
  • 手机网站模块一直免费的服务器下载
  • 实战:爬取汽车之家车型参数对比的技术指南
  • 网站后台怎么控制护理专业简历制作
  • DP 转光纤:捷米特 JM-DP-FIBER-S-A/B-R 转换器汽车焊接产线应用案例
  • 驭见未来,服务致胜:2025中国汽车终端服务体验洞察报告
  • 京东商品评论 API 返回数据解析指南:从嵌套 JSON 到结构化评论信息
  • 给别人开发一个网站多少钱大型外贸商城网站建设
  • 对于数据结构:链式二叉树的超详细保姆级解析—上
  • 石家庄红酒公司 网站建设资讯门户网站 dede
  • 【MySQL】内外链接和数据库索引
  • HOT100题打卡第38天——贪心算法
  • 力扣热题100道前55道,内容和力扣官方稍有不同,记录了本人的一些独特的解法
  • RDP登录事件详细溯源分析脚本(兼容Windows PowerShell版本)
  • 贪心算法实验1
  • 怎样做一个网站电子商务平台的类型
  • 好的网站建设公司哪家好北京优化推广公司
  • 易语言模块反编译与破解技术解析 | 深入理解反编译的原理与应用
  • 网站开发是哪个营销方案策划书
  • 用ps做一份网站小程序在线制作模板
  • Vite 7 + React 19 升级清单
  • 微网站怎么建设wordpress餐饮