C语言-动态内存管理

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

在初入C语言时,用数组就可以开辟一个我们需要的空间大小。那为什么要使用动态内存的形式来管理空间呢?直到我碰到编写通讯录这个任务时,我突然感觉数组对于未知开辟空间大小的任务来说有些疲软了。开辟空间大了,浪费空间;开辟空间小了,会越界。不能灵活的随着需要的数据去开辟对应大小的空间。

动态内存管理可以方便的解决这种问题,当需要输入新数据时,可以在堆区中开辟对应类型的空间大小去储存数据。当不需要的时候,可以释放这个空间。使用起来十分顺畅。

接下就要介绍开辟空间的函数:malloc和calloc函数。(调用库为<stdlib.h>)

为了方便讲解,释放空间函数不会在上面3个例子中出现。

在这里先强调一点,空间申请完不用后,一定要释放,并且释放后要把指向该空间的指针置为NULL。就像去开车一样,开完车门不关,出事的概率有多大,问题多严重???所以一定要释放空间,指针置NULL

1.malloc函数

malloc函数只有一个参数,参数表示需要开辟空间的字节数,参数类型为size_t(无符号整形)。

返回值为void类型的指针,指针指向开辟空间的地址。(空间开辟失败返回NULL)

下面为malloc函数使用案例:

//void* malloc(size_t size)
#include<stdlib.h>
int main()
{
    int* p1 = (int*)malloc(4);//开辟一个四字节的空间,由于malloc函数返回指针类型为void,需要(int*)进行强制类型转化。
    int* p2 = (int*)malloc(sizeof(int));//开辟一个int类型大小(4字节)的空间,左右两边指针类型不一致,需要(int*)强制类型转换
    return 0;
}

2.calloc函数

calloc函数有两个参数,第一个参数表示需要开辟几个元素的空间,参数类型为size_t(无符号整形)。第二个参数表示一个元素的空间大小,参数类型为size_t(无符号整形)。

返回值为void类型的指针,指针指向开辟空间的地址。(空间开辟失败返回NULL)

下面为calloc函数使用案例:

//void* calloc(size_t num, size_t size)
#include<stdlib.h>
int main()
{
    int* p1 = (int*)calloc(2, 4);//开辟两个四字节的空间,由于calloc函数返回指针类型为void,需要(int*)进行强制类型转化。
    int* p2 = (int*)calloc(2, sizeof(int));//开辟两个int类型大小(4字节)的空间,左右两边指针类型不一致,需要(int*)强制类型转换
    
    return 0;
}

malloc函数和calloc函数的区别:malloc函数不会对申请的空间进行初始化为0,calloc函数会对申请空间进行初始化为0。

下面为两个函数开辟空间内容的截图:

(1)malloc:

(2)calloc

那上面两个开辟的空间不就和数组一样是固定的吗?不着急,下面就是动态内存管理的重点了。

用于调整申请空间的函数:realloc函数。

如果感觉申请的空间大了或者小了,都可以用realloc函数对其进行调整。调整方式可能和你想象的不一样。因为编译器不同,调整方式也有区别。

在VS2019的x86编译器下:如果调整空间比原空间大,原先的空间后面无法再开辟需要的空间,realloc函数会重新开辟一个符合要求的空间,并返回该空间的地址。当然,你的数据依旧会按照原先空间排列的顺序存储在新空间中。如果调整空间小于等于原空间,返回空间的地址不会变。

在VS2019的x64编译器下:无论是开辟多大的空间,只要使用realloc函数,它便会在堆区开辟一块新的且符合要求的空间,并返回该空间的地址。之前申请的空间内容不会变。如果调整空间比原空间大,realloc函数会重新开辟一个符合要求的空间,并返回该空间的地址。当然,你的数据依旧会按照原先空间排列的顺序存储在新空间中。如果调整空间小于等于原空间,realloc函数会重新开辟一个符合要求的空间,并返回该空间的地址。该空间所有数据与原空间从头开始对应的数据一致,直到新空间结束(也就是原空间从头开始拿数据塞到新空间中,到后面塞不进新空间的数据,从新开辟的空间来看,这部分数据丢失了)。

3.realloc函数

realloc函数拥有两个参数,一个为void类型的指针(指向需要调整申请空间的指针),一个为调整后的空间大小(也就是多少字节数),类型为size_t 。

返回类型为void类型的指针,指针指向开辟空间的地址。(空间开辟失败返回NULL)。

下面为realloc函数使用案例(基于VS2019的x64编译器):

