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语言·经验分享·青少年编程·课程设计
消失的旧时光-19432 小时前
C 语言如何实现“面向对象”?—— 从 struct + 函数指针,到 Linux 内核设计思想
linux·c语言·开发语言
handler012 小时前
滑动窗口(同向双指针)算法:模板与例题解析
c语言·c++·笔记·算法·蓝桥杯·双指针·滑动窗口
薇茗3 小时前
【初阶数据结构】 升沉有序的平仄 排序
c语言·数据结构·算法·排序算法
yoyo_zzm3 小时前
五大编程语言对比:PHP、C、C++、C#、易语言
c语言·c++·php
铅笔小新z4 小时前
【C语言】数组详解
c语言·开发语言
努力努力再努力wz4 小时前
【Redis入门系列】Redis基础命令详解:从客户端连接到数据读写、key 管理与过期机制
c语言·开发语言·数据结构·数据库·c++·redis·缓存
谙弆悕博士4 小时前
【附C源码】C语言实现散列表
c语言·开发语言·数据结构·算法·散列表·数据结构与算法
Lucky_ldy4 小时前
C语言学习:自定义类型-结构体
c语言·开发语言·学习