知识点一:常量字符串
cpp
char* str = "hello"; //会报错 因为"hello" 是常量字符串,需要用const
const char* str = "hello"; //不会报错
知识点二:realloc
realloc函数的出现让动态内存管理更加灵活。
有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时 候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小 的调整。
cpp
void* realloc (void*ptr, size_t size);
(1)ptr 是要调整的内存地址
(2)size 调整之后新大小
(3)返回值为调整之后的内存的起始地址。
(4)内存追加失败就会返回空指针。
注意:realloc()参数中的指针如果是空指针的情况下与malloc是等价的!
灵魂提问:
:realloc 是不是新开辟一个空间,并不是在原来的空间上增加?
灵魂答案:
不一定!realloc 有两种情况,一半概率原地变大,一半概率搬家新开辟!
我用最通俗、最直白的话给你讲懂,你以后永远不会错。
1. 第一种情况:原地扩容(运气好)
原来的内存后面还有足够空位置 realloc 就直接在原来的空间后面加长 → 不搬家、地址不变
c
运行
原来:[XXXX] 空闲空闲空闲
realloc 变大:[XXXXXXXX]
2. 第二种情况:搬家新开辟(最常见)
原来的内存后面被占用了,没地方扩展realloc 会:
-
新找一块足够大的内存
-
把旧数据全部拷贝过去
-
自动把旧的内存 free 掉
-
返回新的地址
旧:[XXXX]被占用被占用
↓ 不够大
新开辟:[XXXXXXXXXXXX]
最重要结论(你必须记住)
realloc 可能返回一个全新的地址!也可能还是原来的地址!
你绝对不能用原来的指针接收!
❌ 错误写法(90% 的人都死在这里)
p = realloc(p, 100); // 万一失败,p 变成 NULL,原数据丢了
✅ 正确写法(永远安全)
void *temp = realloc(p, 100); // 用临时指针接收
if(temp != NULL)
{
p = temp; // 成功才赋值
}
回答你的问题
realloc 是不是新开辟一个空间,并不是在原来的空间上增加?
答案:不一定!
- 后面空间够 → 原地增加
- 后面空间不够 → 新开空间 + 拷贝 + 释放旧空间
但你写代码时,必须按 "会新开空间、地址会变" 来处理!
超级精简口诀
realloc 可能原地变大,也可能搬家! 永远用临时指针接收,别直接覆盖原指针!
知识点三:free
一、头文件
#include <stdlib.h>
二、函数原型
void free(void *ptr);
三、参数
- ptr :指向malloc/calloc/realloc动态申请堆内存的指针
- 可以传 **NULL,如果参数 ptr 是NULL,**函数直接空运行,啥也不做,不会报错
四、核心作用
- 把堆区动态申请的内存还给操作系统 / 内存管理器
- 释放后这块内存不再受当前程序管控,可被重新分配
- 不会自动清零内存原有数据,原数据暂时还在
五、使用规则
-
只能释放堆内存 仅释放
malloc/calloc/realloc开辟的内存栈变量、全局数组、字符串常量地址绝对不能 free,行为未定义,极易崩溃 -
传 NULL 安全无害
free(NULL);函数直接空运行,啥也不做,不会报错 -
不能重复释放同一块内存同一块内存 free 两次 → 内存错乱、程序崩溃
-
释放后原指针变成野指针free 完指针变量本身还存着旧地址,但内存已不属于你,再读写就是非法访问
六、标准规范写法
// 1. 申请
int *p = malloc(10 * sizeof(int));
// 2. 使用内存
p[0] = 100;
// 3. 释放
free(p);
// 4. 必做:指针置空,杜绝野指针
p = NULL;
七、高频注意事项
- 局部函数内 malloc,一定要在同层级 / 外部及时 free ,不然造成内存泄漏
- 结构体、嵌套指针,要逐层释放,不能只释放外层
- 单片机小型裸机系统内存管理简单,少频繁 malloc/free,容易内存碎片
- 函数返回动态内存,调用者必须负责 free
八、一句话总结
free 专门归还堆内存;只放动态地址、不放栈 / 常量地址;空指针随便放;释放立刻置空,不重复释放。
灵魂提问 :
如果有两个指针同时指向同一片内存,我free一个后,会发生什么?
灵魂答案:一个 free 了,另一个直接变成 "野指针",极其危险!
我用最简单、最直白的话给你讲透,这是 C 语言最容易死机的坑!
一、举个例子(你一看就懂)
// 1. 申请一块内存
int *p1 = malloc(100);
// 2. 第二个指针也指向这块内存
int *p2 = p1;
// 3. 释放其中一个
free(p1);
现在发生了什么?
- 内存已经被回收了 → 还给系统了
- p1 变成野指针
- p2 也变成野指针(和 p1 一模一样)
二、你现在用 p2 会怎样?
free(p1);
*p2 = 123; // ❌ 致命!程序崩溃、死机
int a = *p2; // ❌ 读取非法内存,数据乱码
free 谁都一样,只要 free 一次,这块内存就作废了! 两个指针同时作废!
三、最重要的 3 个事实
1. free 是释放内存,不是释放指针
- 不是把 p1 删掉
- 是把p1 指向的那片内存回收掉
2. 所有指向这块内存的指针,都会同时失效
不管有 1 个、2 个、10 个指针指向它只要 free 一次,全部变成野指针!
3. 绝对不能再 free 第二次
free(p1);
free(p2); // ❌ 重复 free → 直接崩溃
四、正确做法(必须记住)
方法 1:只 free 一次,然后全部置空
free(p1);
p1 = NULL;
p2 = NULL;
方法 2:永远只保留一个 "所有者" 指针
不要随便让多个指针指向同一块动态内存,非常容易 double free 或野指针。
最终总结(超级重要)
两个指针指向同一块内存:
- free 其中任何一个 ,内存就没了
- 另一个指针变成野指针
- 不能再读写、不能再 free
- 最好全部手动置 NULL