C++零基础到工程实战(4.3.2):栈区与堆区数组代码演示

张开发
2026/4/18 13:11:00 15 分钟阅读

分享文章

C++零基础到工程实战(4.3.2):栈区与堆区数组代码演示
目录一、本节学习内容概要二、前言三、栈区数组代码演示3.1 栈区数组定义3.2 值访问与地址访问3.3 栈区数组大小计算3.4 栈区数组必须是编译时常量四、堆区数组代码演示4.1 基本定义与访问4.2 值与地址访问4.3 手动释放4.4 堆区数组动态大小示例4.5 memcpy 拷贝示例五、栈区 vs 堆区对比六、扩展点6.1 栈区数组过大可能溢出6.2 堆区数组不释放会泄漏6.3 栈 vs 堆地址方向七、完整示例代码八、本节小结一、本节学习内容概要栈区数组创建与内存分配堆区数组创建与手动释放栈 vs 堆内存地址打印栈区与堆区数组访问示例大小计算与 sizeof 使用面试常考点与注意事项二、前言在上一节我们了解了数组的本质、访问方式以及栈区、堆区数组和 vector 的区别。本节的重点是通过代码演示栈区和堆区数组的值访问、地址访问、十六进制打印、整型转换以及memcpy拷贝操作让概念落地到实际代码顺带掌握工程实践要点。以帮助你理解“连续内存 地址计算 值访问”。三、栈区数组代码演示3.1 栈区数组定义int arr[5] {10, 20, 30, 40, 50};✅ 特点在函数作用域内定义内存分配在栈区系统自动释放3.2 值访问与地址访问for (int i 0; i 5; i) { cout arr[ i ] arr[i] , arr[ i ] arr[i] , arr i arr i , *(arr i ) *(arr i) endl; }arr[i]和*(arr i)获取元素值arr[i]和arr i获取元素地址地址连续每个 int 占 4 字节假设#include iostream using namespace std; int main() { int arr[5] {10, 20, 30, 40, 50}; cout 栈区数组首地址: arr endl; for (int i 0; i 5; i) { cout arr[ i ] arr[i] , 地址: (arr i) endl; } return 0; } 输出解析✅ 可以看到地址是连续的每个元素占 4 字节intarr本身是首地址arr i和arr[i]等价面试点栈区数组自动释放不需要手动 delete3.3 栈区数组大小计算cout 整个数组大小: sizeof(arr) 字节 endl; cout 单个元素大小: sizeof(arr[0]) 字节 endl; cout 数组元素数量: sizeof(arr)/sizeof(arr[0]) endl;✅ 说明sizeof(arr)返回整个数组占用的字节sizeof(arr[0])返回单个元素大小sizeof(arr)/sizeof(arr[0])得到元素数量3.4 栈区数组必须是编译时常量int size 5; const int csize 5; //编译时常量 const int csize2 size; //运行时常量 constexpr int cesize 5; //编译时常量 int arr3[csize]; int arr4[cesize];栈区数组大小必须是编译时常量constexpr不支持运行时变量定义。四、堆区数组代码演示4.1 基本定义与访问int* arr2 new int[5]{10,20,30,40,50};✅ 特点分配在堆区手动管理内存大小可在运行时确定4.2 值与地址访问cout 堆区数组首地址: arr2 endl; for (int i 0; i 5; i) { cout arr2[ i ] arr2[i] , 地址: (arr2 i) endl; }//数组遍历存放的数组首地址 cout arr1 (long long)arr1 endl; // arr1[0]十六进制 (long long)arr1[0]十六进制转十进制整型方式 cout arr1[0] (long long)arr1[0] endl; cout arr1[1] (long long)arr1[1] endl; cout arr1[2] (long long)arr1[2] endl; cout arr1[3] (long long)arr1[3] endl; cout arr1 2 (long long)(arr1 2) endl; cout arr1 3 (long long)(arr1 3) endl;✅ 输出解析地址也是连续的但不与栈区相关与栈区相比分配速度稍慢但灵活4.3 手动释放delete[] arr2; arr2 nullptr; // 避免悬空指针面试点堆数组必须手动释放否则内存泄漏4.4 堆区数组动态大小示例int n; cin n; int* arr3 new int[n]; for (int i 0; i n; i) arr3[i] i * 10; delete[] arr3;✅ 可以根据用户输入动态分配堆内存这一点是栈区数组无法做到的。4.5 memcpy 拷贝示例int* arr2 new int[5]{10, 20, 30, 40, 50}; int arr_copy[5]; memcpy(arr_copy, arr2, 5 * sizeof(int)); cout 复制后的栈区数组 arr_copy: ; for(int i 0; i 5; i) cout arr_copy[i] ; cout endl;快速复制数组内容可实现栈-堆或堆-堆五、栈区 vs 堆区对比特性栈区数组堆区数组内存位置栈堆生命周期自动手动大小编译期固定运行期可变内存释放自动delete[]必须手动值访问arr[i], *(arri)arr[i], *(arri)地址访问arr[i], arriarr[i], arri内存连续性是是面试考点自动释放地址连续手动释放地址连续memcpy使用六、扩展点6.1 栈区数组过大可能溢出栈通常只有几十 KB大数据请用堆或 vector6.2 堆区数组不释放会泄漏工程实践建议使用智能指针或 vector6.3 栈 vs 堆地址方向栈从高地址向低地址增长堆从低地址向高地址增长可以通过打印地址观察七、完整示例代码#include iostream using namespace std; int main() { //栈区数组 { //类型 变量名[数组数量] int arr1[4]{ 0 }; //c11 for循环遍历 for (int a : arr1) //int a:arr1 : 每次循环创建一个新的int类型变量a 创建变量a让他一次等于arr1[0]...arr1[3] cout a ; cout endl; arr1[0] 99; //下标从0 arr1[2] 88; for (int a : arr1) cout a ; cout endl; cout sizeof(arr1) sizeof(arr1) endl; // 一个int类型是4个字节 4个是16字节 for (int i 0; i sizeof(arr1)/sizeof(int);i) { cout arr1[i] ,; } cout endl; int arr2[4]; //未初始化 值不确定 //c11 for循环遍历 for (int a : arr2) cout a ; cout endl; //栈区数组空间只能用编译时常量 int size 5; const int csize 5; //编译时常量 const int csize2 size; //运行时常量 constexpr int cesize 5; //编译时常量 int arr3[csize]; int arr4[cesize]; //栈区数组的初始化不加大小时数组会根据初始化内容自己定义大小 int arr5[10] { 1,2,3,4,5 }; int arr6[] { 3,4,5,6,7,8 }; char arr7[] test string; //字符串结尾还有个/0 一个字母一字节 所以共12字节 cout sizeof(arr6) sizeof(arr6) endl; cout sizeof(arr7) sizeof(arr7) endl; //数组是地址连续的空间 //数组遍历存放的数组首地址 cout arr1 (long long)arr1 endl; // arr1[0]十六进制 (long long)arr1[0]十六进制转十进制整型方式 cout arr1[0] (long long)arr1[0] endl; cout arr1[1] (long long)arr1[1] endl; cout arr1[2] (long long)arr1[2] endl; cout arr1[3] (long long)arr1[3] endl; cout arr1 2 (long long)(arr1 2) endl; cout arr1 3 (long long)(arr1 3) endl; cout *(arr1 2) *(arr1 2) endl; } { int arr1[4]{ 0 }; } { //堆区数组 int* arr1 new int[4] {0}; // 堆区空间大小必须分配 不能像栈区那样自动分配 auto arr2 new int[4] {1, 2, 3, 4}; cout sizeof(arr1) sizeof(arr1) endl; // sizeof对于堆区数组只是拿到指针大小 这里是8 int size 10; auto arr3 new int[size] {0}; // 空间大小可以通过变量运行时确定 而栈区数组得编译时确定 // size大小可控制 但是不能用C11得循环 也不能直接获取大小 实际字节大小 size*int for (int i 0; i size; i) { cout arr3[i] |; } cout endl; delete[] arr1; arr1 nullptr; delete[] arr2; arr2 nullptr; delete[] arr3; arr3 nullptr; // delete过后 数组(arr1)的地址并没有变化仍然指向原来的空间但原来空间的内存已经被释放 继续访问就是未知错误 int arr5[5] { 1,2,3,4,5 }; auto* arr6 new int[5]; // 内存复制 memcpy(目标数组被复制的数组首地址复制字节) memcpy(arr6, arr5, sizeof(arr5)); for (int i 0; i 5; i) cout arr6[i] -; cout endl; delete[]arr6; arr6 nullptr; } }八、本节小结栈区数组简单、快速、自动释放但大小固定堆区数组灵活、可动态分配但必须手动释放访问方式栈和堆一致arr[i]/arr i面试提示打印地址可观察栈/堆增长方向

更多文章