循環結構又稱重複結構,是程式的 3 種基本結構之一。它反複執行循環體内的代碼,解決需要大量重複處理的問題。循環結構由循環控制語句實作,其中内建有條件控制語句,用來判讀是否繼續執行循環操作。C 語言提供了 while 語句、do-while 語句、for 語句 3 種基本的循環控制語句,并且可以互相嵌套使用。
3.4.1 while 語句
while 語句是“當”型循環控制語句,即在條件滿足時執行循環體,否則跳過或跳出循環體。while 語句的一般形式為:
while (條件表達式) { 循環體; }
如下例所示,求階乘 n! 的結果:
int n = 1, p; // 聲明整型變量 n 和 p,n 用于控制步進,p 用于儲存操作數
double s = 1; // 聲明雙精度變量 s, s用于儲存計算結果
printf("請輸入操作數 (1 - 170):"); // 輸出操作提示資訊
scanf("%d", &p); // 擷取操作數,儲存到變量 p 中
while (n <= p) // 當步進值不大于操作數時,執行循環體
{
s *= n++; // 将上一次的計算結果 s 與 步長值 n 相乘,并儲存新的計算結果到 s,計算完成後步進值 n 自增
}
printf("\n階乘 n = %d 的結果為:%fd \n", p, s); // 輸出操作結果
上例使用循環控制語句進行階乘操作,while語句中的表達式用于判斷目前階乘的步進值是否大于輸入的操作數。如果不大于則繼續進行運算,否則結束循環。
提示:階乘(factorial)是基斯頓.卡曼(1760 - 1826)于1808年發明的運算符号。階乘指從 1 乘以 2 乘以 3 乘以 4 一直乘到所要求的數。例如操作數是 4,則階乘式是 1 x 2 x 3 x4,得到的結果是 24,24就是 4 的階乘。階乘的計算會産生相當巨大的結果,在 C 語言的基本資料類型中字長最大的 double 型,也隻能儲存 170!的運算結果。當然,有很多方法可以儲存更大的階乘結果,有興趣的可以探索這一問題。
3.4.2 do-while 語句
在 C語言中,“直到” 型循環是 do-while 語句,一般的形式為:
do { 循環體 } while { 條件表達式 }
與 while 語句的差別是,while 是先判讀條件表達式再去執行循環體,而 do-whie 語句是先執行循環體再判讀條件表達式。也就是說,do-while 語句會首先将循環體執行一次,再判斷是否應該結束循環。例如計算 sin(x) 的值算法是“x - x3/3! + x5/5! - x7/7(......)”直到最後一項小于 1e-7 時為止,可用下例代碼描述:
#include <stuio.h>
#include <math.h> // 加入數學函數庫,以提供幂運算函數 fabs()
int main()
{
double s, t, x; // 定義雙精度型變量 s、t、x,其中 s 儲存計算結果,t 表示下一項的結果,x 表示操作數
int n; // n表示公式中的 幂
printf("請輸入 x 的值:");
scanf("%lf", &x); // 擷取操作數
t = x; // 使 t 的值等于 x,得到公式中的第一項的值
n = 1; // 初始化幂數 n 為 1
s = x; // 将第一項的結果儲存到結果 s 中
do
{
n += 2;
t *= (-x * x) / ((float)(n) - 1) / (float) (n);
s += t;
}
while (fabs(t) >= le-7);
printf("\nsin(%f) = %lf\n", x, s);
return 0;
}
上例中,使用循環控制語句依次将公式中的每一項加入結果中,從上一項推算目前項的結果隻用将上一項乘以因子(x2)/((n-1) * n),即代碼第 16 行所示。函數fabs()由頭檔案 math.h提供,作用是取絕對值。當輸入 x 的值為 1.5753時,運算結果為 0.999 990。
3.4.3 for 語句
for 語句使用于可預知執行次數的循環控制結構,是 C 語言中最常用的循環控制語句。for 語句的一般形式為:
for (<表達式1>; <表達式2>; <表達式3>) { 循環體 }
表達式1 用于為控制變量賦初始值,表達式2用于放置循環控制條件的邏輯表達式,表達式3用于改變變量的值。這種結構能明确地展現循環控制結構中的 3 個重要組成部分,即控制變量的初始值、循環條件 和 控制變量 的改變。如計算自然數數列 1 至 n 的平方和,可用下列代碼描述:
int i, p;
double s = 0;
printf("請輸入操作數:\n");
scanf("%d", &p);
for (i = 1; i <= p; i++)
{
s += (double) i * (double) i;
}
printf("自然數 1 至 %d 平方和為:%lf\n", p, s);
for語句的 3個表達式都可以省略,或者放置在 for 語句的參數集合外,但不能省略表達式之間的分号,否則會造成文法錯誤。
注意:在編寫循環結構的程式時,如果循環控制條件不能有效地結束,就會出現死循環,這是程式員經常會碰到的問題。含有死循環的代碼能被編譯器編譯,但運作該程式會造成循環體無休止地被執行,消耗系統資源,嚴重的會造成系統當機。Linux系統針對死循環有良好的控制機制,不會讓一個程序無休止地占據所有CPU資源,進而避免當機現象。當然,死循環在某些情況下存在是合理的,例如硬體驅動程式,通信程式和裝置控制程式中,都需要用死循環反複無休止地處理某些問題。while(1) 和 for(;;) 常被生成死循環。
3.4.4 break 與 continue 語句
如果需要在循環體的執行過程中結束某一輪循環,或者直接跳出循環,可以使用 break 或 continue 語句。
break 語句的作用是立即結束目前循環并跳出循環體。下例用一個有趣的計算題說明該語句的使用方法,一隻蝸牛順着葡萄架向上爬,葡萄架高 11 米,蝸牛每天白天可以向上爬 3 米,但晚上會滑下來 1 米,問該蝸牛幾天能夠爬到葡萄架的頂端,程式代碼如下:
int i = 1, s = 0; // 定義變量 i 和 s,表示天數,s 表示已爬上的高度
const int h = 11; // 定義常量 h,h 表示總高
const int up_move = 3; // 定義常量 up_move,up_move 表示每天爬上的高度
const int down_move = 1; // 定義常量 down_move,down_move 表示每天滑下的高度
while (s <= h) // 當 s 不大于 h 時,執行循環體
{
s += up_move; // 将已爬上的高度加上當天爬上的高度
if (s >= h) // 判讀已爬上的高度是否不小于總高度
{
break; // 結束目前循環,并跳出循環體
}
s -= down_move; // 将已爬上的高度減去當天滑下的高度
i++; // 天數自增
}
printf("蝸牛需要 %d 天爬到葡萄架頂\n", i); // 輸出結果
int n1 = 1, nm = 100; // 定義查找範圍
int i, j, flag; // 定義循環控制變量
if (n1 == 1 || n1 == 2) // 處理素數 2
{
printf("%4d", 2); // 輸出素數 2
n1 = 3; // 将查找範圍移動到 2 以後
}
for (i = n1; i <= nm; i++)
{
if (!(i % 2))
{
continue; // 如果目前的數能被 2 整除,則結束該輪循環,該數不是素數
}
for (flag = 1, j = 3; flag && j < i / 2; j += 2) // 從 3 開始周遊至 i x 1/2,每次步進 2
{
if (!(i % j))
{
flag = 0; // 若能整除,則不是素數
}
}
if (flag)
{
printf("%4d", i); // 如果是素數,則輸出該數
}
}