C语言第23讲

动态内存管理

复制代码
int n = 10;                 int arr[20];
char c = 'W';               char ch[20];

一个元素 一片空间,上面两种一旦申请成功,空间大小就无法调整

动态内存,是可以根据情况进行内存大小修改的

下面是4个内存函数

malloc

free

calloc

realloc

4个函数头文件都是 <stdlib.h>

4个函数所操控的空间都在堆区上

malloc

malloc的原型:

void* malloc(size_t size)

size 为你要想申请的空间大小,单位为字节

void* 这个函数向内存申请一块联系可用的空间,

成功返回这片空间的起始位置

失败返回 NULL

free

free的原型:

void free (void* ptr)

ptr为你向释放空间的起始地址

如果传参为 NULL free函数什么也不会做

专门用来做动态内存的释放和回收的,如果不释放,程序在运行时这片内存一直是你的

free(p); free释放了p指向的空间后p会成为野指针,所以要尽早赋值 NULL

p = NULL;

calloc

calloc的原型:

void * calloc(size_t num, size_t size);

作用:为 num 个大小 size 的元素开辟一片空间,并且把空间的每个字节初始化为0

calloc 和 malloc 的区别点就两

1.原型传参的不同

2.calloc多了给空间初始化的功能

realloc

realloc的原型:

void realloc (void* ptr, size_t size)

void* 为申请调节空间的起始地址

size 为准备申请调整成 size 大的空间,大小为字节

realloc 是动态内存的关键

realloc 在开辟空间会有3种情况:

1.调整失败返回 NULL

所以,常常在使用玩后会追加判断,以避免使用 realloc 后返回NULL

2.3.情况如图

2.为连续空间开辟 后续空间足够

3.为连续空间开辟 后续空间不足

情况3 .会在空间中再找一块足够的内存空间,将原来空间的数据拷贝一份到新的空间,然后释放旧的空间,返回新的空间起始位置

有类写法,可以将 realloc 的作用和 malloc 一样

复制代码
realloc(NULL,20);  等于   malloc(20);

给 realloc 传NULL,realloc会因为找不到地址,重新开辟一块空间

常见的动态内存错误

1.对NULL指针解引用操作

cpp 复制代码
int *p =(int*)malloc(int_MAX);
*p = 20; // 报错,p有对NULL进行解引用的风险
free(p);
p = NULL;

2.对动态内存开辟空间的越界访问

cpp 复制代码
void test()
 {
 int i = 0;
 int *p = (int *)malloc(10*sizeof(int));
 if(NULL == p)
 {
 exit(EXIT_FAILURE);
 }
 for(i=0; i<=10; i++)
 {
 }
 free(p);
 }

3.对非动态开辟内存使用free

cpp 复制代码
int a = 10;
int* p = &a;
free(p);
P = NULL;

4.使用free释放动态内存空间的一部分

cpp 复制代码
 int *p = (int *)malloc(100);
 p++;
 free(p) // P 已经不是内存的起始位置了

5.对同一块动态内存多次释放

cpp 复制代码
 int *p = (int *)malloc(100);
 free(p);
 free(p);// 重复释放

6.开辟的动态内存忘记释放(内存泄漏)

当程序结束时,内存会由操作系统回收,但有程序7 * 24小时运行(游戏)

cpp 复制代码
void test()
 {
    int *p = (int *)malloc(100);
     if(NULL != p)
     {
         *p = 20;
     }
 }

 int main()
 {
     test();
     while(1);
 }  

问题1:下方代码哪里有问题

cpp 复制代码
void GetMemory(char *p)       // 2.p 为新创建的指针变量 内存中存着 NULL
 {
 p = (char *)malloc(100);     // 3.开辟的内存没有传递过去,也没有释放,导致内存泄漏
 }
 void Test(void)
 {
 char *str = NULL;
 GetMemory(str);              // 1.指针变量 本质还是变量,所以这是传值调用
 strcpy(str, "hello world");  // 4.str 为空指针,对空指针进行解引用导致程序崩溃
 printf(str);
 }

**问题2:**下方代码哪里有问题

cpp 复制代码
char *GetMemory(void)
 {
 char p[] = "hello world";
 return p;
 }
 void Test(void)
 {
 char *str = NULL;
 str = GetMemory();          // 成功返回数组p的地址,但是指针指向的空间已被程序回收 
 printf(str);                // str为野指针 回收的空间内容可能会被覆盖,可能未被覆盖
 }                    

柔性数组:

结构体中的最后一个元素是未知大小的数组,就叫做柔性数组

达成条件:

1.结构体中最后一个数组

2.数组未指定大小

柔性数组的两种写法:

cpp 复制代码
// 1
struct S
{
    int a;
    int arr[];
};

// 2
struct S
{
    int a;
    int arr[0];
}

特点:

1.结构体中柔性数组成员前必须至少有一个其他成员

2.sizeof 在计算结构体内存大小时不会包括柔性数组

3.包含柔性数组成员的结构用malloc函数进行的动态分配,并且分配的内存大小应该大于结构的大小,以适应柔性数组的大小

柔性数组的使用:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>
#include <stdlib.h>

struct S
{
	int a;
	int arr[];
} * p;

int main()
{
	struct S* ptr = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));
	if (ptr == NULL)
	{
		perror("ptr");
		return 1;
	}
	p = ptr;
	ptr = NULL;

	for (int i = 0; i < 10; i++)
		*(p->arr + i) = i;

	for (int i = 0; i < 10; i++)
		printf("%d ", *(p->arr+ i));

	free(p);
	p = NULL;
	return 0;
}
相关推荐
Wenweno0o20 小时前
0基础Go语言Eino框架智能体实战-chatModel
开发语言·后端·golang
小O的算法实验室20 小时前
2026年ASOC,基于深度强化学习的无人机三维复杂环境分层自适应导航规划方法,深度解析+性能实测
算法·无人机·论文复现·智能算法·智能算法改进
chenjingming66621 小时前
jmeter线程组设置以及串行和并行设置
java·开发语言·jmeter
qq_3395548221 小时前
英飞凌ModusToolbox环境搭建
c语言·eclipse
cch891821 小时前
Python主流框架全解析
开发语言·python
不爱吃炸鸡柳21 小时前
C++ STL list 超详细解析:从接口使用到模拟实现
开发语言·c++·list
十五年专注C++开发21 小时前
RTTR: 一款MIT 协议开源的 C++ 运行时反射库
开发语言·c++·反射
Momentary_SixthSense21 小时前
设计模式之工厂模式
java·开发语言·设计模式
‎ദ്ദിᵔ.˛.ᵔ₎21 小时前
STL 栈 队列
开发语言·c++
勿忘,瞬间21 小时前
数据结构—顺序表
java·开发语言