您的位置:首页 > 编程语言 > C语言/C++

C/C++中传递动态内存的一些问题

2010-08-23 21:49 225 查看
文章中的例子都来自 《程序员面试宝典》(二)。

看书的时候,发现了几个动态内存的问题,很经典,自己在编写程序时也经常要碰到。很多问题,自己也是第一次明白,想了很长时间。

***************题 1 *******************

//找出这个程序的问题
#include <iostream>
using namespace std;
void GetMemory(char *p, int num)
{
p = (char *)malloc(sizeof(char) * num);
}
int main()
{
char *str = NULL;
GetMemory(str, 100);
strcpy(str, "hello");
return 0;
}


这是个很经典的问题,回想一下,自己在写程序时也遇到过这种情况,而且错误经常很难发现。

我现在来分析一下错误的地方,我们很多人都觉得这样写没问题,这样也能为str分配一定长度的空间,这正是我们忽略的地方。可能是我们遇到的传指针来交换两个变量的值这样的例子太多,潜意识中总觉得传进去一个指针,就万事大吉了,什么也能帮我们修改了(不管是赋值,还是申请空间……)。这是个很大的问题,这也正是我们容易出错的地方,我们忽略了原来我们传递指针后,操作的都是指针地址所指向的内容,而这道题操作的确实指针本身。这就是错误所在。

这道题毛病出在GetMemory中,函数中的*p实际上是主函数中的str的一个副本,编译器总是要为函数的每个参数制作临时副本。在本例中,p申请了新的内存,只是把p所指的内存地址改变了,但是str丝毫未变。因为函数GetMemory没有返回值,因此str并不指向p所申请的那段内存,所以函数并没有为str申请一段可用的内存。事实上,每执行一次GetMemory就会申请一块内存,但申请的内存却不能有效释放,结果是内存一直被独占,最终造成内存泄漏。

要解决这个问题,可以由于两种方法,

第一种方法还是用指针,这时我们必须采用指向指针的指针:

//用指向指针的指针来申请一块内存区
#include <iostream>
using namespace std;
void GetMemory(char **p, int num)
{
*p = (char *)malloc(sizeof(char) * num);
}
int main()
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
cout << str << endl;
return 0;
}


第二种方法我们可以用函数返回值来传递动态内存:

//用函数返回值来传递动态内存
#include <iostream>
using namespace std;
char *GetMemory(char *p, int num)
{
p = (char *)malloc(sizeof(char) * num);
return p;
}
int main()
{
char *str = NULL;
str = GetMemory(str, 100);
strcpy(str, "hello");
return 0;
}


***************题 2 *******************

//请问这个函数有什么问题?
char *strA()
{
char str[] = "hello word";
return str;
}


很多人看到这个问题时,觉得很简单。认为str是一个函数的局部变量,在函数返回时,它的内存被收回,所以指针指的是个未知区域,容易出问题。这样的返回操作是不允许的。

这样的回答是对的,因为我也是这么回答的。但是先别急,这只是一半,我们其实并没有把它搞得很明白,再来看书上给的一个例子:

//这个函数有什么问题?
char *strA()
{
char *str = "hello word";
return str;
}


相信很多人(包括我)在这就犯嘀咕了。很多人认为这两个题是一样的,考的内容都是同一个,都是局部变量的问题。要是这样理解的话,那就错了。

其实第二个函数是没问题的,这样写就是第一个函数的改进。如果函数写成指针的形式,就不会报错。

这两个例子函数,考察的是我们对局部数组和全局数组的理解。首先我们一定要搞清楚char str[]和char *str的区别:

1、char str[] = “hello word“;是分配一个局部数组。这个局部变量在内存中的栈,共占了11个字节(后面还有一个/n),这个应该都没问题能理解。也就是说字符数组所有的内容全部存在函数所使用的内存中的栈。当函数结束时,这部分栈也随之“丢失“。故str指向了一个空闲区域。

2、而char

*str = “hello word“;是分配了一个全局数组。它所对应的是内存中的全局区域。这个局部变量只占了内存的4个字节(也就是指针str所占的内存),这个指针是位于内存的栈中,但是它指向全局区域的一串字符串hello word。所以说,在函数结束时,字符串所占用的内存并不随之“消失“。消失的只是指针所占的内存。

所以,第一个函数要是想修改,可以在语句前,加一个static。通过static开辟一段静态存储空间,使之也变为一个全局区域的数据。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: