关于局部变量的问题求解答~

judymac 2012-01-18 11:46:30
突然在看程序时对局部变量有所疑问了:


第一个程序如此:

char translate(int type)
{
char u8Data;
switch(type)
{
case 1:
u8Data='a';
break;
case 2:
u8Data='b';
break;
default:
u8Data='x'
}//end switch
return u8Data;
}//end translate

int main(int argc,char* argv[])
{
char buffer[4]={};
buffer[0]=translate(1);
buffer[1]=translate(2);
buffer[2]=translate(4);
buffer[3]=translate(6);

for(int i=0;i<4;i++)
cout<<buffer[i]<<" ";
cout<<endl;
}

这个可以正常输出 a b x x;

而第二个

char* test_variable_utility()
{
char a[4]={};
a[0]='c';
a[1]='f';
a[2]='a';
a[3]='v';
return a;
}//end

int main(int argc,char* argv[])
{
char* b;
b=new char[4];
b=test_variable_utility();

int i;

for(i=0;i<4;i++)
cout<<b[i]<<" ";
cout<<endl;

}

第二个程序则显示错误;

不都是返回局部变量吗?为什么第一个可以正常返回,而第二个不行呢?

是不是因为第一个虽然是局部变量但返回的是所对应的值,所以不会消失?
而第二个是指针,而返回后数组析构后,指针在第二个之后开始就丢失了吗?
...全文
141 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
yulinlang 2012-01-19
  • 打赏
  • 举报
回复
参考《C++程序设计语言 特别版》 Bjarne Stroustrup 裘宗燕译 机械工业出版社 P133:

每当一个函数被调用时,就会建立起它的所以参数和局部(自动)变量的一套新副本。在该函数返回后,这些存储又会被另作他用。所以,绝不能返回指向局部变量的指针,因为被指位置中内容的改变情况是无法预料的。
测试NULL 2012-01-18
  • 打赏
  • 举报
回复
还可以这样:

#include <iostream>
using namespace std;

char* test_variable_utility()
{
char a[4]={0};

a[0]='c';
a[1]='f';
a[2]='a';
a[3]='v';

return a;
}//end

int main(int argc,char* argv[])
{
int i;
char b[4] = {0};

b[0] = test_variable_utility()[0];
b[1] = test_variable_utility()[1];
b[2] = test_variable_utility()[2];
b[3] = test_variable_utility()[3];

cout<<b[0]<<endl;
cout<<b[1]<<endl;
cout<<b[2]<<endl;
cout<<b[3]<<endl;

return 0;
}
测试NULL 2012-01-18
  • 打赏
  • 举报
回复
下面这个应该对你理解有点帮助:

#include <iostream>
using namespace std;

char* test_variable_utility()
{
char a[4]={0};

a[0]='c';
a[1]='f';
a[2]='a';
a[3]='v';

return a;
}//end

int main(int argc,char* argv[])
{
int i;
char* b=test_variable_utility();
cout<<"刚调用完test_variable_utility的瞬间:"<<b[0]<<endl;

cout<<b[0]<<endl;
cout<<b[0]<<endl;
cout<<b[0]<<endl;

b=test_variable_utility();
cout<<"刚调用完test_variable_utility的瞬间:"<<b[1]<<endl;


cout<<b[1]<<endl;
cout<<b[1]<<endl;
cout<<b[1]<<endl;


b=test_variable_utility();
cout<<"刚调用完test_variable_utility的瞬间:"<<b[2]<<endl;


cout<<b[2]<<endl;
cout<<b[2]<<endl;
cout<<b[2]<<endl;


b=test_variable_utility();
cout<<"刚调用完test_variable_utility的瞬间:"<<b[3]<<endl;

cout<<b[3]<<endl;
cout<<b[3]<<endl;
cout<<b[3]<<endl;

return 0;
}
碎炎 2012-01-18
  • 打赏
  • 举报
