欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 国际 > 【C++入门】数组:从基础到实践

【C++入门】数组:从基础到实践

2025/3/20 14:07:29 来源:https://blog.csdn.net/weixin_37800531/article/details/146286960  浏览:    关键词:【C++入门】数组:从基础到实践

目录

一、数组概述:数据存储的基石

1.1. 核心价值

1.2. 主要类型对比

二、数组的基本概念

2.1 什么是数组

2.2 数组的声明和初始化

2.2.1 声明数组

2.2.2 初始化数组

2.3 访问数组元素

三、一维数组

3.1 一维数组的遍历

3.2 一维数组的常见操作

四、二维数组

4.1 二维数组的概念

4.2 二维数组的声明和初始化

4.3 二维数组的遍历

4.4 二维数组的应用场景

五、多维数组

5.1 三维数组的声明和初始化

5.2 多维数组的遍历

六、数组与函数

6.1 数组作为函数参数

6.2 函数返回数组

七、数组的优缺点

7.1 优点

7.2 缺点

八、内存机制深度剖析

九、高级操作技巧

十、性能优化实战

十一、现代C++特性应用

十二、常见问题解决方案

十三、总结

十四、参考资料


在 C++ 编程中,数组是一种非常基础且重要的数据结构。它允许存储和管理一组相同类型的数据元素。无论是处理简单的数据集合,还是构建复杂的算法和程序,数组都扮演着不可或缺的角色。

一、数组概述:数据存储的基石

1.1. 核心价值

  • 连续内存空间存储相同类型元素

  • 支持随机访问(时间复杂度O(1))

  • 编译期确定大小(静态数组)或运行时动态分配(动态数组)

  • 内存效率极高,无额外管理开销

1.2. 主要类型对比

特性内置数组std::array(C++11)std::vector
大小确定编译时编译时运行时
内存管理自动/手动自动自动
边界检查at()方法提供at()方法提供
迭代器支持原生指针标准迭代器标准迭代器
传递效率退化指针值/引用传递引用传递

二、数组的基本概念

2.1 什么是数组

数组是一种由相同类型的元素组成的集合,这些元素在内存中是连续存储的。每个元素都可以通过一个唯一的索引来访问,索引通常是一个整数,从 0 开始计数。例如,一个包含 5 个整数的数组可以表示为int arr[5],其中arr是数组的名称,5是数组的大小。

2.2 数组的声明和初始化

2.2.1 声明数组

在 C++ 中,声明数组需要指定数组的类型和大小。以下是一些声明数组的示例:

// 声明一个包含5个整数的数组
int arr1[5];// 声明一个包含10个字符的数组
char arr2[10];// 声明一个包含3个双精度浮点数的数组
double arr3[3];

需要注意的是,数组的大小必须是一个常量表达式,即在编译时就可以确定的值。

2.2.2 初始化数组

数组可以在声明时进行初始化,也可以在声明后再进行赋值。以下是几种常见的初始化方式:

 ①逐个元素初始化

int arr[5] = {1, 2, 3, 4, 5};

声明了一个包含 5 个整数的数组,并使用大括号{}对每个元素进行了初始化。数组的第一个元素是1,第二个元素是2,以此类推。

② 部分元素初始化

int arr[5] = {1, 2};

在这种情况下,数组的前两个元素被初始化为12,其余元素会被自动初始化为 0。

③省略数组大小

int arr[] = {1, 2, 3, 4, 5};

 当使用大括号初始化数组时,可以省略数组的大小,编译器会根据初始化列表中的元素个数自动确定数组的大小。

④默认初始化

int arr[5];

如果只声明数组而没有进行初始化,数组中的元素将是未定义的。对于全局数组和静态数组,元素会被自动初始化为 0;对于局部数组,元素的值是不确定的。

2.3 访问数组元素

数组元素可以通过索引来访问。索引是一个整数,从 0 开始计数,最大索引为数组大小减 1。以下是一个访问数组元素的示例: 

#include <iostream>int main() {int arr[5] = {1, 2, 3, 4, 5};std::cout << "数组的第一个元素是: " << arr[0] << std::endl;std::cout << "数组的第三个元素是: " << arr[2] << std::endl;return 0;
}

 

 通过索引02分别访问了数组的第一个和第三个元素,并将其输出。

