如果函数的参数是一个指针,不要指望用该指针去申请动态内存。示例7-4-1 中,
Test 函数的语句GetMemory(str, 200)并没有使str 获得期望的内存,str 依旧是NULL,
为什么?
void GetMemory(char *p, int num)
{
p = (char *)malloc(sizeof(char) * num);
}
void Test(void)
{
char *str = NULL;
GetMemory(str, 100); // str 仍然为 NULL
strcpy(str, "hello"); // 运行错误
}
示例7-4-1 试图用指针参数申请动态内存
毛病出在函数GetMemory 中。编译器总是要为函数的每个参数制作临时副本,指针
参数p 的副本是 _p,编译器使 _p = p。如果函数体内的程序修改了_p 的内容,就导致
参数p 的内容作相应的修改。这就是指针可以用作输出参数的原因。在本例中,_p 申请
了新的内存,只是把_p 所指的内存地址改变了,但是p 所指的内存地址丝毫未变。(不会执行p =_p)所以函数GetMemory并不能输出任何东西。事实上,每执行一次GetMemory 就会泄露一块内存,因为没有用free 释放内存。
如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”,见示例7-4-2。
void GetMemory2(char **p, int num)
{
*p = (char *)malloc(sizeof(char) * num);
}
void Test2(void)
{
char *str = NULL;
GetMemory2(&str, 100); // 注意参数是 &str,而不是str
strcpy(str, "hello");
cout<< str << endl;
free(str);
}
示例7-4-2 用指向指针的指针申请动态内存
由于“指向指针的指针”这个概念不容易理解,我们可以用函数返回值来传递动态
内存。(很好的方法,可借鉴)这种方法更加简单,见示例7-4-3。
char *GetMemory3(int num)
{
char *p = (char *)malloc(sizeof(char) * num);
return p;
}
void Test3(void)
{
char *str = NULL;
str = GetMemory3(100);
strcpy(str, "hello");
cout<< str << endl;
free(str);
}
示例7-4-3 用函数返回值来传递动态内存
用函数返回值来传递动态内存这种方法虽然好用,但是常常有人把return 语句用错
了。这里强调不要用return 语句返回指向“栈内存”的指针(多用指向堆指针,记得要free),因为该内存在函数结束时自动消亡,见示例7-4-4。
char *GetString(void)
{
char p[] = "hello world";
return p; // 编译器将提出警告
}
void Test4(void)
{
char *str = NULL;
str = GetString(); // str 的内容是垃圾
cout<< str << endl;
}
示例7-4-4 return 语句返回指向“栈内存”的指针用调试器逐步跟踪Test4,发现执行str = GetString 语句后str 不再是NULL 指针,但是str 的内容不是“hello world”而是垃圾。
p[]数组为函数内的局部自动变量,在函数返回后,内存已经被释放。这是许多程序员常犯的错误,其根源在于不理解变量的生存期。
如果把示例7-4-4 改写成示例7-4-5,会怎么样?
char *GetString2(void)
{
char *p = "hello world";
return p;
}
void Test5(void)
{
char *str = NULL;
str = GetString2();
cout<< str << endl;
}
示例7-4-5 return 语句返回常量字符串
函数Test5 运行虽然不会出错,但是函数GetString2 的设计概念却是错误的。因
为GetString2 内的“hello world”是常量字符串,位于静态存储区,它在程序生命期
内恒定不变。无论什么时候调用GetString2,它返回的始终是同一个“只读”的内存块。
常见的内存错误及其对策
发生内存错误是件非常麻烦的事情。编译器不能自动发现这些错误,通常是在程序
运行时才能捕捉到。而这些错误大多没有明显的症状,时隐时现,增加了改错的难度。
有时用户怒气冲冲地把你找来,程序却没有发生任何问题,你一走,错误又发作了。
常见的内存错误及其对策如下:
- 猜你在找
核心技术类目
Hadoop
AWS
移动游戏
Java
Android
iOS
Swift
智能硬件
Docker
OpenStack
VPN
Spark
ERP
IE10
Eclipse
CRM
JavaScript
数据库
Ubuntu
NFC
WAP
jQuery
BI
HTML5
Spring
Apache
.NET
API
HTML
SDK
IIS
Fedora
XML
LBS
Unity
Splashtop
UML
components
Windows Mobile
Rails
QEMU
KDE
Cassandra
CloudStack
FTC
coremail
OPhone
CouchBase
云计算
iOS6
Rackspace
Web App
SpringSide
Maemo
Compuware
大数据
aptech
Perl
Tornado
Ruby
Hibernate
ThinkPHP
HBase
Pure
Solr
Angular
Cloud Foundry
Redis
Scala
Django
Bootstrap