动态内存管理

malloc

在这里插入图片描述
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的起始地址
上开辟空间

  • 如果开辟成功,则返回一个指向开辟好空间的指针。
  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
  • 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
    在这里插入图片描述

free函数用来释放动态开辟的内存。

  • 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
  • 如果参数 ptrNULL指针,则函数什么事都不做。
	int arr[10] = { 0 };//在栈上开辟40个字节
	int* p = (int*)malloc(40);
	//在内存上开辟好空间,把起始地址强制类型转换成int*后赋给p
	free(p);//把p所指向的空间还给操作系统
	p = NULL;

calloc

malloc和calloc都是用来内存分配
malloc函数只负责在堆区申请空间,并且返回起始地址,不初始化内存空间
calloc函数在堆区上申请空间,并且初始化为0,返回起始地址
在这里插入图片描述
在这里插入图片描述

realloc

在这里插入图片描述

int main()
{
	int* p = (int*)calloc(10, sizeof(int));//失败返回NULL
	//开辟十个整形,每个元素大小是sizeof(int)
	//空间不够,增加20个int
	int* ptr=(int*)realloc(p, 20 * sizeof(int));
	//使用临时变量ptr,防止realloc内存开辟失败了返回空指针,使p改变
	if (ptr != NULL)
		p = ptr;
	free(p);
	p = NULL;
	return 0;
}

常见内存开辟的错误

对空指针进行解引用

int main()
{
	int* p = (int*)malloc(20);
	/*if (p == NULL)//检查
		return -1;*/
	*p = 0;//如果内存开辟失败,返回NULL
	//空指针解引用就有问题
	return 0;
}

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

int main()
{
	int* p = (int*)malloc(200);
	//开辟200个字节,最多容纳50个整形
	if (p == NULL)//检查
		return -1;
	for (int i = 0; i < 80; i++)//越界访问
		*(p + i) = i;

	free(p);
	p = NULL;
	return 0;
}

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

int main()
{   
	int a = 10;
	int* p = &a;//p是栈上开辟空间

	free(p);//错
	p = NULL;
	return 0;
}

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

int main()
{
	int* p = (int*)malloc(40);
	if (p == NULL)//检查
		return -1;
	for (int i = 0; i < 10; i++)
		*p++ = i;

	free(p);//错,p已经改变
	p = NULL;
	return 0;
}

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

int main()
{
	int* p = (int*)malloc(40);
	if (p == NULL)//检查
		return -1;

	free(p);
	free(p);//错
	p = NULL;
	return 0;
}

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

int main()
{
	int* p = (int*)malloc(40);
	if (p == NULL)//检查
		return -1;
	//在堆区上申请的空间,有两种回收的方式
	// 1.主动free   2.程序退出时,申请的空间也会回收
    //忘记释放
	getchar();
	return 0;
}

笔试题

1.下面程序运行结果是?

void GetMemory(char* p)
{
	p = (char*)malloc(100);//p的改变不会影响str
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);//str是形参
	strcpy(str, "hello world");//程序崩溃
	printf(str);
}

int main()
{
	Test();
	return 0;
}

程序运行会崩溃, 1.str传给p时是值传递,p是str的临时拷贝,当malloc开辟的空间起始地址放在p中的时候,不会影响str,str依然为NULL;
2.当str是NULL,strcpy想把hello world拷贝到str指向的空间时,程序就崩溃了,因为NULL指针指向的空间是不能直接访问的
3.存在内存泄漏,malloc开辟的空间,从来没有被主动释放(free)

如何修改?
方法一:

void GetMemory(char** p)
{
	*p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str);//传址
	strcpy(str, "hello world");
	printf(str);
	free(str);//释放
	str = NULL;
}

方法二:

char* GetMemory()
{
	char* p = (char*)malloc(100);
	return p;//返回值的方式带回malloc出来的空间的起始地址
}
void Test(void)
{
	char* str = NULL;
	str=GetMemory();
	strcpy(str, "hello world");
	printf(str);
	free(str);//释放
 	str = NULL;
}

2.下面程序运行结果是?

char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}

程序运行打印随机值:
为什么?返回栈空间地址的问题,p[]是局部变量,出了函数作用域空间会还给操作系统

更简单的理解


int* test()
{
	int n = 10;
	return &n;
}//n的空间已经还给操作系统

int main()
{
	int* p=test();
	printf("%d ", *p);//错
	return 0;
}

3.下面程序错误的原因?
free之后要记得置空

void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)//str到这是野指针
	{
		strcpy(str, "world");//非法访问内存
		printf(str);
	}
}

int main()
{
	Test();
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值