C语言动态内存 + 柔性数组 + 数组名退化

C语言动态内存 + 柔性数组 + 数组名退化

一、动态内存核心函数

  1. malloc(size_t size)
  • 在堆区申请连续内存,返回 void* 地址;申请失败返回 NULL
  • 模板:

int p = (int )malloc(sizeof(int)*5);//两个地方强制类型转化

// ✅ 必须判空

if(p == NULL)

{

perror("malloc fail");//这个是打印错误的原因

return -1; //异常退出

}

// 使用内存

free§; // 释放堆内存

p = NULL; // 置空,防止野指针!

固定流程:申请 → NULL判断 → 使用 → free → 指针置NULL

  1. calloc(n, size) :申请n个大小为size的空间,自动初始化为0 //这个比maloc多一个初始化为0
  2. realloc(p, new_size) :扩容/缩容原有堆内存,会自动拷贝旧数据(它会复制原来的加后面要拷贝的)

⚠️重点: free 只是归还内存给操作系统,不会把p本身清空,p依旧存旧地址 → 野指针//所以后面还要重新赋值NULL

二、野指针

定义:指针存了一块已经释放/非法、不受程序管控的内存地址

产生原因:

① free之后没有把指针赋值NULL

② 未初始化的局部指针变量

③ 越界访问后指针指向非法区域

风险:随机崩溃、程序玄学bug,很难排查

三、数组名什么时候不会退化(3种特例,其余全部退化成首元素地址)

  1. sizeof(数组名) :得到整个数组总字节数,不退化
  2. &数组名 :取出整个数组的地址(数组指针,类型和首元素地址不一样),不退化
  3. 字符串字面量初始化数组: char arr\[\] = "hello"; ,不退化

其余所有场景:数组名 → 首元素地址

注意:scanf的时候,只有arr不用&,arr\[\],arr\[\]\[\]这些都要&

四、柔性数组(结构体最后一个成员未知)

它不是arr\[\]={}这种东西,因为这个省略写法的大小已经知道了,柔性数组的大小本身就是未知的,也不占内存

写法:结构体末尾 int arr\[\]; 或者 int arr0;

✅规则

  1. 结构体里最后一个成员,不能有大小
  2. 结构体本身不分配数组内存,需要一次malloc申请【结构体大小 + 数组需要的空间】
  3. 内存整块连续,只需要一次free,相比结构体里 int *arr 优势:减少内存碎片

示例:

c

struct test

{

int num;

int arr\[\]; //柔性数组,不占结构体大小

};

//一次性申请结构体+数组空间

struct test p = (struct test )malloc(sizeof(struct test)+sizeof(int)*10);

if(p == NULL) return -1;

p->num = 10;

p->arr0 = 100;

free§;

p=NULL;

对比: int *arr 是指针,占8字节(64位),需要两次malloc、两次free,内存不连续。

配套经典题型(带考点)

题型1 动态内存标准模板(默写题)

题目:申请能存放5个int的堆内存,写入数据,释放。要求包含判空、置NULL。

c

#include<stdio.h>

#include<stdlib.h>

int main(void)

{

int p = (int )malloc(sizeof(int)*5);//这里使用指针变量去承载动态内存

if(p == NULL)

{

perror("malloc");

return 1;

}

for(int i=0;i<5;i++)

{

pi = i;

}

free§;

p = NULL;

return 0;

}

考点:忘记判空 / free后不置NULL产生野指针

题型2 数组名退化选择题

c

char arr\[\] = "abcd";

printf("%zd", sizeof(arr));

printf("%p", &arr);

//printf和scanf是不一样的

问:sizeof(arr)输出?&arr是什么类型?

答案:5字节(后面有一个\0);&arr是整个数组的地址(char(*)5数组指针)

考点:数组名两大不退化场景

题型3 柔性数组基础题

c

struct S

{

int n;

int arr\[\];

};

struct S ps = malloc(sizeof(struct S)+5sizeof(int));

问:malloc申请的内存包含哪两部分?释放时free几次?

答案:结构体int n + 5个int数组;只free一次

题型4 野指针判断题

c

int *p = malloc(4);

free§;

*p = 10;

问题:代码错在哪?

答案:free之后p变成野指针,解引用*p属于非法访问;free后必须 p=NULL;

题型5 易错对比:结构体指针成员 VS 柔性数组

c

//版本A:柔性数组

struct A{

int cnt;

int data\[\];

};

//版本B:普通指针成员

struct B{

int cnt;

int *data;

};

考点:A一次malloc、一次free,内存连续;(柔性数组本身就不用内存,内存直接给结构体就可以了)

B要两次malloc两次free,容易内存泄漏(结构体本身有一块内存,指针变量本生也有一块内存,两块内存要分别malloc和free)

相关推荐
上海潭龙东海科技有限公司16 分钟前
客运站管控之动态孪生技术方案(新增一屏管控模块
数据仓库·人工智能·算法·重构·动态规划
YLCHUP3 小时前
【思维&图论建模】题解:债权(debt)_图论_建模_思路转化_思维题目_C++算法竞赛
c++·笔记·算法·数学建模·贪心算法·深度优先·图论
思麟呀3 小时前
背包DP(01背包+完全背包)
c++·算法
Zwawa4 小时前
让屏幕动起来:OLED动画效果,丝滑光标、帧动画和一只贪吃蛇
c语言·单片机·嵌入式
笑容掩饰我的失落4 小时前
区块链从小白到精通(七):Solidity 语法精讲——数据类型、函数、修饰器与事件
算法·区块链·php·智能合约·哈希算法
Pniubi5 小时前
力扣24. 两两交换链表中的节点(递归)
算法·leetcode·链表
꧁细听勿语情꧂6 小时前
直接选择排序,堆排序,冒泡排序,递归快速排序、hoare版本、挖坑法、lomuto前后指针,非递归快速排序
c语言·开发语言·数据结构·算法
俊俊几年的6 小时前
动态规划(Dynamic Programming)详解:从入门到 LeetCode Hot 100
linux·c++·算法·leetcode·嵌入式·动态规划·c
小雉系统15 小时前
BcoreOS安全通信架构:FsSession 抗算法后门安全设计
算法·安全·架构