10.返回指向临时变量的指针
大家都知道,栈里面的变量都是临时的。当前函数执行完成时,相关的临时变量和参数都被清除了。不能把指向这些临时变量的指针返回给调用者,这样的指针指向的数据是随机的,会给程序造成不可预料的后果。
下面是个错误的例子:
/*********** 1 *****************/
char* get_str(void)
{
char str[] = {"abcd"};
return str;
}
int main(int argc, char* argv[])
{
char* p = get_str();
printf("%s/n", p);
return 0;
}
下面这个例子没有问题,大家知道为什么吗?
/*********** 2 *****************/
char* get_str(void)
{
char* str = {"abcd"};
return str;
}
int main(int argc, char* argv[])
{
char* p = get_str();
printf("%s/n", p);
return 0;
}
我在VC++6.0上一试,果然前者有问题,后者没有问题。于是就在想为什么会不一样,看了反汇编代码有请教了一位朋友,才明白了其中的原因,相关语句的反汇编代码如下:
7: char *str = {"abcd"};
0040D798 mov dword ptr [ebp-4],offset string "abcd" (00422fa4)
11: return str;
0040D79F mov eax,dword ptr [ebp-4]
7: char *str = {"abcd"};
0040D798 mov dword ptr [ebp-4],offset string "abcd" (00422fa4)
11: return str;
0040D79F mov eax,dword ptr [ebp-4]
7: char str[] = {"abcd"};
0040D798 mov eax,[string "abcd" (00422fa4)]
0040D79D mov dword ptr [ebp-8],eax
_max_test:
0040D7A0 mov cl,byte ptr [string "abcd"+4 (00422fa8)]
0040D7A6 mov byte ptr [ebp-4],cl
11: return str;
0040D7A9 lea eax,[ebp-8]
0040D798 mov eax,[string "abcd" (00422fa4)]
0040D79D mov dword ptr [ebp-8],eax
_max_test:
0040D7A0 mov cl,byte ptr [string "abcd"+4 (00422fa8)]
0040D7A6 mov byte ptr [ebp-4],cl
11: return str;
0040D7A9 lea eax,[ebp-8]
"abcd"是编译时放在代码段中的一个无名常量,当程序载入内存的时候是放在另一段内存中的,而非堆栈所在的内存中。从汇编代码中也可以看出,使用char *str这种方式时,程序是把"abcd"所在的内存地址先放到了堆栈中,然后再放入eax作为返回值的,也就是说eax中的地址指向的是"abcd"所在的内存。而用char str[]这种方式是,是先把原来的"abcd"复制到堆栈中的,然后再把存储"abcd"的堆栈的地址放入eax的,也就是说eax中的地址指向的是堆栈中"abcd",而不是原来的那个"abcd",由于函数使用的堆栈中的内存在函数退出后就会被释放,所以作为返回值的指向堆栈的指针就有可能会造成内存错误。后来我又实验了动态分配内存,由于动态分配的内存是在堆上的,所以不会造成上述的内存错误。
没有评论:
发表评论