C语言之动态内存管理

在开始对动态内存管理讲解之前,我们先想一想这两个问题:

一.什么是动态内存管理:

所谓动态内存管理,就是指在程序执行的过程中,由程序员动态地申请和回收内存空间。动态内存管理不像变量(例如数组)那样在程序编译时预先分配内存空间,而是根据程序的需要时进行即时分配,而且分配的内存大小由程序员自己去决定

二.为什么存在动态内存管理:

因为平时我们创建的变量或者数组的空间开辟大小是固定的,但有时我们并不知道我们究竟需要多大的空间,上述的方法就不能满足我们对空间的需求了,只能尝试动态开辟了

我相信在讲解完这两个问题之后,大家对动态内存管理有了一定的了解了,言归正传,我们开始学习今天的主要内容

三.动态内存函数的介绍:

3.1malloc和free:

malloc:void *malloc( size_t size )

这个函数的功能是向内存申请一块连续可用的空间,并且返回指向这块空间的指针

注意事项:

a.如果开辟成功,则返回一个指向开辟好的空间的指针

b.如果开辟失败,则返回一个NULL指针,因此在用malloc时要检查返回值,否则可能会对空指针进行解引用

c.返回值类型是void*类型,所以malloc并不知道要开辟空间的类型,这个类型要由使用者自己决定

d.如果参数size为0,这种情况是C语言没有定义的,能不能开辟成功取决于编译器(博主用的是vs2019,可以成功,但是不能用这块空间,就没啥用)

free:void free( void *memblock )

这个函数的功能是释放动态开辟的内存(注意一定是动态开辟的)

注意事项:

a.如果参数memblock指向的空间不是动态开辟的,会报错

b.如果参数memblock是NULL指针,该函数什么也不做

3.2calloc:

calloc:void *calloc( size_t num, size_t size )

该函数的功能是:为num个大小为size的元素开辟一块空间,并且把开辟的空间的每个字节都初始化为0,除了初始化为0的功能,其他和malloc差不多

3.3realloc:

realloc:void *realloc( void *memblock, size_t size )

realloc函数的出现,让动态内存管理更加灵活,有时候我们发现我们第一次动态开辟的内存不够大或者开辟得过大了,这时候我们就需要调整,而realloc函数就能实现这样的功能

注意事项:

a.参数memblock是要调整的内存的地址

b.参数size是要调整之后的新大小

c.返回值为调整之后的起始地址

在使用这个函数的时候有两个细节需要注意:

3.3.1原有空间之后有足够大的空间:

情况1:要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化

3.3.2原有空间之后没有足够大的空间:
情况2:原有空间之后没有足够多的空间时,扩展的方法是:在堆区上另找一个合适大小
的连续空间来使用,此时函数返回的是一个新的内存地址

C语言之动态内存管理_第1张图片

在介绍完动态内存管理的相关函数之后,为了预防大家在使用的时候出错,博主这里写了几个常见的错误,给大家排排雷 

4.常见的动态内存错误:

4.1对NULL指针的解引用:

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
int main()
{
	int* p = (int*)malloc(INT_MAX);//当开辟的空间过大,会开辟失败
	*p = 20;//在vs2019的编译器下,会出现一个警告:取消对空指针的解引用
	free(p);
	p = NULL;
    return 0;
}

解决方法就是:对动态开辟空间的函数的返回值p进行一个判NULL操作 

4.2 对动态开辟的空间的越界访问:

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
int main()
{
	int* p = (int*)malloc(100);
	if (p == NULL)
	{
		return 1;
	}
	int i = 0;
	for (i; i <= 25; i++)
	{
		*(p+i) = i;
	}
	free(p);
	p = NULL;
    return 0;
}

这里我们开辟了100个字节的大小的空间,而每个元素的类型为int,所以只有25个元素,而后面我们却访问了26个元素,这样就形成了越界访问 不属于自己的内存

 解决方法:对边界进行检查,不要超过边界去访问和使用不属于自己开辟的内存了

 4.3对非动态开辟内存使用free释放:

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
int main()
{
	int a = 10;
	int* p = &a;
	free(p);
	p = NULL;
	return 0;
}

解决方法:只对动态开辟的空间去释放,我们不用关心

4.4使用free释放一块动态开辟内存的一部分:

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
int main()
{
	int* p = (int*)malloc(100);
	if (p == NULL)
	{
		return 1;
	}
	int i = 0;
	for (i; i < 15; i++)
	{
		*p = i;
		p++;
	}
	free(p);
	p = NULL;
	return 0;
}

这里我们看见每次给开辟的空间放值时,p的指向都会改变,到最后已经不在指向该空间的起始地址了,这时候去释放就会报错 

解决方法:必须从动态开辟内存的起始地址,不能从中间的地址去释放,可以通过创建临时变量去放值,或者不改变p的指向的方法

4.5对同一块动态内存多次释放: 

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
int main()
{
	int* p = (int*)malloc(100);
	if (p == NULL)
	{
		return 1;
	}
    //……
	free(p);
	//……
	free(p);//error
	p = NULL;
}

以上就是在使用动态开辟的函数可能会出现的错误,希望能对大家有所帮助

今天分享的动态内存管理的相关知识就到这里了,希望能让大家受益匪浅,请大家三连一波,后续会有更多的只是分享

这是博主的gitee链接:code_C语言: 专门用于存放C语言的代码 (gitee.com),大家可以在这里看C语言编程题的解答方法,欢迎大家来看。

你可能感兴趣的:(C语言,c语言)