- C#入門經典(第7版):C# 6.0 & Visual Studio 2015(.NET開發經典名著)
- (美)Beijamin Perkins Jacob Vibe Hammer Jon D. Reid
- 1845字
- 2021-04-02 21:18:35
4.3 循環
循環就是重復執行語句。這個技術使用起來非常方便,因為可以對操作重復任意多次(數千次,甚至數百萬次),而不必每次都編寫相同的代碼。
舉一個簡單例子,下面的代碼計算一個銀行賬戶在10年后的金額,假定支付每年的利息,且該賬戶沒有其他款項的存?。?/p>
double balance = 1000; double interestRate = 1.05; // 5% interest/year balance *= interestRate; balance *= interestRate; balance *= interestRate; balance *= interestRate; balance *= interestRate; balance *= interestRate; balance *= interestRate; balance *= interestRate; balance *= interestRate; balance *= interestRate;
將相同代碼編寫10次很費時間,如果把10年改為其他值,又會如何?那就必須把該代碼行手工復制需要的次數,這是一件多么痛苦的事!幸運的是,完全不必這樣做。使用一個循環就可以對指令執行需要的次數。
循環的另一種重要類型是一直循環到給定的條件滿足為止。這些循環比上面描述的循環稍簡單些(但同樣很有用),所以首先從這類循環開始介紹。
4.3.1 do循環
do循環以下述方式執行:執行標記為循環的代碼,然后進行一個布爾測試,如果測試結果為true,就再次執行這段代碼,并重復這個過程。當測試結果為false時,就退出循環。
do循環的結構如下:
do { <code to be looped> } while (<Test>);
其中,計算<Test>會得到一個布爾值。
注意:while語句之后必須使用分號。
例如,使用該結構可以把從1到10的數字輸出到一列:
int i = 1; do { WriteLine("{0}", i++); } while (i <= 10);
在把i的值寫到屏幕上后,使用后綴形式的++運算符遞增i的值,所以需要檢查一下i <= 10,把10也包含在輸出到控制臺的數字中。
下面的示例使用這個結構略微修改一下本節前面的代碼。該段代碼計算一個賬戶在10年后的余額。這次使用一個循環,根據起始的金額和固定利率,計算該賬戶的金額需要多少年才能達到某個指定的數額。
試一試:使用do循環:Ch04Ex04\Program.cs
(1)在目錄C:\BegVCSharp\Chapter04創建一個新的控制臺應用程序Ch04Ex04。
(2)把下述代碼添加到Program.cs中:
static void Main(string[] args) { double balance, interestRate, targetBalance; WriteLine("What is your current balance? "); balance = ToDouble(ReadLine()); WriteLine("What is your current annual interest rate (in %)? "); interestRate = 1 + ToDouble(ReadLine()) / 100.0; WriteLine("What balance would you like to have? "); targetBalance = ToDouble(ReadLine()); int totalYears = 0; do { balance *= interestRate; ++totalYears; } while (balance < targetBalance); WriteLine($"In {totalYears} year{(totalYears == 1 ? "": "s")} you'll have a balance of {balance}."); ReadKey(); }
(3)執行代碼,輸入一些值,示例結果如圖4-4所示。

圖4-4
示例說明
這段代碼利用固定的利率,對年度計算余額的過程重復必要的次數,直到滿足結束條件為止。在每次循環中,遞增一個計數器變量,就可以確定需要多少年:
int totalYears = 0; do { balance *= interestRate; ++totalYears; } while (balance < targetBalance); 然后就可以將這個計數器變量用作輸出結果的一部分: WriteLine($"In {totalYears} year{(totalYears == 1 ? "": "s")} you'll have a balance of {balance}.");
注意:這可能是?: (三元)運算符最常見的用法了—— 用最少的代碼有條件地格式化文本。這里,如果totalYears不等于1,就在year后面輸出一個s。
但這段代碼并不完美,考慮一下目標余額少于當前余額的情況,則結果應如圖4-5所示。

圖4-5
do循環至少執行一次。有時(如這個示例)這并不是很理想。當然,可以添加一條if語句:
int totalYears = 0; if (balance < targetBalance) { do { balance *= interestRate; ++totalYears; } while (balance < targetBalance); } WriteLine($"In {totalYears} year{(totalYears == 1 ? "": "s")} " + $"you'll have a balance of {balance}.");
這顯然無謂地增加了復雜性。更好的解決方案是使用while循環。
4.3.2 while循環
while循環非常類似于do循環,但有一個明顯區別:while循環中的布爾測試在循環開始時進行,而不是最后進行。如果測試結果為false,就不會執行循環。程序會直接跳轉到循環之后的代碼。
按下述方式指定while循環:
while (<Test>) { <code to be looped> }
使用方式幾乎與do循環完全相同,例如:
int i = 1; while (i <= 10) { WriteLine($"{i++}"); }
這段代碼的執行結果與前面的do循環相同,它在一列中輸出從1到10的數字。下面使用while循環修改上一個示例。
試一試:使用while循環:Ch04Ex05\Program.cs
(1)在目錄C:\BegVCSharp\Chapter04中創建一個新的控制臺應用程序Ch04Ex05。
(2)修改代碼,如下所示(使用Ch04Ex04中的代碼作為起點,記住刪除原來do循環最后的while語句):
static void Main(string[] args)
{
double balance, interestRate, targetBalance;
WriteLine("What is your current balance? ");
balance = ToDouble(ReadLine());
WriteLine("What is your current annual interest rate (in %)? ");
interestRate = 1 + ToDouble(ReadLine()) / 100.0;
WriteLine("What balance would you like to have? ");
targetBalance = ToDouble(ReadLine());
int totalYears = 0;
while (balance < targetBalance)
{
balance *= interestRate;
++totalYears;
}
WriteLine($"In {totalYears} year{(totalYears == 1 ? "": "s")} " +
$"you'll have a balance of {balance}.");
if (totalYears == 0)
WriteLine(
"To be honest, you really didn't need to use this calculator.");
ReadKey();
}
(3)再次執行代碼,但這次使用少于起始余額的目標余額,如圖4-6所示。

