资讯专栏INFORMATION COLUMN

【C语言】动态内存分配

helloworldcoding / 1216人阅读

摘要:一动态内存的函数和头文件功能向堆区申请一块大小为的连续的空间,并返回该空间的起始地址。若指向的不是动态分配的内存,函数的行为标准未定义,取决于编译器。


    常规开辟空间的方式,开辟出空间的大小是固定的(尤其是数组的开辟需要预先给定空间),而动态内存分配可以解决这个问题。

一、动态内存的函数

    1.1 malloc和free

1️⃣ malloc:

void* malloc (size_t size);

    头文件stdlib.h
    功能:向堆区申请一块大小为size连续的空间,并返回该空间的起始地址。

  • 申请成功,返回该空间的指针。
  • 申请失败,返回NULL

?注意
    ① 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。

//eg.int* p = (int*)malloc(40);//强制类型转换为int*

    ② 如果参数 size0malloc的行为是标准是未定义的,取决于编译器。

2️⃣ free:

void free (void* ptr);

    功能:释放动态开辟的内存。

?注意
    ① 若ptr指向的是NULL,函数啥也不做。
    ② 若ptr指向的不是动态分配的内存,free函数的行为标准未定义,取决于编译器。

//egint main(){	int num = 0;	scanf("%d", &num);	int* ptr = NULL;	ptr = (int*)malloc(num * sizeof(int));//动态开辟空间	if (NULL != ptr)//是否开辟成功	{		int i = 0;		for (i = 0; i < num; i++)		{			*(ptr + i) = 0;		}	}	free(ptr);//释放ptr所指向的动态内存	//虽然free将空间释放但是ptr还可以找到那块空间,所以需要将ptr置NULL	ptr = NULL;	return 0;}

Summary:
mallocfree是一对,malloc开辟后需要检测是否成功,free释放后需要置NULL

    1.2 calloc

void* calloc (size_t num, size_t size);

    功能:向堆区申请num个大小为size的空间,并将空间的每一个字节初始化为0,返回该空间的起始地址。

//eg.int main(){	int* p = (int*)calloc(10, sizeof(int));	if (NULL != p)	{		//使用空间	}	free(p);	p = NULL;	return 0;}

    1.3 realloc

void* realloc (void* ptr, size_t size);

    功能:将ptr指向的空间调整为size大小,返回调整之后的内存起始位置。

?注意:有两种调整内存空间的情况:
    ① 原有空间之后有足够大的空间:在原有空间的基础上向后延伸,不改变原有数据。
    ② 原有空间之后没有足够大的空间:在堆区上找一个连续的合适空间,返回新空间的起始地址。并将数据转移到新地址中,旧地址释放。

//eg.int main(){	int* ptr = (int*)malloc(100);	if (ptr != NULL)	{		//业务处理	}	else	{		exit(EXIT_FAILURE);		//EXIT_FAILURE 可以作为exit ()的参数来使用,表示没有成功地执行一个程序		//EXIT_SUCCESS 作为exit ()的参数来使用,表示成功地执行一个程序	}	//扩容	int* p = NULL;	p = realloc(ptr, 1000);//要注意需要新建一个变量以免开辟失败而造成原地址丢失	if (p != NULL)	{		ptr = p;	}	free(ptr);	ptr = NULL;	return 0;}

Summary:
所有动态内存开辟后,最好都检测一遍是否成功,释放后都置NULL

在堆区申请的空间,有两种回收方式

  • free
  • 程序退出时,申请的空间被回收

二、常见的错误

    2.1 动态开辟后忘记检测

//Qvoid test(){	int* p = (int*)malloc(INT_MAX / 4);	*p = 20;//如果p的值是NULL,就会有问题	free(p);	p=NULL;}
//Svoid test(){	int* p = (int*)malloc(INT_MAX / 4);	if (p == NULL)//检测是否开辟成功	{		exit(EXIT_FAILURE);	}	*p = 20;	free(p);	p=NULL;}

    2.2 动态开辟后忘记释放(内存泄漏)

//Qvoid test(){	int* p = (int*)malloc(100);	if (NULL != p)	{		*p = 20;	}}int main(){	test();	while (1);}

S:开辟的空间在未结束前,一直被占用,记得free回收,别等程序退出自己回收。

    2.3 动态开辟空间越界访问

//Qvoid test(){	int i = 0;	int* p = (int*)malloc(10 * sizeof(int));	if (NULL == p)	{		exit(EXIT_FAILURE);	}	for (i = 0; i <= 10; i++)	{		*(p + i) = i;//当i是10的时候越界访问	}	free(p);	p=NULL;}

S:编译器不能检测出,得程序员自己格外注意。

    2.4 free释放非动态开辟内存

//Qvoid test(){	int a = 10;	int* p = &a;	free(p);//err	p=NULL;}

S:free释放堆上的空间

    2.5 free释放一部分

void test(){	int* p = (int*)malloc(100);	p++;//p不再指向动态内存的起始位置	free(p);//err}

free释放一块空间必须提供该空间的起始地址。

    2.6 free多次释放

//Qvoid test(){	int *p = (int *)malloc(100);	free(p);	free(p);//err 重复释放}
//Svoid test(){	int *p = (int *)malloc(100);	free(p);	p=NULL;	free(p);//NULL啥都不干	p=NULL;}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/122558.html

相关文章

  • C语言进阶】动态内存管理/分配

    摘要:栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。栈区主要存放运行函数而分配的局部变量函数参数返回数据返回地址等。 C语言动态内存分配篇 目录 一、为什么存在动态内存管理/分配?         内存的存储形式划分 二、动态内存函数的介绍         malloc ...

    Carson 评论0 收藏0
  • C语言篇 + 内存管理及柔性数组话题

    摘要:动态内存函数的介绍和语言提供了一个动态内存开辟的函数,它的函数原型是这样的这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。 目录 为什么存在动态...

    VishKozus 评论0 收藏0
  • 深入理解Redis 数据结构—简单动态字符串sds

    摘要:本文主要介绍的数据结构简单动态字符串简称。遵守字符串以空字符串结尾的惯例,保存的空字符串一个字节空间不计算在的属性里面。添加空字符串到字符串末尾等操作,都是由函数自动完成的,所以这个空字符对于使用者来说完全是透明的。Redis是用ANSI C语言编写的,它是一个高性能的key-value数据库,它可以作用在数据库、缓存和消息中间件。其中 Redis 键值对中的键都是 string 类型,而键...

    番茄西红柿 评论0 收藏2637
  • 秋招——语言篇(C++)

    摘要:语言不支持函数重载,编译后的代码只包含函数名。发布程序无需提供静态库,移植方便。全局和静态变量当且仅当对象首次用到时才进行构造。静态全局变量全局作用域文件作用域,无法在其他文件中使用。求数组数组名数据类型。 ...

    LuDongWei 评论0 收藏0
  • C语言进阶:动态内存管理

    摘要:释放不完全导致内存泄漏。既然把柔性数组放在动态内存管理一章,可见二者有必然的联系。包含柔性数组的结构用进行动态内存分配,且分配的内存应大于结构大小,以满足柔性数组的预期。使用含柔性数组的结构体,需配合以等动态内存分配函数。 ...

    shinezejian 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<