您的位置:首页 > 其它

指向临时变量的指针的返回

2014-04-07 20:32 399 查看
一直以为对于函数返回的指针了解得还可以,但是真实不用不知道,一用吓一跳。今天在一篇博客上面看到如下两段代码,博客的作者给出了一个问题,但是并没有解释为什么不同。自己通过实验给出了解释,但是不知道对不对,仅供参考!

下面是个错误的例子:

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;

}

下面这个例子没有问题,大家知道为什么吗?

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;

}

我在linux环境下面验证了作者的说法,的确是那样,上面一个有错,下面一个正确。问题就出在一个用的是数组类型,而另外一个用的是指针类型(从侧面亦可以看出并不是有些大学老师说的那样char str[]等价于char* str),由于栈里面的变量都是临时的。当前函数执行完成时,相关的临时变量和参数都被清除了。不能把指向这些临时变量的指针返回给调用者,这样的指针指向的数据是随机的,会给程式造成不可预料的后果。但是指针却有所不同,指针的地址在栈上,但是它所指向的内容却是在堆上面,所以并没有被清除。这就是为什么一个正确一个错误的原因。

其实这博客提前写了一天,我并没有发表,因为怕自己理解得有错,所以跟博客的作者写信交流下了,下面贴出我们的信件内容,希望对需要的朋友有所帮助:

问:

大家都知道,栈里面的变量都是临时的。当前函数执行完成时,相关的临时变量和参数都被清除了。不能把指向这些临时变量的指针返回给调用者,这样的指针指向的数据是随机的,会给程式造成不可预料的后果。

下面是个错误的例子:

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;

}

下面这个例子没有问题,大家知道为什么吗?

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;

}

我在linux环境下跑了,对代码做了点修改,相应的修改和运行结果如下:

#include <stdio.h>

char* get_str(void)

{

char str[] = {"abcd"};

return str;

}

int main(int argc, char* argv[])

{

char* p = get_str();

printf("%d/n", *p);

printf("%d/n", *(p+1));

return 0;

}

运行结果:

[root@localhost singnode]# ./ss

97

-12

#include <stdio.h>

char* get_str(void)

{

char* str = {"abcd"};

return str;

}

int main(int argc, char* argv[])

{

char* p = get_str();

printf("%d/n", *p);

printf("%d/n", *(p+1));

return 0;

}

运行结果:

[root@localhost singnode]# ./cc

97

98

对于这样的运行结果是不是因为指针的地址虽然是在栈上,但是它指向的内容却是在堆上面,所以并没有被清除。而数组的地址和内容都是在栈上面(首地址除外),所以出错。而对于 printf("%d/n", *p);能够输出正确的97,是因为首地址被当成指针来处理了,所以它的内容保存在堆上面,而其它的值保存在栈上面则被清除,从而产生了随机值,如-12。

(在此解释下我最初的理解,红字部分,一开始我并不知道数组返回的p也是正确的值,只是在调用printf语句后p的值才被破坏掉了,所以这是我之前根据运行结果来做的解释,在此纠正下。)

答:

int main(int argc, char* argv[])

{

char* p = get_str();

printf("%d/n", *p);

printf("%d/n", *(p+1));

return 0;

}

运行结果:

[root@localhost singnode]# ./cc

97

98

对于这样的运行结果是不是因为指针的地址虽然是在栈上,但是它指向的内容却是在堆上面,所以并没有被清除。而数组的地址和内容都是在栈上面(首地址除外),所以出错。

答:是的。

而对于 printf("%d/n", *p);能够输出正确的97,是因为首地址被当成指针来处理了,所以它的内容保存在堆上面,而其它的值保存在栈上面则被清除,从而产生了随机值,如-12。

答:

char* p = get_str();

此时p指向的内容还没有破坏,你可以在调试器中看一下。

printf("%d/n", *p);

此时因为调用了printf,所以p就被破坏了。

printf("%d/n", *(p+1));

即使再调用:

printf("%d/n", *p);

结果也是错误的。

这是最后写的回信:

非常感谢!我验证了下,如下:

(gdb) print p

$2 = 0xbffff703 "dbcd"

(gdb) s

98

12 printf("%d/n", *p);

(gdb) print p

$3 = 0xbffff703 "��/017m"

(gdb)

在调用printf之前的p内容还没有被破坏掉,但是调用printf之后就被破坏了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: