动态内存管理(c语言)

目录

1.什么是内存的动态匹配         

2. 怎样建立内存的动态分配

3.常见的动态内存错误

4.堆区与栈区的区别:


1.什么是内存的动态匹配         

         之前介绍过全局变量和局部变量,全局变量是分配在内存中的静态存储区的,非静态的局部变量(包括形参)是分配在内存中的动态存储区的,这个存储区称为    栈。除此以外,C语言还允许建立内存动态分配区域,以存放一些临时用的数据,这些数据不必在程序的声明部分定义,也不必等到函数结束时才释放,而是需要时随时开辟,不需要时随时释放。这些数据是临时存放在一个特别的自由存储区,称为    堆 区。可以根据需要,向系统申请所需大小的空间。由于未在声明部分定义它们为变量或数组,因此不能通过变量名或数组名去引用这些数据,只能通过指针引用。

2. 怎样建立内存的动态分配

     对内存的动态分配是通过系统提供的库函数来实现的,主要有malloc,calloc,free,realloc  这4个函数

2.1.  用malloc函数开辟动态存储区

其函数原型为   void  * malloc(unsigned  int  size ) ; 

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

2.如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查,不然可能会造成野指针的问题;

3.返回值的类型时void*,所以malloc函数并不知道开辟空间的类型,具体-+在使用的时候由使用者自己来决定返回值的类型;

4.如果参数size为0,此时malloc函数的行为是标准未定义的,取决于程序运行时使用的编译器;

malloc(100);      //开辟100字节的临时分配域,函数值为其第1个字节的地址

注意指针的基类型为void,即不指向任何类型的数据,只提供一个纯地址。如果此函数未能成功执行,则返回空指针(NULL)。

malloc的使用:

vint main()
{
	int* p = (int*)malloc(40);//向内存申请一块40字节的空间,并对放回的指针类型转换
	if (p == NULL)//返回NULL指针时让打印错误信息并让程序结束
	{
		perror("malloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	return 0;
}

这样就对开辟的内存空间进行了一个使用了,但是还有点问题,因为向内存申请的空间没有进行释放。

所以这时就引入了另一个函数free

 2.2  用free函数释放动态存储区

其函数原型为:void  free (void * p);

1.如果参数p指向的空间是不是动态开辟的,那么free函数的行为是未定义的;

2.如果参数 p是NULL指针,则free函数什么事也不做;

free函数的使用:

#include<stdio.h>
#include<stdlib.h>
#include<cassert>
int main() {
	int* p = (int*)malloc(sizeof(int)*10);
	assert(p != NULL);
	for (int i = 0; i < 10; i++) {
		printf("%15d", p[i]);
	}
	free(p);    //释放内存
	p = NULL;
}

2.3 用calloc函数开辟动态存储区

 其函数原型为:void * calloc(unsigned n,unsigned size);

1.calloc的功能是为num个字节大小为size的元素开辟一个空间,并且把空间的每个字节的数据都初始化为0,然后返回这块连续空间的起始位置的地址;

2.与malloc函数的区别只在于,calloc在返回地址之前会把申请的空间的每个字节的数据都初始化为全0;

calloc函数的使用:

#include<stdio.h>
#include<stdlib.h>
#include<cassert>
int main() {
	int* p = (int*)calloc(10, sizeof(int));
	assert(p != NULL);
	for (int i = 0; i < 10; i++) {
		printf("%5d", p[i]);
	}
	free(p);
	p = NULL;
}

 

2.4  用relloc函数重新分配动态存储区

其函数原型为:void * relloc(void*p,unsigned int size);

1.p是要调整的内存空间;

2.size是调整之后的新大小;

3.返回值为调整之后的内存起始位置;

4.realloc函数在调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间;

relloc函数的使用:

#include<stdio.h>
#include<stdlib.h>
#include<cassert>
#include<string.h>
int main() {
	int* p = (int*)calloc(2 , sizeof(int));
	assert(p != NULL);

	int* q = (int*)realloc(p,5 * sizeof(int));
	assert(q != NULL);
}

 

3.常见的动态内存错误

3.1 对非动态内存使用free

对栈区上的空间使用free:

int main()
{
	int a = 0;
	free(&a);   // 错误
	return 0;
}

3.2  使用释放一块动态开辟内存的一部分

int main()
{
	int* p = (int*)malloc(40);
	p++;     // 此时p没有指向动态开辟内存的起始位置
	free(p);
	return 0;
}

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

int main()
{
	int* p = (int*)malloc(40);
	free(p);
	free(p);    //对同一块内存多次释放
	return 0;
}

3.4  动态开辟内存忘记释放

int main()
{
	while (1)
	{
		malloc(40);
	}
	return 0;
}

没有free,如果程序在没有结束之前申请的内存都没有进行释放的话,就会出现内存泄漏的问题。所以在申请好一块内存之后要记得对其进行释放。

4.堆区与栈区的区别:

C语言的内存模型分为5个区:栈区、堆区、静态区、常量区、代码区。每个区存储的内容如下:

1、栈区:存放函数的参数值、局部变量等,由编译器自动分配和释放,通常在函数执行完后就释放了,其操作方式类似于数据结构中的栈。栈内存分配运算内置于CPU的指令集,效率很高,但是分配的内存量有限,比如iOS中栈区的大小是2M。

2、堆区:就是通过new、malloc、realloc分配的内存块,编译器不会负责它们的释放工作,需要用程序区释放。分配方式类似于数据结构中的链表。“内存泄漏”通常说的就是堆区。

3、静态区:全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后,由系统释放。

4、常量区:常量存储在这里,不允许修改。

5、代码区:顾名思义,存放代码。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值