对于局部变量,首先应该明确:其作用域是在函数内部,函数返回则变量被释放。而函数返回局部变量的情况,一般来说分两种:返回变量的值和返回指针。直接返回变量的值,一般来说是没有问题的。经常出错的是返回指针的情况。
返回指针的情况,我们先看两个例子:
1.
char *gen_local_variable()
{
char *local_variable = "hello world!";
return local_variable;
}
......
tmp = gen_local_variable();
......
2.
char *gen_local_variable()
{
char local_variable[] = "hello world!";
return local_variable;
}
......
tmp = gen_local_variable();
......
这两种情况,哪个对哪个错?
答案是:1对,2错。
让我们来分析一下为什么。对于1,函数中定义了局部指针local_variable,并且指向字符串"hello world!"。这里,我们要明确:"hello world!"是字符串常量,其存放的位置在只读存储区。因此,在函数gen_local_variable()结束后,local_variable指向的空间是不释放的。所以,这里是没有问题的。
反观2中,定义了字符数组local_variable,其存放的位置是在栈上。很明显,当函数执行完之后,指针所指向的栈的空间已经释放了。因此,就不难理解为什么会出错了。
下面我们讨论一下,如何解决上面的问题。方案有如下几种:
1. 使用全局变量
这种方法简单易用,但是缺点在于任何人都有可能在任何时候修改这个全局变量,
2. 使用静态数组,例如
char *gen_local_variable()
{
static char local_variable[] ;
......
return local_variable;
}
这样可以防止任何人修改这个数组,但是该函数的下一次调用将覆盖这个数组的内容,所以调用者必须在此之前使用或者备份数组的内容。和全局变量一样,大段的缓冲区闲置不用,是很浪费内存空间的。
3. 显式分配一些内存,保存返回的值。例如:
char *gen_local_variable()
{
char *local_variable = malloc(100);
......
return local_variable;
}
这个方法具有静态数组的优点,而且在每次调用时都创建一个新的缓冲区,所以函数以后的调用都不会覆盖之前的返回值。它适用于多线程的代码。其缺点在于:程序员必须承担内存管理的任务。人们很容易忘记释放已分配的内存,从而产生令人难以置信的bug。
4. 调用者分配内存来保存函数的返回值。这也许是最好的解决方案。
void gen_variable(char *variable, int size)
{
char *local_variable;
......
strncpy(variable, local_variable, size);
}
buffer = malloc(size);
gen_variable(buffer, size);
......
free(buff);
在同一代码块中进行malloc和free操作,内存管理是最简单的了。
以上是我在看《C专家编程》中的一些体会,欢迎各位的指正。