在 C++ 中,数组是存储固定大小同类型元素的集合。
数组的定义、输入输出、应用注意事项以及去重方法。
一维数组的静态与动态定义
静态定义(栈内存)
这是最常见的方式。数组的大小在编译时确定,存储在栈区。
-
语法 :
类型 数组名[大小]; -
示例 :
cppint a[10]; // 定义一个包含10个整数的数组,未初始化(值随机) int b[5] = {1, 2, 3, 4, 5}; // 定义并初始化 int c[] = {10, 20}; // 省略大小,编译器自动推断为2 -
特点:速度快,但大小受限(通常几 MB),函数结束后自动销毁。
动态定义(堆内存)
当数组大小需要在运行时才能确定,或者需要非常大的空间时使用。
-
方式一:使用
newcppint n; cin >> n; int* arr = new int[n]; // 在堆上分配 n 个 int 的空间 // ... 使用数组 ... delete[] arr; // 【重要】必须手动释放内存,防止内存泄漏 -
方式二:使用
vector(推荐)
C++ STL 提供的动态数组,自动管理内存。cpp#include <vector> int n; cin >> n; vector<int> vec(n); // 定义大小为 n 的动态数组 // 不需要手动 delete
输入与输出
C++ 原生不支持直接 cin >> a 或 cout << a 来操作整个数组,必须使用循环逐个处理。
输入
cpp
int a[5];
// 方法:for 循环
for(int i = 0; i < 5; i++) {
cin >> a[i];
}
输出
cpp
// 方法:for 循环
for(int i = 0; i < 5; i++) {
cout << a[i] << " ";
}
cout << endl;
// C++11 范围 for 循环(更简洁)
for(int x : a) {
cout << x << " ";
}
数组的应用及注意事项
常见应用
- 批量数据处理:如计算平均分、查找最大值/最小值。
- 桶排序/计数:利用下标记录数据出现的次数(例如统计字符频率)。
- 模拟数据结构:用数组模拟栈、队列或哈希表。
核心注意事项(避坑指南)
- 下标越界 :数组下标从 0 开始,到 N-1 结束。访问
a[N]是严重错误,可能导致程序崩溃或读取脏数据。 - 未初始化:局部数组(在函数内定义的)如果不初始化,里面的值是随机的垃圾值。全局数组默认初始化为 0。
- 大小限制 :不要在函数内部定义过大的静态数组(如
int a[10000000]),这会导致栈溢出 。大数组应定义为全局变量或使用vector。 - 长度不可变 :静态数组一旦定义,长度无法改变。如果需要变长,请使用
std::vector。
数组去重的两种方法
假设有一个无序数组,需要去除重复元素。
方法一:排序 + 双指针(原地去重,节省空间)
先对数组排序,重复的元素会相邻,然后通过双指针将不重复的元素移到前面。
- 时间复杂度 :O(NlogN)O(N \log N)O(NlogN)
- 空间复杂度 :O(1)O(1)O(1)
cpp
#include <algorithm>
#include <iostream>
using namespace std;
int main() {
int a[] = {4, 2, 4, 1, 2, 3};
int n = 6;
// 1. 排序
sort(a, a + n);
// 2. 双指针去重
int k = 0; // k 指向去重后数组的最后一个位置
for (int i = 1; i < n; i++) {
if (a[i] != a[k]) {
a[++k] = a[i]; // 将不重复的元素前移
}
}
// 输出去重后的结果 (长度为 k+1)
for (int i = 0; i <= k; i++) {
cout << a[i] << " ";
}
return 0;
}
方法二:使用 set 集合(代码简单,自动去重)
利用 std::set 不允许存储重复元素的特性。
- 时间复杂度 :O(NlogN)O(N \log N)O(NlogN)
- 空间复杂度 :O(N)O(N)O(N)
cpp
#include <iostream>
#include <set>
using namespace std;
int main() {
int a[] = {4, 2, 4, 1, 2, 3};
int n = 6;
set<int> s;
// 插入所有元素,set 会自动去重并排序
for (int i = 0; i < n; i++) {
s.insert(a[i]);
}
// 遍历输出
for (int x : s) {
cout << x << " ";
}
return 0;
}
C++ 一维数组核心速查表:
1. 数组定义方式速查
| 方式 | 语法 | 内存位置 | 特点与适用场景 |
|---|---|---|---|
| 静态定义 | int a[10]; |
栈区 | 编译时确定大小,速度快,但大小受限(防栈溢出)。 |
| 动态定义(new) | int* a = new int[n]; |
堆区 | 运行时确定大小,必须手动 delete[] 释放。 |
| 动态定义(vector) | vector<int> a(n); |
堆区 | 最推荐。自动管理内存,支持动态扩容,防越界。 |
2. 输入与输出模板
- 输入 :
for(int i=0; i<n; i++) cin >> a[i]; - 输出 :
for(int x : a) cout << x << " ";(范围 for 循环最简洁)
3. 避坑指南(注意事项)
- 下标从 0 开始 :有效范围是
0到N-1,访问a[N]会越界崩溃。 - 局部数组需初始化 :函数内定义的
int a[10];默认是随机垃圾值,建议写int a[10] = {0};。 - 大数组放全局 :超过百万级别的数组,一定要定义在函数外面(全局区)或用
vector,否则必栈溢出。
4. 数组去重方案对比
| 方法 | 核心逻辑 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|---|
| 排序 + 双指针 | 先 sort,再用双指针把不重复的元素往前挪。 |
O(NlogN)O(N \log N)O(NlogN) | O(1)O(1)O(1) | 要求原地修改、节省内存,或算法题限制空间。 |
| Set 集合 | 将元素丢进 set,自动去重并排序。 |
O(NlogN)O(N \log N)O(NlogN) | O(N)O(N)O(N) | 追求代码极简,不在乎额外空间开销。 |
1.为什么需要"魔法背包" ----Vector?
"同学们,之前我们学的普通数组(静态数组),就像是一个固定大小的收纳盒 。如果盒子里只能装 5 个苹果,你非要塞进第 6 个,盒子就会'砰'地炸掉(程序崩溃)!
但是,如果我们去超市买东西,根本不知道会买多少件,怎么办?这时候我们需要一个魔法背包(vector)!你放进去一个苹果,它就变大一点;放进去十个,它继续变大。它会自动调整大小,永远不会撑爆!"
2. 核心语法:魔法背包的"三件套"
第一步:准备背包(声明)
cpp
#include <vector> // 必须带上这个"说明书"
vector<int> myBag; // 准备一个装整数的魔法背包
第二步:往背包里放东西(push_back)
cpp
myBag.push_back(10); // 放进一个 10
myBag.push_back(20); // 再放进一个 20
myBag.push_back(30); // 继续放
【提示】 :push_back 就像是往背包后面"推(push)"进去一个东西,back 就是"后面"。
第三步:看看背包里有什么(遍历)
C++11 范围 for 循环 ,这比传统的 for(int i=0; i<n; i++) 简单太多。
cpp
for(int item : myBag) {
cout << item << " ";
}
3. 实战演练:超级加法器
用一个能无限接收数字,直到输入特定数字(比如 -1)才停止的小程序,体验 vector 的威力。
cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> numbers; // 1. 准备空背包
int num;
cout << "请输入数字(输入 -1 结束):";
// 2. 无限接收数据,直到遇到 -1
while(cin >> num && num != -1) {
numbers.push_back(num); // 自动放进背包
}
// 3. 打印所有收集到的数字
cout << "你一共输入了这些数字:";
for(int n : numbers) {
cout << n << " ";
}
return 0;
}
4."避坑"建议
- 忘记写头文件 :这是最常见的错误。可以编个口诀:"用魔法背包,先喊
#include <vector>"。 - 拼写错误 :
push_back中间有个下划线,很多孩子会写成pushback。建议让他们把push_back当作一个完整的单词来记。 - 最好不要用
new和delete:千万不要在这个阶段提new int[n]和内存泄漏,这会产生畏难情绪。vector就是为了替代这些复杂操作的。 - 关于
size()函数 :可以补充numbers.size()这是"看看背包里有几个东西",在写普通 for 循环遍历时会用到。