参数传递
在调用带有 参数 的函数时,需要将 参数 传递给函数。
先认识一下 形式参数(形参) 和 实际参数(实参) 这两个概念:
形式参数:
在定义函数阶段参数列表中定义的参数称之为形式参数,简称形参,可以将它看作变量的名称,它没有具体的值,只是用来接收函数调用时传递过来的数据;
实际参数:
在函数被调用时传递给函数的参数称之为实际参数,简称实参,可以将它看作变量的值,用来为形参赋值。
示例:
using System;
namespace test
{
class Demo
{
static void Main(string[] args){
Demo Obj = new Demo(); //实例化当前类的对象
string s = "这是一个有参没有返回值的函数!" //定义一个 string 类型的变量 s
Obj.test(s); //调用定义好的 test 函数,需要传入参数
}
/*
* 定义一个有参数的函数
*/
public string test(string str){
Console.WriteLine(str);
}
}
}
如上代码:在 test() 方法中,定义了一个 string 类型的 str 参数变量,则 str 就称为”形式参数“(形参)。str 用来接收 test() 被调用时传过来的参数。main 函数中也定义了一个 string 类型的 s 参数变量,则 s 就被称为“实际参数”(实参),由 ** Obj.test(s); **可以看出,参数 s 的值就是用来传递给 test() 函数的。
三种向方法传递参数的方式
方式 | 描述 |
---|---|
值参数 | 这种方式复制参数的实际值给函数的形式参数,实参和形参使用的是两个不同内存中的值。在这种情况下,当形参的值发生改变时,不会影响实参的值,从而保证了实参数据的安全。 |
引用参数 | 这种方式复制参数的内存位置的引用给形式参数。这意味着,当形参的值发生改变时,同时也改变实参的值。 |
输出参数 | 这种方式可以返回多个值。 |
-
值传递参数
这是参数传递的默认方式。在这种方式下,当调用一个方法时,会为每个值参数创建一个新的存储位置。
实际参数的值会复制给形参,实参和形参使用的是两个不同内存中的值。所以,当形参的值发生改变时,不会影响实参的值,从而保证了实参数据的安全。
using System;
namespace test
{
class Demo
{
static void Main(string[] args){
/* 局部变量定义 */
int val = 10;
Console.WriteLine("调用函数之前:{0}", val);
Demo Obj = new Demo();
Obj.test(val);
Console.WriteLine("调用函数之后:{0}", val);
}
public void test(int i){
i *= i;
Console.WriteLine("函数内部的值:{0}", i);
}
}
}
运行结果:
调用函数之前:10 函数内部的值:100 调用函数之后:10
通过运行结果可以看出,尽管我们在函数内部对形参 val 的值进行的修改,但是并不会影响函数外面实参 val 的值。
在调用 test() 函数前,val 的值为 10 ,调用 test() 函数时,变量 i 接收了 val 传过来的值(10),所以 test() 内部的参数 i 的值为10,因为需要进行 i *=i 运算,所以此时 test() 内部的参数 i 的值为10 x 10 = 100。调用 test() 函数之后,因为传递给 test() 函数的参数 val的值等于10,所以调用之后,val的值还是10。
-
引用传递参数
引用参数是一个对变量的 内存位置的引用 。当按引用传递参数时,与值参数不同的是,它不会为这些参数创建一个新的存储位置。引用参数表示与提供给方法的实际参数具有相同的内存位置。
在 C# 中,需要使用 ref 关键字声明引用参数。
using System; namespace test { class Demo { static void Main(string[] args){ int val = 10; Demo Obj = new Demo(); Console.WriteLine("调用函数之前:{0}", val); Obj.test(ref val); Console.WriteLine("调用函数之后:{0}", val); } public void test(ref int i){ i *= i; Console.WriteLine("函数内部的值:{0}", i); } } }
运行结果:
调用函数之前:10 函数内部的值:100 调用函数之后:100
结果表明,test 函数内的值改变了。在 test 函数没调用之前 val 的值为10。**Obj.test(ref val) ** 在调用 test() 是说那个了关键字 **ref ** 关键字。在定义函数时需要加入 ref 关键字(public void test(ref int i){ }),在调用这个函数时也要加入关键字 ref ,比如:Obj.test(ref val)
-
输出传递参数
使用 return 语句可以从函数中返回一个值,但是使用输出传递则可以从函数中一次性返回多个值。输出传递与引用传递相似,不同之处在于输出传递是将数据从函数中传输出来而不是传输到函数中。
在 C# 中,需要使用 out 关键字来使用输出传递
using System; namespace test { class Demo { static void Main(string[] args){ // int val = 33; Demo Obj = new Demo(); // Console.WriteLine("调用函数之前 val 的值:{0}", val); int val; int i; Obj.test(out val,out i); Console.WriteLine("调用函数之后 val 的值:{0}", val); Console.WriteLine("调用函数之后 i 的值:{0}", i); } public void test(out int x,out int y){ y = 10; y *= y; int temp = 11; x = temp; x *= x; Console.WriteLine("函数内部 x 的值:{0}", x); Console.WriteLine("函数内部 temp 的值:{0}", temp); } } }
运行结果:
函数内部 x 的值:121
函数内部 temp 的值:11
调用函数之后 val 的值:121
调用函数之后 i 的值:100
结果表明,使用输出传递参数,在调用 test()方法时,参数不需要赋值;**test()**方法执行时,y 的值为100,temp的值为11,x 的值为
121。main函数中的 val 和 i 就是用来接收 test() 方法输出的 x(121) 和 y(100) 的参数。相当于,接收 test() 方法的 return 返返返回值。但是,return 只能返回一个值,out 输出可以返回多个值。
注意:如果在调用函数前,定义了参数并赋值,在调用函数时,定义参数的值无效。也就是说,参数只会拿到被调用方法输出的值。
using System;
namespace test
{
class Demo
{
static void Main(string[] args){
int val = 33;
int i = 55;
Demo Obj = new Demo();
// Console.WriteLine("调用函数之前 val 的值:{0}", val);
// int val;
// int i;
Obj.test(out val,out i);
Console.WriteLine("调用函数之后 val 的值:{0}", val);
Console.WriteLine("调用函数之后 i 的值:{0}", i);
}
public void test(out int x,out int y){
y = 10;
y *= y;
int temp = 11;
x = temp;
x *= x;
// Console.WriteLine("函数内部 x 的值:{0}", x);
// Console.WriteLine("函数内部 temp 的值:{0}", temp);
}
}
}
运行结果:
调用函数之后 val 的值:121 调用函数之后 i 的值:100
结果表明,调用函数之前的 val = 33,i = 55,这些参数的值都是无效的。