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

文章中的例子都来自  《程序员面试宝典》(二)。


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


***************题 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开辟一段静态存储空间,使之也变为一个全局区域的数据。

 

 




你可能感兴趣的:(面试,null,存储,编译器)