如题:起因是本人之前在B站某个视频留言让不懂传值传引用的私信我,今天竟真有一个网友联系,未免以后下一个人再问又要重新说一遍,特写此贴用于公开详解传值传引用;这也或许就是一种简单的因果,既然我造了因,那我也理当完成这个果。
首先,让我们重温一下什么是变量:
在C#中,变量是用来存储数据的标识符。定义变量时,需要指定变量的类型,并且可以选择性地为其分配一个初始值。变量的类型决定了它在内存中的大小和布局,以及可以存储在内存中的值的范围。C#支持多种数据类型,包括整数类型、浮点型、十进制类型、布尔类型、字符串和空类型等。
其他语言类同。。。
再看看局部变量:
局部变量,也称内部变量,是指在一个函数内部或复合语句内部定义的变量 [1]。局部变量的作用域是定义该变量的函数或定义该变量的复合语句。局部变量的生存期是从函数被调用的时刻算起到函数返回调用处的时刻结束。
然后让我们看两段代码
传值:
//此处是Main()方法中
int a = 10;
int b = 100;
swap(a, b);
Console.WriteLine($"实际调用完交换方法以后: a={a}:b={b}");
#endregion
}
static void swap(int a,int b)
{
Console.WriteLine($"方法内部交换前:a={a}:b={b}");
int temp = 0;
temp = a;
a=b;
b = temp;
Console.WriteLine($"方法内部交换后: a={a}:b={b}");
}
打印结果为:
可以看到,虽然在方法swap()内部打印的时候,看似a与b已经成功交换,但实际在Main()方法中调用完swap后,实际作为实参的a和b变量内部存储的值并未进行交换。
再看看传引用:
传引用:
//此处是Main()方法中
int a = 10;
int b = 100;
swap(ref a, ref b);
Console.WriteLine($"实际调用完交换方法以后: a={a}:b={b}");
#endregion
}
static void swap(ref int a, ref int b)
{
Console.WriteLine($"方法内部交换前:a={a}:b={b}");
int temp = 0;
temp = a;
a=b;
b = temp;
Console.WriteLine($"方法内部交换后: a={a}:b={b}");
}
打印结果:
可以看到,以传引用的方式进行传参,main()方法中的a和b确实完成了交换
那么古尔丹,代价(原因)是什么?
首先,我们再重新看一遍开篇变量与局部变量的定义,3 2 1.。。。。
好,我们再看看在内存中,变量是如何存储数据的:

本人做了一个简单的表格,用于代表内存。
当我们创建一个变量int a=10的时候,a所代表的就是上图中的000001地址其中存储的数据,也就是说系统在内存中拿了一块地址为000001的存储区交给了变量a来使用,同时将内部数据初始化为10。(上图数据区本应存储10的二进制数据,为了方便理解,我并未进行转换)
然后在我们调用swap(int a,int b)方法的时候:

可以看到,当我们在main()方法中调用swap(a,b)时,因为我们swap(int a,int b)形参列表里面是以变量的形式传入,所以系统便以初始化变量的方式,在内存中又开辟了两块地址用于初始化swap方法的a,b参数(此处已经发现应该在方法中不要使用a,b命名变量,解释起来有些费劲,但是不想改了。。。)
,因为我们实际调用的时候a=10,b=100,所以此时初始化的时候,000008地址内部的数据也就用10来初始化,000009用100初始化。
在方法swap执行的时候,swap方法的变量a和b,在内部确实完成了交换,等同于:

,然后方法内部执行打印操作。
当方法执行完毕的时候,因为swap中的a与b为局部变量,所以自动释放,此时内存中变为:

所以,我们虽然看似以传值的形式进行了a和b的交换,但其原理只是在系统在栈上为方法swap()的形参所申请的2块内存中,将其中的值进行了交换,并不影响Main()中的实参a,b。也就是不影响000001与000002中的数据。
那么传引用呢?
初始化还是一样,但在调用的时候则不同:

当我们调用传引用的方法时可以看到形参列表不再是(int a,int b),而是swap( ref a, ref b),
此处ref a 就代表的是实际调用时候传入的参数在内存中的地址。也就是main()函数中,等于10的变量a的地址,也就是上图中的000001。
在我们在Main()方法中以传引用的形式调用swap(ref a,ref b)后,方法内部不再是交换新建的变量中存储的值,而是实参a和b中存储的值,等同于下图

实际上完成的操作是对实参变量a和b内部数据完成了交换,此时方法执行完毕,再次打印,便会看到a=100,b=10。
以上就是传值与传引用的实际区别。
至于C++中的传指针,我们知道指针的本质就是地址,所以可以理解为与传引用的底层逻辑是完全一样的。
如果此文有用,还望点赞则个。

被折叠的 条评论
为什么被折叠?



