一个关于c#中return返回值的问题

l198810016 2011-12-11 03:41:12

namespace 实
{
class test
{

}

class Program
{
static test DO()
{
test bar = new test();
return bar;
}
static void Main(string[] args)
{
test Newbar = DO();
}
}
}
问题1:运行时调用了DO()这个方法,DO()这个方法return了一个test的实例bar然后赋值给Newbar,bar是局部变量再函数运行完以后就撤消了那为什么Newbar还能正常使用呢?
问题2:还有return语句再执行以后函数不是已经完成了吗?那么它是赋值的 呢 return 的数据怎么存储的呢
...全文
725 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
l198810016 2011-12-11
  • 打赏
  • 举报
回复
看了你们说的我说一下我的理解哈
有返回值的时候 函数压栈 首先记忆这个返回值 并且再内存堆栈上分配A 运行RETURN 时 系统把返回值复制到 A 里...然后函数 结束 ...把A的值 通过= 赋值给 主调函数的变量 然后A 撤销....是不是 ?
qldsrx 2011-12-11
  • 打赏
  • 举报
回复
堆栈只是一小部分而已,内存很大部分是数据,只有小部分用作堆栈。这部分堆栈空间由CPU快速访问,无需申请或释放,空间是一次性分配好的,为了快速,有时会直接在CPU中缓存。
所以你没必要对堆栈空间考虑过多,堆栈的空间要是频繁申请或释放,会大大影响速度的。
  • 打赏
  • 举报
回复
一个变量 bar 它自身并不就是最终的对象,它只是引用对象而已。当没有引用,对象将来就会被GC自动回收。而既然有引用,那么bar 引用它,随后 Newbar 也引用它,没有什么不好理解的。

bar变量没有了,不代表着对象没有引用了。
兔子-顾问 2011-12-11
  • 打赏
  • 举报
回复
c#是.net clr托管开发语言的一种。
.net的托管开发,关键是托管了内存的管理,你不需要自己管理内存,而是交给CLR来管理,有垃圾回收。这里,创建的类型都继承自Object,并分为两类:
值类型和引用类型
值类型在=的时候进行值拷贝,对象的深度复制。
引用类型的对象永远是在堆上分配内存,你使用的只能是对象的引用。所以,你可以认为.net的class对象,都是指针操作的。为什么说是指针呢,因为c++中的指针可以指向NULL而引用不可以,c#的这个叫做引用,但和指针有点不同是除了对象和null其他不能指。

相关值类型和引用类型的连接
http://msdn.microsoft.com/zh-cn/library/4d43ts61(v=vs.90).aspx
http://www.sosuo8.com/article/show.asp?id=2184
http://www.cnblogs.com/Autumoon/archive/2008/08/18/1270685.html
l198810016 2011-12-11
  • 打赏
  • 举报
回复
我弱弱的问一句 堆栈不是在内存上吗??c#内存的组织方式不是堆栈和堆吗
qldsrx 2011-12-11
  • 打赏
  • 举报
回复
不知道你的分配空间A是指什么空间,如果是CPU堆栈空间,那么你的理解没问题,如果是内存空间,那么你的理解就有问题了。
l198810016 2011-12-11
  • 打赏
  • 举报
回复
...看了你们说的我说一下我的理解哈
有返回值的时候 函数压栈 首先记忆这个返回值 并且给他分配好空间比如说空间A 运行RETURN 时 系统把返回值复制到 A 里...然后函数 结束 ...把A的值 通过= 赋值给 主调函数的变量 然后A 撤销....是不是 ?
qldsrx 2011-12-11
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 l198810016 的回复:]
阿非: 如果没有变量接收呢?? 就不会有出栈操作了?
[/Quote]
那样的话,连压栈动作也不会有,这2个动作必须是配对的,否则整个程序的后续操作都要出错。

PS:如果你一定要看堆栈,将代码编译后看IL语言,那个会显示详细的堆栈操作,但是你肯定会看晕。
分别编译2个操作,一个接收,一个不接受,IL语言会显示2种,接收返回值的,有堆栈动作代码,而不接收返回值的,直接结束,无任何堆栈操作。
l198810016 2011-12-11
  • 打赏
  • 举报
回复
阿非: 如果没有变量接收呢?? 就不会有出栈操作了?
qldsrx 2011-12-11
  • 打赏
  • 举报
回复
不需要考虑堆栈问题,考虑那个会把自己搞晕的。

.NET中不需要考虑内存释放,都是自动管理的。只有非托管代码才需要考虑。
值类型是直接存放在内存地址里,而引用类型是存放在2处,内存地址里先存放引用地址,然后定位到另一个地址的连续内存空间,那才是引用类型的实际内容。
因此访问值类型例如int,就是直接一次寻址,而访问引用类型如chass a,那就是二次寻址。

return返回的都是第一次寻址的结果,值类型的就返回实际值,而引用类型则返回引用地址。考虑到32位操作系统的引用地址只有32位整型长度,因此这个返回值很小。每次为这个返回值开辟新的内存空间存放也没任何关系,几乎感觉不到内存的使用。

bar是局部变量再函数运行完以后就撤消,但是撤销的是bar的引用地址所占用的内存空间而已,第二级地址的内容还没撤销,因为又有新的对象Newbar指向了它,Newbar里存放了和bar一样的引用地址,2个变量虽然第一级地址不同,但是同时指向同一个引用地址。只有当某个引用地址不被任何对象引用,它才会被释放,这是.NET的潜规则。
阿非 2011-12-11
  • 打赏
  • 举报
回复
问题2:还有return语句再执行以后函数不是已经完成了吗?那么它是赋值的 呢 return 的数据怎么存储的呢
---------------------
当方法有返回值并且有变量接收的时候,会有压栈和出栈两个操作

压栈指的记忆方法的返回值,出栈是将返回值赋给对应的变量
阿非 2011-12-11
  • 打赏
  • 举报
回复
public int aa; // 再实例化a 以后 这个aa 是存储再那呢 ????
--------------
aa 存在托管堆,值类型并不总是存在堆栈上的
阿非 2011-12-11
  • 打赏
  • 举报
回复
问题1:运行时调用了DO()这个方法,DO()这个方法return了一个test的实例bar然后赋值给Newbar,bar是局部变量再函数运行完以后就撤消了那为什么Newbar还能正常使用呢?
----------------------------------------------------------------------
因为bar是引用类型,DO那个方法返回的是bar 的引用,
bar所占的空间在DO方法返回时是会释放的,但实际内容是不释放的,
Newbar 能正常实际用因为获取的是对应引用内的东西,就是实际内容。

l198810016 2011-12-11
  • 打赏
  • 举报
回复
1 楼我看了你的博客了
我想问一个问题你说值类型都是在堆栈上分配内存

public class a
{
public int aa; // 再实例化a 以后 这个aa 是存储再那呢 ????
}
还有我问的 RUTURN 这个问题 是这个意思 函数调用 是压栈 那么最先弹出的时候 return 是吧 那么他返回的 那个变量是不是 再栈中临时开辟一块空间用来储存呢
l198810016 2011-12-11
  • 打赏
  • 举报
回复
那你说说 好不好!!!
qldsrx 2011-12-11
  • 打赏
  • 举报
回复
同楼上,你需要买本C#的基础书籍学习,这里基础问题来问,往往得不到很专业的回答。

我们这些人都觉得很平常的知识,你却不懂,就好比有人问:“人为什么要吃饭睡觉啊”。太简单的问题,又如:“为什么1+1=2啊”。这些问题不是不会回答,而是没有专业的技巧来让那些理解有问题的人来理解。

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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