文章目錄
第四章 函數
很多人到現在還分不清楚什麼是函數,什麼是方法,非常之困惑。其實,這兩種概念是換湯不換藥,講到都是同一種東西。方法是物件導向的產物,比如,我們說使用某的對象的某個方法;函數是面向過程的產物,比如,我們經常會說執行某個函數。不管是函數還是方法,它們的寫法都是一樣的。本章將向大家詳細介紹函數的相關概念。
本章的學習重點:
◆ 函數的參數及傳遞方式
◆ 函數的傳回值
4.2函數分類
本節將向大家介紹函數的重要組成部分:函數的參數和函數的傳回值。同時還向大家介紹函數的傳遞方法:值傳遞法和引用傳遞法,希望對大家有所協助。
4.2.1函數的參數及傳遞方式
在函數定義時,函數名後面圓括弧內的參數稱為形式參數,簡稱形參。下例中的a、b均為形參。
int sum(int a,int b)
{
……//語句體
}
下面的形參定義是錯誤的。
int sum(int a, b)
{
……//語句體
}
在函數調用時,函數名後面圓括弧內的參數稱為實際參數,簡稱實參。實參可以是常量、已賦值的變數或運算式。實參在次序、類型和個數上應與相應形參表中的形參保持一致。下例中的a、b均為實參。
int a = 10;
int b = 100;
int result = sum(a,b);
對於實參,在調用函數中不僅指明它的類型,而且系統還為其分配儲存單元。而對於形參,定義時僅僅只是指明它的類型,並不在記憶體中為它們分配儲存單元。形參只是在調用時才為其分配一個臨時儲存單元標誌,函數執行結束返回調用函數後,該儲存單元標誌立即撤銷。
C#語言中形參與實參之間的傳遞有如下兩種方法。
1.值傳遞法
使用這種方法時,調用函數將實參(常數、變數、或可計算的運算式)的值傳遞到被調用函數形參設定的臨時變數儲存單元中,被調用函數形參值的改變對調用函數的實參沒有影響。調用結束後,形參儲存單元被釋放,實參仍保持原值不變。該方法只能由實參向形參傳遞資料,即單向傳遞。
下面我們來看一個範例:
using System;
namespace Microsoft.Example
{
public class TestValueTransfer
{
static int Power(int i, int n) //定義三次方函數
{
int result = i; //定義一個int變數
for (int j = 0; j < n-1; j++)
{
result = result * i; //實現三次方邏輯
}
return result; //返回結果
}
static void Main(string[] args)
{
int i = 20; //定義一個int變數
Console.WriteLine("值傳遞前,i的值為:" + i);
int result = Power(20, 3); //調用三次方函數
Console.WriteLine("值傳遞後,i的值為:" + i);
Console.WriteLine("i三次方後的結果是:" + result);
}
}
}
上述代碼中,第8行的變數i的初值為20,通過參數傳遞,調用求i的立方的被調函數Power()。運行被調函數時,實參的複製值被傳遞給被調函數中的臨時變數儲存單元i,其值為8000。被調用函數形參值的改變對調用函數的實參沒有影響,調用結束後,形參儲存單元i被釋放,實參i仍保持原值不變,即i=20。
最後的輸出結果是:
值傳遞前,i的值為:20
值傳遞後,i的值為:20
i三次方後的結果是:8000
2.引用傳遞法
在值的傳遞調用中,不能將形參的值返回給實參,但在實際運用中往往需要雙向傳遞,為達此目的,通常使用引用傳遞。
當實參是數組名或對象名時,實參傳遞給形參的是地址。若實參是數組名,則調用函數將實參數組的起始地址傳遞給被調用函數形參的臨時變數單元,而不是傳遞實參數組元素的值。此時,相應的形參可以是形參數組名。在這種傳遞方法下,被調用函數執行時,形參通過實參傳遞來的實參數組的起始地址和下標增量,直接去存取相應的數組元素,故形參值的變化實際上是對調用函數的實參數組元素值的改變。
若實參是對象名時,則調用函數將實參對象所指向單元的地址傳遞給被調用函數形參的臨時變數儲存單元。此時,相應的形參必須是相同的物件類型。在被調用函數執行時,也是直接去訪問相應的單元,形參的變化直接改變調用函數實參相應的單元。
因此,當實參是數組名、對象名時,實參與形參間的傳遞是雙向傳遞,稱“地址的傳遞”。
(1)數組名作為函數參數的表示方法
當數組名作為函數參數時,也需要對其類型進行相應的說明,例如可以寫為:
nt[] values = new int[20];
Test(values);
下面我們來看一個範例:
sing System;
namespace Microsoft.Example
{
public class TestReferTransfer
{
static void Double(int[] values) //定義2倍數函數
{
for (int i = 0; i < values.Length; i++)
{
values[i] = values[i] * 2; //實現2倍邏輯
}
}
static void Main(string[] args)
{
int[] values = { 1,2,3 }; //定義一個int類型的數組
Console.WriteLine("引用傳遞前,values的值為:");
for (int i = 0; i < values.Length; i++)
{
Console.Write(values[i] + " "); //輸出調用函數前的values值
}
Double(values); //調用Double函數
Console.WriteLine();
Console.WriteLine("引用傳遞後,values的值為:");
for (int i = 0; i < values.Length; i++)
{
Console.Write(values[i] + " "); //輸出調用函數後的values值
}
Console.WriteLine();
}
}
}
上述代碼中,第15行的變數values是一個數組,通過引用參數傳遞,調用Double函數,把數組中的所有元素都乘以2。運行被調函數時,數組的引用地址被傳遞給被調函數中的臨時變數儲存單元values。被調用函數形參值的改變對調用函數的實參產生了影響,調用結束後,第15行的數組values裡面的所有元素都被改變了。
最後的輸出結果是:
引用傳遞前,values的值為:
1 2 3
引用傳遞後,values的值為:
2 4 6
作者心得:
注意,用數組名作為函數參數時,必須在調用函數與被調用函數中分別定義數組。並且形參數組與實參數組在類型上應該一致,否則會出錯。當使用數組作為函數參數時,必須先進行初始化,否則,編譯無法通過。
另外,values被定義為具有3個元素的一維整型數組。為了提高函數的通用性,在對形參數組說明時不指定數組的長度,而僅給出類型、數組名和一對方括弧,以便允許同一個函數可根據需要來處理不同長度的數組。
(2)為了使程式能瞭解當前處理的數組的實際長度,往往需要用另一個關鍵字param來配合使用。
下面我們來看一個範例:
using System;
namespace Microsoft.Example
{
public class TestParamTransfer
{
static void Double(params int[] values) //定義2倍數函數
{
for (int i = 0; i < values.Length; i++)
{
values[i] = values[i] * 2; //實現2倍邏輯
Console.Write(values[i] + " "); //輸出結果
}
}
static void Main(string[] args)
{
Double(1, 2, 3, 4, 5); //使用5個參數調用Double函數
Console.WriteLine();
Double(1, 2, 3); //使用3個參數調用Double函數
Console.WriteLine();
}
}
}
上述代碼中,第16行我們使用了5個參數來調用Double函數,而第18行我們使用了3個參數來調用Double函數,這樣做就很方便。我們在講數組的時候知道,數組一定要初始化後才能使用,一旦初始化大小就固定了,而且數組不支援修改大小,這樣就給我們帶來很多的不方便。使用Params關鍵字後,可以給我們的函數帶來更大的方便,更好的重複利用代碼,不用5個參數的定義一個方法,3個參數的再定義一個方法。
最後的輸出結果是:
2 4 6 8 10
2 4 6
4.2.2函數的傳回值
函數調用的目的通常是為了得到一個計算結果或者執行一個操作。為了得到一個結果這個比較容易理解,需要得到結果就肯定需要有地方傳回值;那麼操作呢,就比較容易忽略。比如,我們需要刪除一個檔案,那麼需要告訴調用者,操作是否成功等相關資訊,這個也是需要傳回值的。
利用返回語句return可以將計算結果(即傳回值)返回給調用函數,同時,也使程式的執行流程轉到調用語句的下一語句去執行。
返回語句格式如下:
return(運算式);
或return運算式;
當函數有傳回值時,可以在調用函數的地方,得到返回來的數值,並儲存在一個變數中。函數的傳回值類型一般應當與return語句中的運算式值的類型一致。但是C#語言也允許不同;這時,系統會自動進行隱式類型轉換,使其一致。
當函數沒有傳回值時,函數的傳回值類型可以說明為void型,它表示“無類型”或“空類型”。在調用無傳回值的函數時,往往是以單獨的調用語句出現的。常用的Console.Wrile()函數的調用就是這種形式的函數調用。例如:Console.Wrile(“Hello World!”);只是在螢幕中輸出字串,沒有傳回值。
下面我們來看一個範例:
using System;
namespace Microsoft.Example
{
public class TestReturnValue
{
static int Max(int x, int y) //定義Max函數
{
int z;
z = x > y ? x : y; //比較x,y的大小
return z;
}
static void Main(string[] args)
{
int x, y, result; //定義3個整型變數
Console.WriteLine("請輸入X:");
int.TryParse(Console.ReadLine(), out x); //類型轉換
Console.WriteLine("請輸入Y:");
int.TryParse(Console.ReadLine(), out y); //類型轉換
result = Max(x, y); //調用Max函數
Console.WriteLine("最大的數是:" + result);
}
}
}
上述代碼中,第6行定義了Max函數,用來比較兩個數的大小,然後把較大的那個值返回函數調用處。Max函數定義了傳回型別為int類型,所以ruturn的值也必須是int類型。同時,第19行用來儲存傳回值的result變數也必須是int類型的。
最後的輸出結果是:
請輸入X:
1
請輸入Y:
3
最大的數是:3