圖4-6
示例說明
這段代碼只是把do循環改為while循環,就解決了上個示例中的問題。把布爾測試移到開頭處,就考慮了不需要執行循環的情況,可以直接跳轉到輸出結果。
當然,這種情況還有一個解決方案。例如,可以檢查用戶輸入,確保目標余額大于起始余額。此時,可以把用戶輸入部分放在循環中,如下所示:
WriteLine("What balance would you like to have? ");
do
{
targetBalance = ToDouble(ReadLine());
if (targetBalance <= balance)
WriteLine("You must enter an amount greater than " +
"your current balance! \nPlease enter another value.");
}
while (targetBalance <= balance);
這將拒絕接受無意義的值,得到如圖4-7所示的結果。

圖4-7
在設計應用程序時,用戶輸入的有效性檢查是一個很重要的主題,本書將列舉更多這方面的示例。
4.3.3 for循環
本章介紹的最后一類循環是for循環。這類循環可以執行指定的次數,并維護它自己的計數器。要定義for循環,需要下列信息:
● 初始化計數器變量的一個起始值。
● 繼續循環的條件,應涉及計數器變量。
● 在每次循環的最后,對計數器變量執行一個操作。
例如,如果要在循環中,使計數器從1遞增到10,遞增量為1,則起始值為1,條件是計數器小于或等于10,在每次循環的最后,要執行的操作是給計數器加1。
這些信息必須放在for循環的結構中,如下所示:
for (<initialization>; <condition>; <operation>) { <code to loop> }
它的工作方式與下述while循環完全相同:
<initialization> while (<condition>) { <code to loop> <operation> }
前面使用do和while循環輸出了從1到10的數字。下面看看如何使用for循環完成這個任務:
int i; for (i = 1; i <= 10; ++i) { WriteLine($"{i}"); }
計數器變量是一個整數i,它的初始值是1,在每次循環的最后遞增1。在每次循環過程中,把i的值寫到控制臺。
注意,當i的值為11時,將執行循環后面的代碼。這是因為在i等于10的循環末尾,i會遞增為11。這是在測試條件i <= 10之前發生的,此時循環結束。與while循環一樣,在第一次執行前,只在條件計算為true時才執行for循環,所以可能根本就不會執行循環中的代碼。
最后注意,可將計數器變量聲明為for語句的一部分,重新編寫上述代碼,如下所示:
for (int i = 1; i <= 10; ++i) { WriteLine($"{i}"); }
但如果這么做,就不能在循環外部使用變量i (參見第6章中的“變量的作用域”一節)。
4.3.4 循環的中斷
有時需要更精細地控制循環代碼的處理。C#為此提供了以下命令:
● break—— 立即終止循環。
● continue——立即終止當前的循環(繼續執行下一次循環)。
● return—— 跳出循環及包含該循環的函數(參見第6章)。
break命令可退出循環,繼續執行循環后面的第一行代碼,例如:
int i = 1; while (i <= 10) { if (i == 6) break; WriteLine($"{i++}"); }
這段代碼輸出1-5的數字,因為break命令在i的值為6時退出循環。
continue僅終止當前迭代,而不是整個循環,例如:
int i; for (i = 1; i <= 10; i++) { if ((i % 2) == 0) continue; WriteLine(i); }
在上面的示例中,只要i除以2的余數是0, continue語句就終止當前的迭代,所以只顯示數字1、3、5、7和9。
4.3.5 無限循環
在代碼編寫錯誤或故意進行設計時,可以定義永不終止的循環,即所謂的無限循環。例如,下面的代碼就是無限循環的一個簡單例子:
while (true) { // code in loop }
有時這種代碼也是有用的,而且使用break語句或者手工使用Windows任務管理器總是可以退出這樣的循環。但當出現這種情形意外時,就會出問題。考慮下面的循環,它與上一節的for循環非常類似:
int i = 1; while (i <= 10) { if ((i % 2) == 0) continue; WriteLine($"{i++}"); }
i是在循環的最后一行代碼(即continue語句后的那條語句)執行完后才遞增的。如果程序執行到continue語句(此時i為2),程序會用相同的i值進行下一個循環,然后測試這個i值,繼續循環,一直這樣下去。這就凍結了應用程序。注意仍可以用一般方式退出已凍結的應用程序,所以不必重新啟動計算機。