三、一维数组

3.1 一维数组的遍历

遍历数组意味着依次访问数组中的每个元素。常见的遍历方式有使用for循环和while循环。

①使用for循环遍历

#include <iostream>int main() {int arr[5] = {1, 2, 3, 4, 5};for (int i = 0; i < 5; i++) {std::cout << arr[i] << " ";}std::cout << std::endl;return 0;
}

 

使用for循环从索引 0 开始,依次访问数组的每个元素,并将其输出。

②使用while循环遍历

#include <iostream>int main() {int arr[5] = {1, 2, 3, 4, 5};int i = 0;while (i < 5) {std::cout << arr[i] << " ";i++;}std::cout << std::endl;return 0;
}

 

使用while循环实现了同样的遍历功能。

3.2 一维数组的常见操作

①查找元素:查找数组中是否存在某个特定的元素是一个常见的操作。以下是一个简单的查找函数:

#include <iostream>bool findElement(int arr[], int size, int target) {for (int i = 0; i < size; i++) {if (arr[i] == target) {return true;}}return false;
}int main() {int arr[5] = {1, 2, 3, 4, 5};int target = 3;if (findElement(arr, 5, target)) {std::cout << "元素 " << target << " 存在于数组中。" << std::endl;} else {std::cout << "元素 " << target << " 不存在于数组中。" << std::endl;}return 0;
}

 

定义了一个findElement函数,用于查找数组中是否存在指定的元素。

②求数组元素的和

计算数组中所有元素的和也是一个常见的操作。以下是一个求和函数:

#include <iostream>int sumArray(int arr[], int size) {int sum = 0;for (int i = 0; i < size; i++) {sum += arr[i];}return sum;
}int main() {int arr[5] = {1, 2, 3, 4, 5};int total = sumArray(arr, 5);std::cout << "数组元素的和是: " << total << std::endl;return 0;
}

 

定义了一个sumArray函数,用于计算数组中所有元素的和。 

 ③数组排序

对数组进行排序可以使数组元素按照一定的顺序排列。C++ 标准库提供了std::sort函数来实现排序功能。 

#include <iostream>
#include <algorithm>int main() {int arr[5] = {5, 3, 1, 4, 2};std::sort(arr, arr + 5);for (int i = 0; i < 5; i++) {std::cout << arr[i] << " ";}std::cout << std::endl;return 0;
}

 

使用std::sort函数对数组进行了升序排序,并将排序后的数组输出。

四、二维数组

4.1 二维数组的概念

二维数组可以看作是一个表格,由行和列组成。它可以用来表示矩阵、棋盘等数据结构。在 C++ 中,二维数组的声明和初始化方式与一维数组类似。

4.2 二维数组的声明和初始化

① 声明二维数组

// 声明一个3行4列的整数二维数组
int arr[3][4];

声明了一个包含 3 行 4 列的整数二维数组。

②初始化二维数组 

// 初始化一个3行4列的整数二维数组
int arr[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}
};

 使用嵌套的大括号对二维数组进行了初始化。每一行的元素用一个小括号括起来,不同行之间用逗号分隔。

4.3 二维数组的遍历

二维数组的遍历需要使用嵌套循环。外层循环控制行,内层循环控制列。

#include <iostream>int main() {int arr[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}};for (int i = 0; i < 3; i++) {for (int j = 0; j < 4; j++) {std::cout << arr[i][j] << " ";}std::cout << std::endl;}return 0;
}

 

4.4 二维数组的应用场景

二维数组在很多领域都有广泛的应用,例如图像处理、游戏开发等。在图像处理中,二维数组可以用来表示图像的像素矩阵;在游戏开发中,二维数组可以用来表示游戏地图。

五、多维数组

除了一维数组和二维数组,C++ 还支持多维数组。多维数组的概念和操作与二维数组类似,只是维度更多。例如,三维数组可以看作是由多个二维数组组成的。

5.1 三维数组的声明和初始化

// 声明一个2个平面,每个平面3行4列的三维整数数组
int arr[2][3][4];// 初始化三维数组
int arr[2][3][4] = {{{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}},{{13, 14, 15, 16},{17, 18, 19, 20},{21, 22, 23, 24}}
};

5.2 多维数组的遍历

多维数组的遍历需要使用多层嵌套循环。例如,遍历三维数组需要使用三层嵌套循环。

#include <iostream>int main() {int arr[2][3][4] = {{{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}},{{13, 14, 15, 16},{17, 18, 19, 20},{21, 22, 23, 24}}};for (int i = 0; i < 2; i++) {for (int j = 0; j < 3; j++) {for (int k = 0; k < 4; k++) {std::cout << arr[i][j][k] << " ";}std::cout << std::endl;}std::cout << std::endl;}return 0;
}

 

用三层嵌套的for循环遍历了三维数组的每个元素,并将其输出。

六、数组与函数

数组可以作为参数传递给函数,也可以作为函数的返回值。

6.1 数组作为函数参数

当数组作为函数参数时,实际上传递的是数组的首地址。以下是一个示例:

#include <iostream>void printArray(int arr[], int size) {for (int i = 0; i < size; i++) {std::cout << arr[i] << " ";}std::cout << std::endl;
}int main() {int arr[5] = {1, 2, 3, 4, 5};printArray(arr, 5);return 0;
}

 

 定义了一个printArray函数,用于打印数组的元素。函数的第一个参数是一个整数数组,第二个参数是数组的大小。

6.2 函数返回数组

在 C++ 中,函数不能直接返回数组,但可以返回指向数组的指针。以下是一个示例:

#include <iostream>int* createArray() {int* arr = new int[5];for (int i = 0; i < 5; i++) {arr[i] = i + 1;}return arr;
}int main() {int* arr = createArray();for (int i = 0; i < 5; i++) {std::cout << arr[i] << " ";}std::cout << std::endl;delete[] arr; // 释放动态分配的内存return 0;
}

 

定义了一个createArray函数,用于创建一个包含 5 个整数的数组,并返回该数组的指针。在main函数中,调用createArray函数获取数组指针,并打印数组的元素。最后,使用delete[]释放了动态分配的内存,以避免内存泄漏。

七、数组的优缺点

7.1 优点

  • 高效的随机访问:数组元素在内存中是连续存储的,因此可以通过索引快速访问任意元素,时间复杂度为 O (1)。
  • 简单易用:数组的声明和操作都比较简单,容易理解和掌握。

7.2 缺点

  • 大小固定:数组的大小在声明时就已经确定,不能在运行时动态调整。如果需要动态调整大小,可以使用std::vector
  • 插入和删除操作效率低:在数组中插入或删除元素需要移动大量的元素,时间复杂度为 O (n)。

八、内存机制深度剖析

①内存布局示例

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

内存结构:

地址    | 值
0x1000 | 10  // arr[0]
0x1004 | 20  // arr[1]
0x1008 | 30  // arr[2]
0x100C | 40  // arr[3]
0x1010 | 50  // arr[4]

②指针与数组关系

int* ptr = arr;        // 等价于 &arr[0]
ptr += 3;             // 指向arr[3]
*(ptr-1) = 100;       // 修改arr[2]// 数组名不可修改
arr = ptr;           // 编译错误

 ③数组退化的陷阱

void process(int arr[]) {  // 实际退化为int* cout << sizeof(arr);  // 输出指针大小(如8字节)
}int main() {int arr[5] = {0};cout << sizeof(arr);  // 输出20(5*4字节)process(arr);
}

九、高级操作技巧

①数组引用(C++特性)

// 保持数组类型信息
template<size_t N>
void print_array(int (&arr)[N]) {  // 精确匹配数组大小for(int i=0; i<N; ++i)cout << arr[i] << " ";
}int arr[] = {1,2,3};
print_array(arr);  // 正确传递数组引用

②动态内存管理

// 创建动态数组
int* dynArr = new int[10]; // 初始化动态数组
int* dynArr2 = new int[5]{1,2,3,4,5};  // C++11// 释放内存
delete[] dynArr;  // 必须配对使用

③数组与算法结合

#include <algorithm>
#include <numeric>int arr[] = {3,1,4,2,5};// 排序
std::sort(std::begin(arr), std::end(arr));// 累加求和
int sum = std::accumulate(arr, arr+5, 0);// 查找元素
auto it = std::find(arr, arr+5, 4);
if(it != arr+5) cout << "Found at index: " << it - arr;

