C语言 char

知识点一:常量字符串

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 会:

  1. 新找一块足够大的内存

  2. 把旧数据全部拷贝过去

  3. 自动把旧的内存 free 掉

  4. 返回新的地址

    旧:[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,**函数直接空运行,啥也不做,不会报错

四、核心作用

  1. 把堆区动态申请的内存还给操作系统 / 内存管理器
  2. 释放后这块内存不再受当前程序管控,可被重新分配
  3. 不会自动清零内存原有数据,原数据暂时还在

五、使用规则

  1. 只能释放堆内存 仅释放 malloc / calloc / realloc 开辟的内存栈变量、全局数组、字符串常量地址绝对不能 free,行为未定义,极易崩溃

  2. 传 NULL 安全无害 free(NULL); 函数直接空运行,啥也不做,不会报错

  3. 不能重复释放同一块内存同一块内存 free 两次 → 内存错乱、程序崩溃

  4. 释放后原指针变成野指针free 完指针变量本身还存着旧地址,但内存已不属于你,再读写就是非法访问

六、标准规范写法

复制代码
// 1. 申请
int *p = malloc(10 * sizeof(int));

// 2. 使用内存
p[0] = 100;

// 3. 释放
free(p);

// 4. 必做:指针置空,杜绝野指针
p = NULL;

七、高频注意事项

  1. 局部函数内 malloc,一定要在同层级 / 外部及时 free ,不然造成内存泄漏
  2. 结构体、嵌套指针,要逐层释放,不能只释放外层
  3. 单片机小型裸机系统内存管理简单,少频繁 malloc/free,容易内存碎片
  4. 函数返回动态内存,调用者必须负责 free

八、一句话总结

free 专门归还堆内存;只放动态地址、不放栈 / 常量地址;空指针随便放;释放立刻置空,不重复释放。

灵魂提问 :

如果有两个指针同时指向同一片内存,我free一个后,会发生什么?

灵魂答案:一个 free 了,另一个直接变成 "野指针",极其危险!

我用最简单、最直白的话给你讲透,这是 C 语言最容易死机的坑!


一、举个例子(你一看就懂)

复制代码
// 1. 申请一块内存
int *p1 = malloc(100);

// 2. 第二个指针也指向这块内存
int *p2 = p1;

// 3. 释放其中一个
free(p1);

现在发生了什么?

  1. 内存已经被回收了 → 还给系统了
  2. p1 变成野指针
  3. 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 或野指针。


最终总结(超级重要)

两个指针指向同一块内存:

  1. free 其中任何一个 ,内存就没了
  2. 另一个指针变成野指针
  3. 不能再读写、不能再 free
  4. 最好全部手动置 NULL
相关推荐
学逆向的2 小时前
C 堆区内存管理
c语言·开发语言·网络安全
阿尼卡~4 小时前
VS Code 配置 C 语言开发环境(Windows 10/11):从 GCC 安装到运行、断点调试,一篇搞定
c语言·开发语言·windows
从小白到软工13 小时前
5-2 从查表到控件:造按钮
c语言·开发语言·数据结构·经验分享·ai编程
水饺编程13 小时前
第2章:Linux 基础,解压缩【.tar.gz】压缩包
linux·c语言·汇编
cu14313 小时前
细谈IT6653的具体功能与其应用
c语言·c++·单片机·嵌入式硬件
夏虫不可与之言冰14 小时前
RMT 与 WS2812 灯带:可寻址 RGB 全彩控制
c语言·c++·单片机·物联网·visual studio
羊锦磊14 小时前
嵌入式基础1
c语言·c++·gnu
唐青枫14 小时前
C 语言 calloc() 详解:零初始化、动态数组与内存管理实战
c语言
David猪大卫15 小时前
【C++修炼】STL容器—stack与queue
c语言·开发语言·数据结构·c++·经验分享·笔记·学习
瑶池酒剑仙15 小时前
C++变量初始化五法完全指南:默认/拷贝/直接/列表/值初始化与窄化转换陷阱(青云之志)
c语言·开发语言·数据结构·c++·算法·visual studio