C-动态内存管理-动态内存管理

发布时间:2025-06-24 14:08:50  作者:北方职教升学中心  阅读量:472


目录。

为什么要有动态内存管理?

二、malloc和free。

(2.1)malloc。

(2.2.#xfff09;free。

三、calloc和realloc。

(3.1)calloc。

(3.2)realloc。

四、动态内存常见错误(例子都是错误的演示)

(4.1)对空指针的解引操作。

(4.2󿼉越界访问动态开放空间。

(4.3)free用于非动态开发内存。

(4.4󿼉使用free释放动态开放内存的一部分。

(4.5󿼉多次freee地打开同一块动态内存。

(4.6󿼉忘记释放动态开启内存(内存泄漏)

五、动态内存经典笔试题分析。

(5.1)题目1。

(5.2)题目2。

(5.3)题目3。

(5.4)题目4。

六、柔性数组。

(6.1󿼉柔性数组的特点。

(6.2󿼉柔性数组的优点。

七、总结C//C++中程序内存区域划分。


为什么要有动态内存管理?

正常情况下,我们可以在栈上创建一个变量或数组来打开空间,例如:

但上述开放空间的开放空间⽅有两个特点:

• 空间开辟⼤⼩是固定的。
• 数组在申报时,必须指定数组⻓度,数组空间⼀旦确定了⼤⼩不能调整。

但是对空间的需求,不仅仅是上述情况。有时我们需要的空间⼤⼩在程序运⾏只有这样才能知道。
道,当编译数组时,打开空间⽅式就不能满⾜了。C语⾔引⼊开发动态内存,让程序员⾃⼰可以申请和释放空间,就⽐较灵活了。

二、malloc和free。

(2.1)malloc。

C语⾔提供了⼀一个动态内存开辟函数,以下:(该函数在头文件中包含stdlibib.h里)

向内存申请此函数⼀块连续可⽤空间,并返回指向这个空间的指针。具有以下特点:

• 如果开放成功󿀌则返回⼀指向开放空间的指针。
• 如果开启失败󿀌则返回⼀个 NULL 指针,因此,malloc的返回值⼀一定要做检查。                              • 返回值的类型是 void* ,因此,malloc函数不知道开放空间的类型,具体在使⽤的时候使⽤者⾃。
⼰来决定。
• 如果参数 size 0,malloc⾏标准是未定义的,这取决于编译器。

例如,如今,我们想开辟一个存储int类型数据的空间:

(2.2#xff09;free。

C语⾔提供了另外⼀函数free,专⻔是⽤释放和回收动态内存,函数原型如下༚

free函数⽤释放动态开放的内存。xff1具有以下特点a;

• 如果参数 ptr 指向空间不是动态开放的,那free函数⾏为未定义。     。

• 如果参数 ptr NULL指针༌函数什么都不做。

freee和malloc一样󿼌都声明在 stdlib.h 头⽂件中。

例如:

运行效果:

三、calloc和realloc。

(3.1)calloc。

C语⾔还提供了⼀个函数叫 calloc , calloc 函数也⽤动态内存分配。原型如下:

该函数的特性:

• 函数的功能是 num 个⼤⼩为 size 的元素开辟⼀块空间,并将空间的每个字节初始化为0。 。

• 与函数 malloc 区别只在于 calloc 申请空间的每个字节将在返回地址之前初始化为0。

例子:

运行效果:

因此,如果我们要求初始化应用内存空间的内容,那么可以很⽅便的使⽤calloc函数完成任务。

(3.2)realloc。

函数原型如下༚

该函数具有以下特点a;

• realloc函数的出现使得动态内存管理更加灵活。
• 有时候我们会发现过去申请的空间太大了⼩,有时候我们⼜你会觉得申请空间太大了⼤,在合理的时间内存,我们⼀会对内存进行记忆⼤⼩灵活调整。那 realloc 函数可以为动态开启内存⼤⼩的调整。
 。

• ptr 内存地址需要调整。
• size  调整后的新⼤⼩。
• 返回值是调整后内存的起始位置。
• 这个函数调整了原内存空间⼤⼩࿰的基础c;将原始内存中的数据移动到一个新的空间。

• Realloc在调整内存空间时有两种情况:
◦ 情况1:后面有原始空间⾜够⼤的空间。
◦ 情况2༚之后没有原有的空间⾜够⼤的空间。

如图:

情况1的时候,要扩展内存,直接在原始内存后添加空间,没有发送原始空间数据⽣变化。当情况为2时,之后没有原有的空间⾜空间充足的时间,扩展的⽅法是:另找堆空间⼀个合适⼤⼩使用连续空间⽤,将原始空间数据复制到新空间󿼌并释放原始空间。函数返回是这样的⼀新的内存地址。由于上述两种情况,realloc函数使⽤就要注意⼀些。例子:

四、动态内存常见错误(例子都是错误的演示)

(4.1)对空指针的解引操作。

例如:

(4.2󿼉越界访问动态开放空间。

(4.3)freee用于非动态开放内存。

(4.4󿼉使用free释放动态开放内存的一部分。

(4.5󿼉多次freee地打开同一块动态内存。

(4.6󿼉忘记释放动态开启内存(内存泄漏)

忘记释放不再使用⽤动态开放空间会导致内存泄漏。
记住:动态开放空间⼀必须释放,并正确释放。

五、动态内存经典笔试题分析。

(5.1)题目1。

运行结果:

从上述操作结果可以看出,程序已经崩溃。

说明:

通过调试可以发现,作为函数GetMemory的参数,指针str没有传递地址,因此,形参的变化不会影响实参,即p的变化不会影响str,函数结束时,str仍然空,因此,在调用strcpy函数时会报错。

(5.2)题目2。

运行效果:

说明:随着函数的结束,Getmemory函数中开放的数组空间将被销毁,虽然地址已经返回,但是空间已经销毁了,此时,使用str访问这个空间,内容是随机的。

(5.3)题目3。

运行效果:

说明:随着函数的结束,动态开放的空间不会被销毁,在Test中,将Str的地址传输到Getmemory函数,因此,形参可以影响实参,也就是说,str指向malloc申请的空间,因此,strcpy函数可以正常使用,打印没有问题,但是这里忘记释放动态开放的空间,会导致内存泄漏。

(5.4)题目4。

(5.4)题目4.

运行效果:说明:

虽然这里打印成功󿀌但是这个代码有问题,str指向的空间已被释放,但是free函数不会空指针,所以这里有一个被销毁的空间。

六、柔性数组。

C99中󿀌结构的最后⼀未知允许个元素⼤⼩数组,这就叫做『柔性数组』成员。例如:

有些编译器会报错⽆法编译可以改为:

(6.1󿼉柔性数组的特点。
• 结构中的柔性数组成员⾯必须⾄少⼀其他成员。
• sizeof 返回的结构⼤⼩不包括柔性数组的内存。

• 结构包含柔性数组成员⽤malloc()函数进⾏内存动态分配,而且应该分配内存⼤于结构的⼤⼩,适应柔性数组的预期⼤⼩。

例如:

代码1:

(6.2󿼉柔性数组的优点。

上述的 type_a 结构也可以设计为下⾯结构,同样的效果也可以完成。

代码2:

上述代码1和代码2 可完成相同的功能,但是⽅法1的实现有两个好处:
第⼀好处是:⽅大便内存释放。

假如我们的代码在那里⼀个给别⼈⽤￰在函数中c;你在⾥⾯做了⼆二次内存分配󿀌并将整个结构返还给它⽤⼾。⽤⼾调⽤free可以释放结构体,但是⽤⼾我不知道这个结构中的成员也需要free,所以你不能指望⽤⼾发现这件事。所以,如果我们把结构的内存和成员想要的内存放在一起⼀次性分配,并返回给⽤⼾⼀个体结构指针,⽤⼾做⼀次free可以释放所有内存。
第⼆好处是:这有利于访问速度。

连续内存有利于提升⾼访问速度,也有助于减少内存碎片⽚。

七、总结C//C++中程序内存区域划分。
C/C++程序内存分配⼏各区域:
1. 栈区(stack):在执⾏函数时,函数中的局部变量存储单元可以在栈上创建,函数执⾏这些存储单元在结束时⾃动被释放。堆栈内存分配操作中处理器内置的指令集中,效率很⾼,但内存容量的分配是有限的。栈区主要存放运输⾏函数⽽局部变量、函数参数、返回数据、返回地址等。
2. 堆区(heap):⼀程序员通常会分配和释放#xff0c;如果程序员不释放󿀌OS可以在程序结束时回收。分配⽅。
类似链表的类型。

3. #xff08数据段;#xfff09;(static)存储全局变量和静态数据。系统在程序完成后释放。                      4. 代码段:存储函数体(类成员函数和全球函数)的⼆进制代码。