C++信奥静态数组和动态数组

在 C++ 中,数组是存储固定大小同类型元素的集合。

数组的定义、输入输出、应用注意事项以及去重方法。

一维数组的静态与动态定义

静态定义(栈内存)

这是最常见的方式。数组的大小在编译时确定,存储在栈区。

  • 语法类型 数组名[大小];

  • 示例

    cpp 复制代码
    int a[10]; // 定义一个包含10个整数的数组,未初始化(值随机)
    int b[5] = {1, 2, 3, 4, 5}; // 定义并初始化
    int c[] = {10, 20}; // 省略大小,编译器自动推断为2
  • 特点:速度快,但大小受限(通常几 MB),函数结束后自动销毁。

动态定义(堆内存)

当数组大小需要在运行时才能确定,或者需要非常大的空间时使用。

  • 方式一:使用 new

    cpp 复制代码
    int 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 >> acout << 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 << " ";
}

数组的应用及注意事项

常见应用
  1. 批量数据处理:如计算平均分、查找最大值/最小值。
  2. 桶排序/计数:利用下标记录数据出现的次数(例如统计字符频率)。
  3. 模拟数据结构:用数组模拟栈、队列或哈希表。
核心注意事项(避坑指南)
  1. 下标越界 :数组下标从 0 开始,到 N-1 结束。访问 a[N] 是严重错误,可能导致程序崩溃或读取脏数据。
  2. 未初始化:局部数组(在函数内定义的)如果不初始化,里面的值是随机的垃圾值。全局数组默认初始化为 0。
  3. 大小限制 :不要在函数内部定义过大的静态数组(如 int a[10000000]),这会导致栈溢出 。大数组应定义为全局变量或使用 vector
  4. 长度不可变 :静态数组一旦定义,长度无法改变。如果需要变长,请使用 std::vector

数组去重的两种方法

假设有一个无序数组,需要去除重复元素。

方法一:排序 + 双指针(原地去重,节省空间)

先对数组排序,重复的元素会相邻,然后通过双指针将不重复的元素移到前面。

  • 时间复杂度 :O(Nlog⁡N)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(Nlog⁡N)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 开始 :有效范围是 0N-1,访问 a[N] 会越界崩溃。
  • 局部数组需初始化 :函数内定义的 int a[10]; 默认是随机垃圾值,建议写 int a[10] = {0};
  • 大数组放全局 :超过百万级别的数组,一定要定义在函数外面(全局区)或用 vector,否则必栈溢出。

4. 数组去重方案对比

方法 核心逻辑 时间复杂度 空间复杂度 适用场景
排序 + 双指针 sort,再用双指针把不重复的元素往前挪。 O(Nlog⁡N)O(N \log N)O(NlogN) O(1)O(1)O(1) 要求原地修改、节省内存,或算法题限制空间。
Set 集合 将元素丢进 set,自动去重并排序。 O(Nlog⁡N)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."避坑"建议

  1. 忘记写头文件 :这是最常见的错误。可以编个口诀:"用魔法背包,先喊 #include <vector>"。
  2. 拼写错误push_back 中间有个下划线,很多孩子会写成 pushback。建议让他们把 push_back 当作一个完整的单词来记。
  3. 最好不要用 newdelete :千万不要在这个阶段提 new int[n] 和内存泄漏,这会产生畏难情绪。vector 就是为了替代这些复杂操作的。
  4. 关于 size() 函数 :可以补充 numbers.size() 这是"看看背包里有几个东西",在写普通 for 循环遍历时会用到。
相关推荐
gumichef3 小时前
第一章:面向对象核心——类和对象深度讲解
开发语言·c++
郝学胜-神的一滴3 小时前
[简化版 GAMES 104] 现代游戏引擎 04:从0到1构建你的游戏世界
c++·游戏·unity·游戏引擎·软件工程·unreal engine
月光船幽幽3 小时前
呼吸孔设计重塑系统稳定性
python·科技·算法
Bryce学亮3 小时前
FileLine,基于 Qt 6 + QML 构建的跨平台文件传输与即时通讯工具
数据库·c++·人工智能·python·qt·github
旖旎夜光3 小时前
LeetCode 991: 坏了的计算器(贪心算法) —— 题解
数据结构·c++·算法·leetcode·贪心算法
旖旎夜光4 小时前
LeetCode 553:最优除法(贪心算法) —— 题解
数据结构·c++·算法·leetcode·贪心算法
雾喔4 小时前
算法练习7
java·数据结构·算法
过期的秋刀鱼!4 小时前
重点-偏差方差与神经网络
人工智能·深度学习·神经网络·算法·机器学习·过拟合·l2正则化
可编程芯片开发5 小时前
基于模糊PID控制的六步逆变器供电无刷直流电机调速simulink仿真
算法