十、性能优化实战

①缓存友好访问模式

// 优先行序访问(内存连续)
int matrix[1000][1000];
for(int i=0; i<1000; ++i)       // 外层行循环for(int j=0; j<1000; ++j)   // 内层列循环matrix[i][j] = i+j;// 避免跳行访问
for(int j=0; j<1000; ++j)       // 错误示范for(int i=0; i<1000; ++i)matrix[i][j] = i+j;     // 缓存命中率低

②SIMD矢量化

// 使用编译器指令优化
#pragma omp simd
for(int i=0; i<N; ++i) {a[i] = b[i] + c[i];
}// 手动使用AVX指令
#include <immintrin.h>
void add_arrays(float* a, float* b, float* c, int n) {for(int i=0; i<n; i+=8) {__m256 va = _mm256_load_ps(&a[i]);__m256 vb = _mm256_load_ps(&b[i]);__m256 vc = _mm256_add_ps(va, vb);_mm256_store_ps(&c[i], vc);}
}

③循环展开优化

// 手动展开循环
for(int i=0; i<1024; i+=4) {arr[i] = i;arr[i+1] = i+1;arr[i+2] = i+2;arr[i+3] = i+3;
}

十一、现代C++特性应用

①结构化绑定(C++17)

std::array<int,3> get_point() { return {10,20,30}; }auto [x,y,z] = get_point();  // 解包数组元素
cout << "X: " << x << ", Y: " << y;

②constexpr数组(C++11)

constexpr int fib[] = {0,1,1,2,3,5,8,13};
static_assert(fib[7] == 13, "Fibonacci error");

③范围视图(C++20)

#include <ranges>
int arr[] = {1,2,3,4,5,6};// 过滤偶数并反转
for(int v : arr | views::filter([](int x){return x%2==0;})| views::reverse) 
{cout << v << " ";  // 输出6 4 2
}

十二、常见问题解决方案

① 数组越界预防

template<typename T, size_t N>
class SafeArray {T data[N];
public:T& operator[](size_t index) {if(index >= N) throw std::out_of_range("Index overflow");return data[index];}
};

②动态数组内存管理

// 使用智能指针(C++11)
auto dynArr = std::make_unique<int[]>(100);  // 自动释放内存
dynArr[50] = 123;// 容器封装
std::vector<int> safeDynArr(100);  // 推荐替代方案

③深拷贝实现

// 内置数组深拷贝
int src[5] = {1,2,3,4,5};
int dest[5];
std::copy(std::begin(src), std::end(src), dest);// std::array自动深拷贝
std::array<int,5> a = {1,2,3,4,5};
auto b = a;  // 完全独立拷贝

十三、总结

数组是 C++ 编程中非常基础和重要的数据结构。数组具有高效的随机访问能力,但也存在大小固定和插入删除操作效率低的缺点。在实际编程中,需要根据具体的需求选择合适的数据结构。

希望本文能够帮助初学者全面掌握数组的使用,为进一步学习 C++ 编程打下坚实的基础。


十四、参考资料

  •  《C++ Primer(第 5 版)》这本书是 C++ 领域的经典之作,对 C++ 的基础语法和高级特性都有深入讲解。
  • 《Effective C++(第 3 版)》书中包含了很多 C++ 编程的实用建议和最佳实践。
  • 《C++ Templates: The Complete Guide(第 2 版)》该书聚焦于 C++ 模板编程,而using声明在模板编程中有着重要应用,如定义模板类型别名等。
  • C++ 官方标准文档:C++ 标准文档是最权威的参考资料,可以查阅最新的 C++ 标准(如 C++11、C++14、C++17、C++20 等)文档。例如,ISO/IEC 14882:2020 是 C++20 标准的文档,可从相关渠道获取其详细内容。
  • cppreference.com:这是一个非常全面的 C++ 在线参考网站,提供了详细的 C++ 语言和标准库文档。
  • LearnCpp.com:该网站提供了系统的 C++ 教程,配有丰富的示例代码和清晰的解释,适合初学者学习和理解相关知识。

 

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词