回复
b=new char[4];
b=test_variable_utility();

b一开始分配的内存泄露了
函数过后指向的是另一个函数栈上的局部变量,因为是栈上分配的,所以出去后销毁了,是一个野指针
测试NULL 2012-01-18
  • 打赏
  • 举报
回复
第二种方法也可以,这样用的:

#include <iostream>
using namespace std;
char* test_variable_utility()
{
char* a=new char[4];
a[0]='c';
a[1]='f';
a[2]='a';
a[3]='v';

return a;
}

int main(int argc,char* argv[])
{
char* b=test_variable_utility();

int i;

for(i=0;i<4;i++)
cout<<b[i]<<" ";
cout<<endl;

delete [] b;

return 0;
}
游戏设计师 2012-01-18
  • 打赏
  • 举报
回复
第一个你返回的是一个char,由于返回类型为char所以传的是值,值是不会丢失的~
第二你你返回的是一个char*,由于返回的类型是char*所以传的址,由于使用局部变量,传递的地址已经失效,所以可能会造成问题

传值和传址弄清楚就可以了~
碎炎 2012-01-18
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 judymac 的回复:]

引用 2 楼 sryan 的回复:
b=new char[4];
b=test_variable_utility();

b一开始分配的内存泄露了
函数过后指向的是另一个函数栈上的局部变量,因为是栈上分配的,所以出去后销毁了,是一个野指针


是不是因为b指向test_variable_utility() 的地址,然后数组a[]是在stack里分配的,一旦函数调用完之后,数组a作……
[/Quote]

差不多 就是变量的生命周期问题 你要保证引用地址的时候 该地址指向的内存有效
鄢老 2012-01-18
  • 打赏
  • 举报
回复
第二个函数有问题:
如下:
char* test_variable_utility()
{
char a[4]={};
a[0]='c';
a[1]='f';
a[2]='a';
a[3]='v';
return a;
}//end

a[4]是局部数组,只在test_variable_utility中存在,在函数退出时,系统收回栈的资源,a[4]的作用域
失效,代码如下修改:

char a[4]={};char* test_variable_utility()
{
a[0]='c';
a[1]='f';
a[2]='a';
a[3]='v';
return a;
}//end
或:
char* test_variable_utility()
{
static char a[4]={};a[0]='c';
a[1]='f';
a[2]='a';
a[3]='v';
return a;
}//end


judymac 2012-01-18
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 sryan 的回复:]
b=new char[4];
b=test_variable_utility();

b一开始分配的内存泄露了
函数过后指向的是另一个函数栈上的局部变量,因为是栈上分配的,所以出去后销毁了,是一个野指针
[/Quote]

是不是因为b指向test_variable_utility() 的地址,然后数组a[]是在stack里分配的,一旦函数调用完之后,数组a作为局部变量就销毁了,所以相当于它的地址空间实际已经不是数组a[]了,对吗?

而如果按一楼的做法,实际数组a[]是在heap里面分配的,只有当他delete掉之后才真正的销毁,所以就算return回去只要不调用delete,b就是指向a的。right?
judymac 2012-01-18
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 wangliangffaflgh 的回复:]
下面这个应该对你理解有点帮助:

C/C++ code

#include <iostream>
using namespace std;

char* test_variable_utility()
{
char a[4]={0};

a[0]='c';
a[1]='f';
a[2]='a';
a[3]='v';

……
[/Quote]

1楼的方法,我会用,但是不明白,难道就像2楼说的因为new是调用heap,而数组时用stack吗?

3楼的方法,虽然可以但是不太明白,为什么呢?
4的方法也不是很明白,这不是函数指针呀,只是返回值是指针类型,也可以这样用?
赵4老师 2012-01-18
  • 打赏
  • 举报
回复
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”

提醒:
“学习用汇编语言写程序”

“VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习C和汇编的对应关系。”
不是一回事!

不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!

64,649

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