前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【熟视C语言】C语言动态内存管理(malloc,calloc,realloc,free)

【熟视C语言】C语言动态内存管理(malloc,calloc,realloc,free)

作者头像
Crrrush
发布2023-06-23 14:34:04
1850
发布2023-06-23 14:34:04
举报
文章被收录于专栏:后端开发练级指南

写在前面

本篇文章为动态内存函数的使用详解,希望对你的动态内存函数学习有所帮助。

为什么需要使用动态内存

对于初学者来说,最先接触到的内存使用便是以下场景:

代码语言:javascript
复制
//
int val = 3;//为变量val在栈区上申请一块空间存储数据
char str[] = "abc";//为数组str在栈区上申请一块空间存储数据

这样的空间开辟方式,在后续操作中,是无法改变以上数据所占空间大小的,并且对于数组来说,开辟空间是必须指明数组长度的。而在我们实际生活中又确实会出现一组数据量会随时变化的数据组。这时我们就需要使用动态内存函数来为数组,变量来开辟空间。

动态内存函数

(函数声明在头文件stdlib.h中)

mallocfree

malloc是C语言提供的一个开辟动态内存的函数。

代码语言:javascript
复制
void* malloc (size_t size);

这个函数向内存申请一块在堆区上连续可用的空间,并返回指向该空间的指针。

  • 开辟成功会返回指向开辟好的空间的指针,失败则返回NULL指针。
  • 返回值的类型是void*指针,具体使用时只需要对返回的指针进行强制类型转换即可。
  • 在标准中malloc并未对size是0的情况进行规定,具体情况看编译器。

同时,C语言提供另外一个函数free,专门用于释放和回收动态内存。

代码语言:javascript
复制
void free (void* ptr);

free函数接收一个指向一块开辟好的动态内存空间,释放并回收这块J空间。

  • 标准对参数ptr指向的空间不是动态开辟的这个行为并没有做出规定。
  • 如果接收到的ptr是NULL指针,函数不会进行任何操作。
代码语言:javascript
复制
int main()
{
	int n = 10;
	int* array = (int*)malloc(sizeof(int) * n);//开辟n个整型数据大小的连续空间
	if (array == NULL)//检测是否申请失败
	{
		perror("malloc failed");//发出失败提示
		exit(-1);//运行失败,结束程序
	}

	for (int i = 0; i < n; i++)
	{
		array[i] = i;//此时当作数组使用
	}

	free(array);//释放动态内存
	array = NULL;//对该指针置空,防止非法访问内存空间(野指针)

	return 0;
}

calloc

malloc外,C语言还提供了一个函数calloc用于动态内存分配。

代码语言:javascript
复制
void* calloc (size_t num, size_t size);
  • 函数的功能是开辟num个大小为size的空间
  • malloc不同的是,calloc会将申请到的空间的每个字节初始化为0
代码语言:javascript
复制
int main()
{
	int n = 10;
	int* array = (int*)calloc(n, sizeof(int));//申请n个整型大小的内存空间
	if (array == NULL)//检测是否申请失败
	{
		perror("calloc failed");//发出失败提示
		exit(-1);//运行失败,结束程序
	}

	for (int i = 0; i < n; i++)
	{
		printf("%d ", array[i]);//此时打印,是已初始化的数据,全零
	}
	printf("\n");

	free(array);
	array = NULL;

	return 0;
}

(代码运行截图)

realloc

仅有以上的函数要实现真正的动态地使用一块内存空间还是不够的。以上函数功能仅仅是申请和释放一块动态内存,而我们还需要一块改变动态内存大小的函数,这个函数就是realloc

代码语言:javascript
复制
void* realloc (void* ptr, size_t size);
  • ptr指向需要调整的内存空间的地址。
  • size是调整之后的大小。
  • 返回值为一个指向调整之后的空间起始地址的void*的指针。
  • 如果申请失败会返回一个空指针,并且不会自行释放原先的空间。
  • realloc在调整内存空间大小时存在两种情况:
    • 一:在原有空间之后又足够大的空间(即没被其他数据占用)。 这种情况直接原地扩容,追加原有数据后方的空间且不对原有数据做出改动。
    • 二:原有空间之后空间不够大。 这种情况realloc函数会在堆的其他位置上找一块总够大的空间,将原有数据拷贝进去,并且会自行释放原来占用的空间,最后返回的地址是一个新的地址。
代码语言:javascript
复制
int main()
{
	int n = 10;
	int* array = (int*)calloc(n, sizeof(int));//申请n个整型大小的内存空间
	if (array == NULL)//检测是否申请失败
	{
		perror("calloc failed");//发出失败提示
		exit(-1);//运行失败,结束程序
	}

	//危险的操作
	//array = (int*)realloc(array, 12);//由于申请失败时不会自行释放原空间,而此代码将原先指向原空间的指针置空,无法再找回原空间并释放(内存泄露)
    
    
	//安全的操作
	int* ptr = NULL;
	ptr = (int*)realloc(array, 12);
	if (ptr != NULL)//检测是否扩容失败
	{
		array = ptr;//扩容成功再赋值回来
	}
	
	//...

	free(array);
	array = NULL;

	return 0;
}

动态内存函数常见使用错误

由于动态内存函数地使用涉及指针,内存空间的知识,对于C语言这块内容还不是很熟悉的人来说使用难度较大。这里总结几个比较常出现的错误,希望对你的使用有所帮助。

对NULL指针的解引用

代码语言:javascript
复制
void test1()
{
	int* ptr = (int*)malloc(sizeof(int));
	//如果malloc申请空间失败那么此时ptr就是NULL
	*ptr = 9;//此时就会发生
}

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

代码语言:javascript
复制
void test2()
{
	int* ptr = (int*)malloc(10 * sizeof(int));
	if (ptr == NULL)
		exit(-1);

	for (int i = 0; i <= 10; i++)
		ptr[i] = i;//当i==10的3时候发生越界

	free(ptr);//值得注意的是,动态内存空间的越界并不会直接检测出来,而是会在free的时候检测出来并报错
	//此时会报出类似堆区异常访问,或者在访问正常数据后的空间之类的错误
}

(代码运行截图)

使用free释放非动态开辟的内存空间

代码语言:javascript
复制
void test3()
{
	int a[10] = { 0 };
	int* p = &a;
	//...
	free(p);//报错
}

对同一块动态内存空间多次释放

代码语言:javascript
复制
void test4()
{
	int* ptr = (int*)malloc(sizeof(int));
	if (ptr == NULL)
		exit(-1);
	//...
	free(p);
	free(p);//重复释放
}

只释放一部分动态内存空间

代码语言:javascript
复制
void test5()
{
	int* ptr = (int*)malloc(10 * sizeof(int));
	if (ptr == NULL)
		exit(-1);
	//...
	p++;
	//...
	free(p);//只释放了一部分内存
}

忘记释放动态内存空间(内存泄漏)

代码语言:javascript
复制
void test6()
{
	int* ptr = (int*)malloc(10 * sizeof(int));
	if (ptr == NULL)
		exit(-1);
	//...
	//内存泄露
}

结语

非常感谢各位读者能读完这篇文章,如果你觉得做的还不错的话,可以点赞收藏分享,让更多的朋友知道,当然,如果你觉得有什么问题的话也欢迎在评论区留言或私信告诉我哦!下期再会!

彩蛋

源码在这: gitee-test分支-动态函数详解文件 GitHub-master-Dynamic memory.c

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-03-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 写在前面
  • 为什么需要使用动态内存
  • 动态内存函数
    • malloc和free
      • calloc
        • realloc
        • 动态内存函数常见使用错误
          • 对NULL指针的解引用
            • 对动态开辟空间的越界访问
              • 使用free释放非动态开辟的内存空间
                • 对同一块动态内存空间多次释放
                  • 只释放一部分动态内存空间
                    • 忘记释放动态内存空间(内存泄漏)
                    • 结语
                    • 彩蛋
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档