C#数组作为函数参数(附带实例)
一般变量调用函数的传递过程是进行传值调用的过程,在传值的时候,程序可以很顺利地将数据传递给目标函数,然后可以利用 return 回传数据,整个概念如下所示:
从上图可以看到调用方可以利用参数传递数据给目标函数,目标函数则使用 return 回传数据给原始函数,如下所示:
目前流行的 Python 语言,return 可以一次回传多个值,如下:
C# 语言在传递数组时和传递一般变量不同。一般变量在调用函数中的传递过程使用了传值调用(call by value)的概念,也就是将变量内容复制到函数所属变量内存内,这样在传值的时候,可以很顺利地将数据传递给目标函数,但是无法取得回传结果。
C# 在调用函数传递数组时使用了传址调用(call by address)的方式,这种方式的好处是可以有比较高的效率。假设一个数组很大,有 1000 多笔数据,如果采用传值的方式处理,会需要较多的内存空间,同时也会耗用 CPU 时间。如果采用传址的方式,则可以很简单地处理。传递数组到函数后,可以在函数内处理数组内容,更新此数组内容后,再回到调用位置,就可以从数组地址获得新的结果。
例如,设计 Display() 函数可以输出数组内容,主程序则是将数组名传给输出函数 Display():
例如,设计数据交换函数 Swap(),获得失败的结果:
为了改良上述问题可以使用传址的方式调用 Swap() 函数,这时需使用 ref 参数,如下所示:
例如,设计正确的交换函数 Swap():
同样是函数调用,如果将 ref 关键词改为 out 也可以传递地址信息,这时可以不需要初始化变量值,这样函数就可以使用此未初始化的变量,将数值回传。
例如,输入字符串,这个程序会响应有多少个字符‘A’:
例如计算汇率,这个程序会要求输入 VIP 等级,以及美金金额,这个程序会依据 VIP 等级输出可以兑换的金额。
例如:
再例如,计算不同数组数量的总和:
假设所传递的二维数组是 sc,则:
例如,基本二维数组数据传送的应用。本程序的函数会将二维数组各行(row)的前三个元素的平均值,平均分数向下取整数,放在最后一个元素的位置上。
匿名数组的完整意义是,一个可以让我们动态配置的有初始值但是没有名称的数组。
对上述程序的 data 数组而言,如果处理成匿名数组其内容如下:

从上图可以看到调用方可以利用参数传递数据给目标函数,目标函数则使用 return 回传数据给原始函数,如下所示:
return xx;
目前流行的 Python 语言,return 可以一次回传多个值,如下:
return xx, yy;如果使用 C#语言想要回传多个数值,就我们目前所学来看的确没有太便利。
C#数组的传递
如果想要传递多变量数据可以将多变量以数组的形式表达。主程序在调用函数时,将整个数组传递给函数的基础概念如下所示:
C# 语言在传递数组时和传递一般变量不同。一般变量在调用函数中的传递过程使用了传值调用(call by value)的概念,也就是将变量内容复制到函数所属变量内存内,这样在传值的时候,可以很顺利地将数据传递给目标函数,但是无法取得回传结果。
C# 在调用函数传递数组时使用了传址调用(call by address)的方式,这种方式的好处是可以有比较高的效率。假设一个数组很大,有 1000 多笔数据,如果采用传值的方式处理,会需要较多的内存空间,同时也会耗用 CPU 时间。如果采用传址的方式,则可以很简单地处理。传递数组到函数后,可以在函数内处理数组内容,更新此数组内容后,再回到调用位置,就可以从数组地址获得新的结果。
例如,设计 Display() 函数可以输出数组内容,主程序则是将数组名传给输出函数 Display():
void Display(int[] num) { for (int i = 0; i < num.Length; i++) Console.WriteLine($"{num[i]}"); } int[] data = { 5, 6, 7, 8, 9 }; Console.WriteLine("输出数组内容"); Display(data);执行结果为:
输出数组内容
5
6
7
8
9
C#函数使用ref参数交换数据
假设我现在要设计函数 Swap() 将 x 和 y 的数据交换,在没有地址概念前,可能会设计下列程序,而获得失败的结果。例如,设计数据交换函数 Swap(),获得失败的结果:
void Swap(int x, int y) { int tmp; tmp = x; x = y; y = tmp; } int x = 5; int y = 1; Console.WriteLine("执行对调前"); Console.WriteLine($"x = {x} \t y = {y}"); Swap(x, y); Console.WriteLine("执行对调后"); Console.WriteLine($"x = {x} \t y = {y}");执行结果为:
执行对调前
x = 5 y = 1
执行对调后
x = 5 y = 1
为了改良上述问题可以使用传址的方式调用 Swap() 函数,这时需使用 ref 参数,如下所示:
Swap(ref x, ref y); // 关键词ref 可以传递变量x和y的地址所设计的 Swap() 函数也须改由 ref 接收地址参数,如下所示:
Swap(ref int x, ref int y) { ... }
例如,设计正确的交换函数 Swap():
void Swap(ref int x, ref int y) { int tmp; tmp = x; x = y; y = tmp; } int x = 5; int y = 1; Console.WriteLine("执行对调前"); Console.WriteLine($"x = {x} \t y = {y}"); Swap(ref x, ref y); Console.WriteLine("执行对调后"); Console.WriteLine($"x = {x} \t y = {y}");执行结果为:
执行对调前
x = 5 y = 1
执行对调后
x = 1 y = 5
C#函数用关键词out回传数据
函数调用在变量名称使用 ref 关键词时,可以传递地址信息,但是需要初始化变量值。同样是函数调用,如果将 ref 关键词改为 out 也可以传递地址信息,这时可以不需要初始化变量值,这样函数就可以使用此未初始化的变量,将数值回传。
例如,输入字符串,这个程序会响应有多少个字符‘A’:
void CountA(string str, out int counter) { counter = 0; for (int i = 0; i < str.Length; i++) if (str[i] == 'A') counter += 1; } int num; Console.Write("请输入字符串 : "); string mystr = Console.ReadLine(); CountA(mystr, out num); Console.WriteLine($"A 字符的数量 = {num}");执行结果为:
请输入字符串 : ABCDAAA
A 字符的数量 = 4
C#函数只读关键词in
如果在函数声明中增加 in 关键词,则这个关键词是只读关键词,这类关键词的内容在函数内将具有只读属性,假设有一个程序片段与函数如下:void InArgMethod(in int num, ... ) { ... // num 变量只能引用,不可变更其值 } ... int readOnlyNumber = 30; // 定义变量 readOnlyNumber InArgMethod(readOnlyNumber, ... ); // 调用 InArgMethod 函数上述程序定义 InArgMethod() 函数时,从参数行可以知道第 1 个整数参数 num 已经定义为只读,在此函数内 num 的内容只能引用不可更改,只读变量一般应用在需要特别保护的情况中。
例如计算汇率,这个程序会要求输入 VIP 等级,以及美金金额,这个程序会依据 VIP 等级输出可以兑换的金额。
void UsaToNt(int money, in double rate, out double rtn) { rtn = money * rate; } double dollars; Console.Write("请输入 VIP 等级 : "); string vip = Console.ReadLine(); Console.Write("请输入美金金额 : "); int money = Convert.ToInt32(Console.ReadLine()); double rate = 30; // 汇率标准 if (vip == "AAA") rate = 30 * 0.95; // AAA客户可换汇率 else if (vip == "AA") rate = 30 * 0.93; // AA 客户可换汇率 else rate = 30 * 0.9; // 其他客户可换汇率 UsaToNt(money, rate, out dollars); Console.WriteLine($"{vip} 客户 {money} 可以换汇 : {dollars}");执行结果为:
请输入 VIP 等级 : AAA
请输入美金金额 : 100
AAA 客户 100 可以换汇 : 2850
C#函数可变动数量参数params
设计函数时若是在参数行放置 params,则表示在设定可变量的参数,不过只限定是一维数组,声明时需留意后面不可以有其他参数。例如:
void UseParams1(params int[] arr) { for (int i = 0; i < arr.Length; i++) { Console.Write(arr[i] + " "); } Console.WriteLine(); } void UseParams2(params object[] arr) { for (int i = 0; i < arr.Length; i++) { Console.Write(arr[i] + " "); } Console.WriteLine(); } UseParams1(1, 10, 20, 30, 40); UseParams1(5, 15); UseParams1(); // 没有参数则显示空白行 UseParams2(1, 'a', "test", "C语言中文网"); UseParams2("c.biancheng.net", "C语言中文网");执行结果为:
1 10 20 30 40
5 15
1 a test C语言中文网
c.biancheng.net C语言中文网
再例如,计算不同数组数量的总和:
void MySum(params int[] values) { Console.WriteLine(values.Sum().ToString()); } MySum(1, 2, 3, 4, 5); MySum(6, 7); MySum(8, 9, 10);执行结果为:
15
23
27
C#传递二维数组数据
主程序在调用函数时、传递二维数组时,可以只传递数组名,然后由二维数组的 GetLength() 属性获得行(row)数和列(column)数。假设所传递的二维数组是 sc,则:
- sc.GetLength(0):可以取得行(row)数。
- sc.GetLength(1):可以取得列(col)数。
例如,基本二维数组数据传送的应用。本程序的函数会将二维数组各行(row)的前三个元素的平均值,平均分数向下取整数,放在最后一个元素的位置上。
void Average(int[,] sc) { int rows = sc.GetLength(0); // 行数 int cols = sc.GetLength(1); // 列数 int sum; for (int i = 0; i < rows; i++) { sum = 0; for (int j = 0; j < cols; j++) sum += sc[i, j]; // 每一行的总分 sc[i, cols - 1] = sum / 3; // 平均值放入各行最右 } } int[,] num = { { 88, 79, 91, 0 }, { 86, 84, 90, 0 }, { 77, 65, 70, 0 } }; Average(num); for (int i = 0; i < 3; i++) // 打印新的数组 { for (int j = 0; j < 4; j++) Console.Write($"{num[i, j],5}"); Console.WriteLine(); }执行结果为:
88 79 91 86 86 84 90 87 77 65 70 70
C#匿名数组
在执行调用方法时,有时候要传递的是一个数组,可是这个数组可能使用一次以后就不需要再使用,如果我们为此数组重新声明然后配置内存空间,似乎有点浪费系统资源,此时可以考虑使用匿名数组(anonymous array)来处理。匿名数组的完整意义是,一个可以让我们动态配置的有初始值但是没有名称的数组。
int add(int[] nums) { int sum = 0; foreach (int n in nums) sum += n; return sum; } int[] data = { 1, 2, 3, 4, 5 }; Console.WriteLine(add(data));执行结果为:
15
在上述实例中,很明显所声明的数组 data 可能用完就不再需要了,此时可以考虑不要声明数组,直接用匿名数组来处理,将匿名数组当作参数传递。对上述程序的 data 数组而言,如果处理成匿名数组其内容如下:
new int[ ] {1, 2, 3, 4, 5};以声明匿名数组的方式重新设计上面的实例:
int add(int[] nums) { int sum = 0; foreach (int n in nums) sum += n; return sum; } //int[] data = { 1, 2, 3, 4, 5 }; Console.WriteLine(add(new int[] {1, 2, 3, 4, 5}));执行结果为:
15