动态内存函数易错例题详解

前言

首先本文中所讲述的例题皆来自于《高质量 C++/C 编程指南》这本书中。这本书中包含了很多C/C++中的陷阱和编程规则,读完这本书之后,相信你会对C/C++有了一个新的认识。

第一题

大家先来看这一段代码,请问Test函数运行的结果是什么?

void GetMemory(char *p) 
{ 
	p = (char *)malloc(100); 
} 
void Test(void) 
{ 
	char *str = NULL; 
	GetMemory(str); 
	strcpy(str, "hello world"); 
	printf(str); 
}

首先这里的答案是程序会崩溃掉,那么为什么程序会崩溃,你是不是觉得这里面并没有一点问题?
这里涉及到指针传参,这里GetMemory(str)虽然将str传了进去,形参是实参的一份临时拷贝,那么这里的形参p=str,如果你只改变p的值是不会改变str的值,str的值还是NULL,所以这里程序会崩溃,当然这里申请了空间却没有free也会造成内存泄漏。
如果想要改变str的值,你需要从地址访问str,那么你这里就需要传入str的地址,代码如下

void GetMemory(char **p) 
{ 
	*p = (char *)malloc(100); //对二级指针p解引用,**p=&str
} 
void Test(void) 
{ 
	char *str = NULL; 
	GetMemory(&str); //传入str的地址
	strcpy(str, "hello world"); 
	printf(str); 
}

第二题

那么这段代码Test函数运行的结果又是什么呢?

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

答案是:不能确定。为什么不能确定,str不应该是‘h’的地址吗?这里涉及到了函数堆栈的知识,这些函数都是在栈上开辟的空间,在栈上开辟空间有一个特点就是进栈开辟空间,出栈自动释放空间。我们来解析GetMemory函数。

char *GetMemory(void) //在栈上开辟空间
{ 
	char p[] = "hello world"; //给p分配空间
	return p; //返回p的值后自动释放刚刚开辟的空间
} 

这里大家就能看出问题,如果刚刚开辟的空间被释放了,那“hello world"字符串就不存在了,但是这个指针p将‘h’的地址返回给了str,虽然GetMemory的空间被释放掉,可是str依旧指向原来的’h’,只是字符串已经不在了,这个时候str就变成了一个野指针,现在这个位置(原‘h’)上存放的是什么内容我们就不得而知了。

第三题

大家是否感觉很有意思,接下来是第三题

void Test(void) 
{ 
	 char *str = (char *) malloc(100);
	 strcpy(str, “hello”); 
	 free(str); 
	 if(str != NULL) 
	 { 
		 strcpy(str, “world”); 
		 printf(str); 
	} 
}

这道题很简单,但这种错误造成的后果很严重,答案是会篡改动态内存区的内容。这里虽然使用free释放了刚才开辟的动态内存空间,但是str依然指向原‘h’所在位置,这个时候str便成了一个野指针,这里的if语句对str根本没有任何作用。我们需要养成一个好习惯,不仅malloc和free要成对出现,而且在free释放之后要将刚刚保存开辟空间首地址的指针置NULL。

《高质量 C++/C 编程指南》这本书中有很多习惯可以使你能更稳定的编写高难度的程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值