C++系列学习 指针、数组、函数

📅 发布时间:2026/7/5 22:56:49 👁️ 浏览次数:
C++系列学习 指针、数组、函数
理解一下指针、数组、函数1、为什么引入解决什么问题有什么好处基本语法使用过程中什么时候要关心可以用解引用指针来初始化引用inta10;int*pa;// 指针 p 指向 aintq*p;// 引用 q 绑定到 p 所指向的对象就是 a此时三者的关系p (指针) ┌────────┐ │ 0x7FF8 │ ──────→ ┌──────┐ └────────┘ │ 10 │ ← 对象 a └──────┘ ↑ q (引用a 的别名)a、*p、q三个都是同一个东西修改任何一个都会影响其他inta10;int*pa;intq*p;q20;couta;// 20cout*p;// 20coutq;// 20 三个都是 20各种组合都合法inta10;// 从对象创建指针和引用int*pa;// 指针 ← 对象地址intra;// 引用 ← 对象// 从指针创建引用intr2*p;// 引用 ← 解引用指针 ✅// 从引用创建指针int*p2r;// 指针 ← 引用的地址就是 a 的地址 ✅// 最终 a, *p, *p2, r, r2 全部是同一个东西本质理解回到你之前的领悟——引用是自动解引用的常量指针intq*p;// 编译器底层做的事// int* const q_internal p; // 引用底层存的就是 p 的值地址// 使用 q 时自动 *q_internal所以int q *p本质上就是把指针 p 里存的地址交给引用 q 底层的常量指针保存。你这个理解方向完全正确对这是引用最基本的语法格式基本格式类型引用名对象;例子inta10;intrefa;// ref 是 a 的引用别名string sHello;stringrss;// rs 是 s 的引用Box box;Boxrbbox;// rb 是 box 的引用对比 C 语言的指针// 指针指针变量 对象的地址int*pa;// p 存的是 a 的地址// 引用引用 对象直接绑定不需要取地址intra;// r 就是 a 的别名注意事项// ✅ 必须在声明时就绑定intrefa;// ❌ 不能先声明后绑定intref;// 编译错误引用必须初始化refa;// ❌ 不能绑定字面量除非加 constintref10;// 编译错误constintref10;// ✅ const 引用可以绑定临时值/字面量一句话类型 引用名 对象;就是引用的基本格式。引用必须在声明时绑定一旦绑定就不可更改终身指向同一个对象。跟 C 里的类型* 指针名 对象;对比记忆就很清晰。C 中创建对象主要有以下几种方式1. 直接初始化最常用Studentstu(张三,20,95.5);// 直接调用有参构造Student stu2;// 调用无参构造默认构造2. 拷贝初始化用Student stuStudent(张三,20,95.5);// 先构造临时对象再拷贝编译器通常会优化掉拷贝3. 列表初始化C11 起用{}Student stu{张三,20,95.5};// 花括号初始化Student stu2{张三,20,95.5};// 花括号 等号4. new 创建堆上分配Student*stunewStudent(张三,20,95.5);// 返回指针// 用完必须手动释放deletestu;对比总结方式语法分配位置生命周期需要 delete直接初始化Student stu(...)栈出作用域自动销毁不需要拷贝初始化Student stu Student(...)栈出作用域自动销毁不需要列表初始化Student stu{...}栈出作用域自动销毁不需要new 创建Student* stu new Student(...)堆手动管理必须 delete用 C 语言对比// C 语言structStudentstu;// 栈上类似方式1structStudent*stumalloc(sizeof(Student));// 堆上类似方式4 newfree(stu);// 对应 delete⚠️ 一个常见错误Studentstu();// ❌ 这不是创建对象这是声明了一个函数Student stu;// ✅ 无参构造应该这样写不加括号Student stu{};// ✅ 或者用空花括号一句话日常开发优先用栈上创建方式1简单安全。只有需要动态管理生命周期时才用new方式4并且现代 C 推荐用智能指针make_unique/make_shared代替裸new。这是语言设计上的规定但背后有原因先回忆 C 语言inta10;// 栈上 —— 编译时就确定大小自动管理int*pmalloc(sizeof(int)*n);// 堆上 —— 运行时才知道大小手动管理free(p);C 的new就是 C 的malloc的升级版int*pnewint(10);// 堆上相当于 malloc 初始化deletep;// 释放相当于 free为什么需要堆栈不够用吗┌─────────────────────────────────────────────┐ │ 栈Stack │ │ 特点 │ │ ✅ 自动分配、自动释放出作用域就没了 │ │ ✅ 速度快 │ │ ❌ 大小固定通常只有 1~8MB │ │ ❌ 生命周期受限于作用域 │ ├─────────────────────────────────────────────┤ │ 堆Heap │ │ 特点 │ │ ✅ 大小灵活几个GB都行 │ │ ✅ 生命周期由你控制跨函数、跨作用域 │ │ ❌ 需要手动释放 │ │ ❌ 速度略慢 │ └─────────────────────────────────────────────┘三个必须用堆的场景// 场景1运行时才知道大小intn;cinn;int*arrnewint[n];// 栈上做不到C99 的 VLA 不推荐// 场景2对象需要在函数外存活Person*createPerson(){Person*pnewPerson(张三);returnp;// ✅ 堆上的对象函数结束后还在// 如果放栈上// Person p(张三);// return p; // ❌ 函数结束p 被销毁返回野指针}// 场景3对象太大栈放不下double*bigArraynewdouble[10000000];// 80MB栈肯定放不下底层原理操作系统层面程序内存布局你学 C 时应该见过 高地址 ┌──────────────┐ │ 栈 Stack │ ← 函数调用时自动分配向下增长 │ ↓ │ 编译器管理速度快 │ │ │ ↑ │ │ 堆 Heap │ ← new/malloc 时分配向上增长 │ │ 操作系统管理通过系统调用(brk/mmap) ├──────────────┤ │ 全局/静态数据 │ ├──────────────┤ │ 代码段 │ 低地址 └──────────────┘new的底层做了两件事调用operator new内部调用malloc→ 操作系统的brk/mmap在堆上分配内存调用构造函数初始化对象一句话栈是自动的但受限大小小、生命周期短堆是自由的但需要手动管。new在堆上分配是因为你需要超出栈限制的能力——更大的空间、更长的生命周期、运行时决定大小。这跟 C 里用malloc的原因完全一样。