//void *realloc( void *memblock, size_t size );

#include<stdlib.h>
#include<stdio.h>
int main()
{
    int* p1 = (int*)calloc(2, sizeof(int));
    *p1 = 0xFFFFFFFF;
    *(p1 + 1) = 0xFFFFFFFE;
    p1 = (int*)realloc(p1, sizeof(int)*4);//p1指向的空间需要调整空间大小为4个4字节(int类型大小)
    *(p1 + 2) = 0xFFFFFFFD;
    *(p1 + 3) = 0xFFFFFFFC;
    p1 = (int*)realloc(p1, sizeof(int)*2);//p1指向的空间需要调整空间大小为2个4字节(int类型大小)
    printf("%d", *(p1 + 1));
    return 0;
}

(1)calloc函数开辟空间

 第一次通过calloc开辟空间,并且将数据放进去,为了后面好观测其变化。第一次通过calloc函数开辟得到的空间首地址为0x0000 0224 F9FB F460(为了方便观测地址变化,将其进行分割)。

(2)realloc函数第一次开辟空间

 第一次通过realloc函数对p1指针指向的空间进行空间调整,空间调整为4个int类型大小的空间(16字节),并且继续往后存放数据。可以看到在x64编译器下,地址发生了变化(在x86编译器下尝试时,地址没变)。地址为0x0000 0224 F9FB F780。

(3)realloc函数第二次开辟空间

 第二次通过realloc函数对p1指针指向的空间进行空间调整,空间调整为2个int类型大小的空间(8字节)。可以看到在x64编译器下,地址发生了变化(在x86编译器下尝试时,这里的地址也没变)。地址为0x0000 0224 F9FB F690。观察上面的地址存放的数据可以发现,数据搬移只过来8字节的数据,后面的数据在新空间中都丢失了。

最后,讲的是如何对动态开辟的空间进行释放。这里就要提到上面一直强调的释放函数free。

4.free函数

realloc函数只有一个参数,参数为void类型的指针(指向需要释放动态内存空间的指针)。没有返回值。

//void free( void *memblock );

#include<stdlib.h>
#include<stdio.h>
int main()
{
    int* p1 = (int*)calloc(2, sizeof(int));
    *p1 = 0xFFFFFFFF;
    *(p1 + 1) = 0xFFFFFFFE;
    p1 = (int*)realloc(p1, sizeof(int) * 4);
    *(p1 + 2) = 0xFFFFFFFD;
    *(p1 + 3) = 0xFFFFFFFC;
    p1 = (int*)realloc(p1, sizeof(int) * 2);
    

    free(p1);//释放p1指向地址的空间(动态开辟的空间)
    p1 = NULL;//让p1指针指向NULL,不然p1会变成野指针
    return 0;
}

为什么p1要指向NULL?因为开辟内存相当于拥有钥匙,属于合法使用。当开辟的空间释放完,相当于非法占用钥匙,钥匙是需要归还的。当指针不知道指向什么地址时,指向NULL。

以上是对动态内存的初步介绍。

如果有不当之处,请大佬指正。

  • 18
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 26
    评论
C语言-学生信息管理系统是一个基于链表数据结构的学生信息管理系统。链表是一种数据结构,可以存储和管理一系列具有相同类型的数据。在学生信息管理系统中,链表被用来存储和操作学生的基本信息。 该系统主要有以下功能: 1. 添加学生信息:可以添加学生的姓名、学号、性别、年龄等信息,并将该学生的信息节点插入到链表中。 2. 删除学生信息:根据学号或其他关键词查找到对应的学生信息节点,并从链表中删除该节点。 3. 修改学生信息:根据学号或其他关键词查找到对应的学生信息节点,并根据需求修改学生的信息。 4. 查询学生信息:可以根据学号或其他关键词查找到对应的学生信息节点,并显示该学生的详细信息。 5. 遍历学生信息:可以遍历整个链表,显示所有学生的基本信息。 链表的优势在于插入和删除节点的操作比较高效,因为只需要改变节点的指针指向即可,不需要移动其他节点。而数组在插入和删除操作时需要移动其他元素,效率较低。 在实现学生信息管理系统时,可以使用指针来操作链表,通过指针的指向找到链表的某个节点,并进行相应的操作。同时,需要注意对内存管理,确保动态分配和释放内存的正确性,避免内存泄漏和访问错误。 总之,C语言-学生信息管理系统是一个基于链表数据结构的系统,可以实现学生信息的增删改查等功能。通过灵活运用链表的特点,可以高效地管理学生的基本信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值