哲理
5.1 選擇結構
在人生中我們會遇到各種各樣的選擇,有時候選擇可能會決定一個人的一生。那麼在程序中選擇結構是什麼呢?選擇結構用於判斷給定的條件,根據判斷的結果來決定怎麼執行程序,執行哪一步程序。多數情況下不同的判斷結果,導致程序執行不同的過程或步驟。
在上一章圖4.2 三目運算符一定程度上也就是選擇結構一種普通情況,在圖4.2中我們首先判斷“表達式1”的運行結果是否爲真,如果判斷結果爲真,那麼我們就會執行“表達式2”,如果判斷結果爲假,我們就會執行“表達式3”。在程序執行的過程中,無論判斷結果爲真還是爲假,每一次只能執行“表達式2”或者“表達式3”的其中一種,因此就產生的程序運行過程中相應結果的差異。比如,現實生活中,總有陰天和晴天,那麼我們就可以把“今天下雨”做爲“表達式1”,“拿傘”作爲“表達式2”,“不拿傘”作爲“表達式3”。所以,則有如果“今天下雨”爲真(“表達式1”爲真),即今天要下雨,那麼我們就會很自然的選擇“拿傘”(執行“表達式2”)。反之如果“今天下雨”爲假(“表達式1”爲假),即今天不下雨,那麼我們就不會拿傘了(執行“表達式3”)。具體如圖5.1所示。
如圖5.1,是一個多種選擇結構的流程圖。我們首先進行“判斷1”,如果“判斷1”爲真,就會執行“語句1”,否則執行“判斷2”,最後執行“語句4”。如果“判斷2”爲真,就會執行“語句2”,然後執行“語句4”,否則執行“判斷3”。如果“判斷3”爲真,就會執行“語句3”,然後執行“語句4”,否則直接執行“語句4”。
如圖5.3所示,它是圖5.2的一個實際應用,該圖用於判斷學生成績等級。如果學生成績“大於等於90”爲真,那麼該學生等級爲“優秀”,並加一句鼓勵“繼續努力”,否則學生成績小於90分。然後在判斷學生的成績是不是“大於等於80”。如果成績“大於等於80”爲真,那麼該學生的等級爲“良好”,並加一句鼓勵“繼續努力”,否則該學生的成績小於80分。如果成績“小於等於60”爲真,那麼該學生的等級爲“及格”,並加一句鼓勵“繼續努力”,否則該學生的成績小於60分,只能說句“繼續努力”了。所以同學們要好好學習喲!!!
5.2 if語句選擇結構
在C語言中實現選擇結構時,最常用的是if語句和switch語句。
5.2.1 if語句的基本介紹
if語句有三種一般形式:
-
if(表達式) 語句
-
if(表達式)
語句1
else
語句2
-
if(表達式1) 語句1;
else if(表達式2) 語句2;
else if(表達式3) 語句3;
┇
else if(表達式n) 語句n;
else 語句n+1;
以上三種是最基本if語句的形式。當然還有其他多種類似形式。那麼對於第一種if語句,其功能就是判斷表達式是否爲真,如果爲真,執行“語句”。對於第二種if-else語句,如果“表達式”爲真,執行“語句1”,否則爲假,執行“語句2”。對於第三種if-else if-else語句存在多種可選項,如果“表達式1”爲真,執行“語句1”,否則判斷“表達式2”,如果“表達式2”爲真,則執行“語句2”,依次進行比較。如果表達式都不爲真,執行else,如果有其中的一個表達式爲真,則結束對應的整個if判斷語句。
比如:
-
if(age>18) printf(“你已經成年了”);
-
if(grade > =60) printf(“成績及格\n”);
else printf(“成績不及格\n”);
-
if(grade >=90) printf(“優秀\n”);
else if(grade >=80) printf(“良好\n”);
else if(grade >=60) printf(“及格\n”);
else printf(“繼續努力\n”);
經過上面一堆理論知識的講解,下面將會用幾個實例來證實我們的理論,加深大家對if語句的理解。
【例5.1】輸入一個數,判斷這個數是否大於95?
解題思路:很簡單,用scanf函數從鍵盤接受一個整數,然後用if語句把輸入的數據與95進行比較。最後根據結果給出提示信息。對應上面理論知識部分中if語句的第二種形式。
編寫程序:
#include <stdio.h>
int main()
{
int num;
printf("請輸入一個整數:");
scanf("%d", &num);
if (num >= 95)
{
printf("%d大於等於95。\n", num);
}
else
{
printf("%d小於95。\n", num);
}
return 0;
}
第一次運行結果:
請輸入一個整數:23
23小於95。
Press any key to continue
第二次運行結果:
請輸入一個整數:98
98大於等於95。
Press any key to continue
程序分析:第一次運行結果我們輸入23,用if語句判斷23是否大於等於95,因爲小於95,所以輸出else裏面對應的printf函數。第二次運行結果我們輸入98,因爲98滿足if語句,所以輸出if裏面的printf函數。
【例5.2】比較三個數的大小,按從小到大的順序輸出。
解題思路:我們輸入三個數,讓這三個數兩兩進行比較即可。具體可以參考中學數學中數值比較大小。對應上面理論知識部分中if語句的第一種形式。
編寫程序:
#include <stdio.h>
int main()
{
int first_num,second_num,third_num,tmp_num;
printf("請輸入一個整數:");
scanf("%d,%d,%d", &first_num,&second_num,&third_num);
if (first_num > second_num)
{
tmp_num = first_num;
first_num = second_num;
second_num = tmp_num;
}
if (first_num > third_num)
{
tmp_num = first_num;
first_num = third_num;
third_num = tmp_num;
}
if (second_num > third_num)
{
tmp_num = second_num;
second_num = third_num;
third_num = tmp_num;
}
printf("%d < %d < %d\n", first_num, second_num, third_num);
return 0;
}
運行結果:
請輸入一個整數:12,54,4
4 < 12 < 54
Press any key to continue
程序分析:程序是按照從小到大進行排序的,因爲if語句是如果前一個比後一個大,那麼就把後一個放到後面。經過三個if語句的使用,最終實現排序。
【例5.3】國家稅法規定,工資薪金使用七級超額進制。應交個人所得稅是按個人工資薪金計算交納的個人應交的稅額,以每月收入額減除免稅的個人應負擔的“五險一金”等項目,再減去允許扣除費用3500元(外籍人員按4800元)後的餘額,爲應納稅所得額。
公式:
全月應納稅額 = (工資 — 五險一金 — 3500);
個人應交所得稅 = 全月應納稅額 * 稅率 — 速算扣除數;
七級超額進制:
1. 全月應納稅額不超過1500元的,稅率爲3%,速算扣除數0;
2. 全月應納稅額超過1500元至4500元的部分,稅率爲10%。速算扣除數105元;
3. 全月應納稅額超過4500元至9000元的部分,稅率爲20%。速算扣除數555元;
4. 全月應納稅額超過9000元至35000元的部分,稅率爲25%,速算扣除數1005元;
5. 全月應納稅額超過35000元至55000元的部分,稅率爲30%,速算扣除數2755元;
6. 全月應納稅額超過55000元至80000元的部分,稅率爲35%。速算扣除數5505元;
7. 全月應納稅額超過80000的部分,稅率爲45%。速算扣除數13505元。
注:由於在實際生活中,不同地區的五險一金是不一樣的。所以計算的時候暫時不考慮五險一金。
解題思路:我們根據題目中給出的數學公式即可。這部分只要求大家初中的數學知識足夠。對應上面理論知識部分中if語句的第三種形式。
編寫程序:
#include <stdio.h>
int main()
{
double money_before,money_after;
printf("money is ");
scanf("%lf", &money_before);
if(money_before <= 3500)
{
printf("您的工資達不到基本工資。請向國家申請基本生活保障。\n");
return -1;
}
money_after = money_before-3500;
if( money_after < 1500)
{
money_after = money_after*0.03;
}
else if( money_after < 4500)
{
money_after = money_after*0.1-105;
}
else if( money_after < 9000)
{
money_after = money_after*0.2-555;
}
else if( money_after < 35000)
{
money_after = money_after*0.25-1005;
}
else if( money_after < 55000)
{
money_after = money_after*0.3-2755;
}
else if( money_after < 80000)
{
money_after = money_after*0.35-5505;
}
else
{
money_after = money_after*0.45-13505;
}
printf("工資爲:%0.01f,交稅:%.01f,應得工資:%.01f\n", money_before,money_after,money_before-money_after);
return 0;
}
運行結果:
money is 9500
工資爲:9500.0,交稅:645.0,應得工資:8855.0
Press any key to continue
程序分析:此程序看上去代碼挺多,不過也只是if-else if-else的多個使用而已,看透它,就是紙老虎。
如上我們通過多重if-else-if實現了交稅問題,每一個if或者else-if對應一中收稅的的標準。看上去例5.3程序的代碼中if-else if-else挺多的,那麼是不是我們可以把部分if-else語句放到一個if-else的其中一個子語句中呢?答案是肯定的,那麼寫成這個樣的形式:
if()
{
if(){}else{}
}
else
{
if(){}else{}
}
我們稱這樣形式爲if語句的嵌套。具體請看下節的詳細說明。
5.2.2 多重if語句嵌套
在if語句中包含一個或多個if語句稱爲if語句的嵌套。if語句嵌套的基本形式如圖5.4所示。
在書寫時需要注意if和else配對,else總是與它最近的未配對的if配對。比如,我們把上面的語句進行適當的改變,有如圖5.5形式。圖5.6爲其對應的流程圖。
要求遵循else與最近未匹配的if進行匹配,所以有第一個else與第三個if進行匹配,就是所標記的“內層嵌套”。第二個else與最近未匹配的if進行匹配,由於第三個if已經與第一個else進行了匹配,所以第二個if與第二個else進行匹配。那麼第三個else將會與第一個if進行匹配,因爲後兩個if已經與前兩個else對應匹配了。
但是在編程中爲了能夠更加清楚直觀地瞭解到每個else對應的if,通常會加上一個花括號,用於標記對應if的作用範圍。
如下:
if()
{
if()
{ }
else
{}
}
else
{}
在這個if-else語句中,可以清楚地看出那個else對應那個if,這樣在編程時,特別是編寫較大或者較複雜的程序時,減少出現出現錯誤的可能性。
比如:
if(a>=60)
{
if(a>=85)
{
printf(“優秀!\n”);
}
else
{
printf(“及格!\n”);
}
}
else
{
printf(“繼續努力!\n”);
}
理論講解完成,又到了我們用實踐來檢驗真理的時候!請看下題。
【例5.4】程序實現判斷某一年是否爲閏年?
解題思路:在上一章中的條件運算符與條件表達式一節中的三目運算符就曾被用來判斷那一年是閏年。這個例題我們使用if語句進行閏年的判斷。首先讓我們再加深一下閏年判斷的條件。可以4整除且不可被100整除,或者被400整除的年份都是閏年。我們首先判斷年份能否被4整除,如果不能。註定該年與閏年無緣。否則判斷能否被100整除。如果能這也不是閏年。如果不能,我們在判斷能否被400整除,如果能那就是想要的閏年了,如果不能,嗚嗚,就是平年了。
編寫程序:
#include <stdio.h>
int main()
{
int year, leap;
printf("輸入年份:");
scanf("%d", &year);
if (year%4 == 0)
{
if (year%100 == 0)
{
if (year%400 == 0)
{
leap = 1;
}
else
{
leap = 0;
}
}
else
{
leap = 1;
}
}
else
{
leap = 0;
}
if (leap)
{
printf("%d is ", year);
}
else
{
printf("%d is not ", year);
}
printf("a leap year.\n");
return 0;
}
第一次運行結果:
輸入年份:2008
2008 is a leap year.
Press any key to continue
第二次運行結果:
輸入年份:2006
2006 is not a leap year.
Press any key to continue
程序分析:程序第4行,定義變量leap,實現是閏年還是平年的判斷。當leap爲1時,表示是閏年。leap爲0,表示平年。第7~28行,就是實現判斷是否是閏年的核心代碼。第29~37行,實現最終結果的輸出,相當於提示信息,提示你是閏年還是平年。
5.3 switch語句
5.3.1 switch語句基本介紹
在編程時,如果使用多重的if-else語句,會降低程序執行效率,並且在書寫時也會顯得臃腫不堪。對於一些特定的邏輯結構顯得並不是那麼清晰。比如等級的劃分,省市的劃分,工資的劃分等。
switch語句的基本語法:
switch(表達式)
{
case 常量1: 語句1;
case 常量2: 語句2;
case 常量3: 語句3;
┇ ┇ ┇
case 常量n: 語句n;
default : 語句n+1;
}
如圖5.7和5.8爲switch語句的兩種流程圖。
說明:
- switch後面的“表達式”,數據類型只能是整型或者字符型。
比如:
- switch語句花括號內是一個複合體語句。複合體語句是由若干case語句開頭和default語句結尾的語句組成。每個case後面都有一個常量(或者常量表達式),switch後面的“表達式”,會與每一個case後面的數據進行比較,如果相同就會執行case後面相應的語句,否則執行default後面的語句。
比如:
switch(a%5)
{
case 0:語句1;break;
case 1:語句2;break;
case 2:語句3;break;
default: 語句4;
}
假如a取6,則表達式a%5的餘爲1,所以執行且僅執行第二個case語句,即“case 1:語句2;break;”,但是如果沒有break關鍵字,程序會一直執行到switch語句的結尾或者有break關鍵字處結束。假如a取4,則表達式a%5的餘爲4,和case語句不匹配,所以執行default語句。
- case語句出現的先後順序不影響執行結果。
比如:
switch(a)
{
case ‘D’:…
case ‘B’:…
case ‘C’:…
case ‘A’:…
┇
}
- 每個case後面對應的變量(或常量)是互不相同的,如果相同就會造成歧義。
比如:
switch(a)
{
case ‘A:
case ‘B’:
case ‘A’:
}
在這個switch中,存在case後面對應的常量‘A’重複出現,這樣會造成矛盾現象。
- case標號只起標記作用,執行switch語句時程序就會自動找到對應的標號,然後執行對應標號後面的語句。如果每個case語句之後對應多條語句可以不用花括號標記起來,但是建議標記,這樣有利於提高程序的可讀性。
- 多個case語句可以組成一條語句執行。
比如:
switch(a)
{
case 1:
case 2:
case 3:printf(“hello my girl friend!\n”);break;
case 4:
case 5:printf(“hello my boy friend!\n”);break;
}
如果a爲1,程序會先執行語句“case 1”,由於沒有break語句,然後執行語句“case 2”,語句“case 3”,直到遇到“case 3” 後面的break,結束整個switch語句的執行。
【例5.5】輸入某年某月某日,判斷這一天是這一年的第幾天?
解題思路:以3月1日爲例,我們應該先把前兩個月(1月,2月)的加起來,然後再加上這個月已經過得天數。唯一特殊的是需要判斷輸入的年份是不是閏年,如果是閏年2月是29天,平年是28天。
編程程序:
#include<stdio.h>
int main()
{
int year,month,day;
int l,sum;
char c;
printf("請輸入年月日(格式如2012-1-1):\n");
scanf("%d%c%d%c%d",&year,&c,&month,&c,&day);
switch(month)
{
case 1:sum=0;break;
case 2:sum=31;break;
case 3:
if((year%4==0 && year%100!=0)||(year%400==0))
sum=60;
else
sum=59;
break;
case 4:sum=90;break;
case 5:sum=120;break;
case 6:sum=151;break;
case 7:sum=181;break;
case 8:sum=212;break;
case 9:sum=243;break;
case 10:sum=273;break;
case 11:sum=304;break;
case 12:sum=334;break;
default:printf("date error!\n");
}
sum=sum+day;
printf("%d年%d月%d日是這一年的第%d天。\n", year, month, day,sum);
}
第一次運行結果:
請輸入年月日(格式如2012-1-1):
2012-3-1
2012年3月1日是這一年的第61天。
Press any key to continue
第二次運行結果:
請輸入年月日(格式如2012-1-1):
2013-3-1
2013年3月1日是這一年的第60天。
Press any key to continue
程序分析:程序第9~30行,爲核心代碼。“case 1”表示1月,“case 2”表示2月,依次類推。當輸入的月份爲1月時,那麼這一年的天數就是輸入的天數決定,就是變量day決定。“case 3”表示對2月是不是閏年的判斷,如果是2月就是29天,否則28天。“default”表示輸入的月份不符合要求。
5.3.2 多重switch語句的嵌套
在switch語句中,如果我們在每一個case語句後再添加一個或多個switch語句,就會構成switch的語句的嵌套。
switch語句的嵌套語法:
switch(表達式)
{
case 常量1:
[switch(表達式1)
{
case 常量11: 語句11;
case 常量12: 語句12;
┇
}]
┇
case 常量2:
[switch(表達式2)
{
case 常量21: 語句21;
case 常量22: 語句22;
┇
}]
┇
┇ ┇ ┇
case 常量n:
[switch(表達式n)
{
case 常量n1: 語句n1;
case 常量n2: 語句n2;
┇
}]
┇
default : 語句n+1;
}
如下就是switch語句的嵌套:
switch(a)
{
case 10:
switch(b)
{
case 1:…;break;
case 2:…;break;
┇
default:…
}
break;
case 20:
switch(c)
{
case 3:…;break;
case 4:…;break;
┇
default:…;
}
break;
case 30: …;break;
┇
default: …;
}
如圖5.9所示爲多重switch語句的嵌套流程圖。
【例5.6】部分省市信息查詢系統。
解題思路:此實例爲一個簡單的switch語句,目的就是使大家學會switch語句的使用。具體細節請看代碼。
編寫程序:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num = 0;
printf("*************************\n");
printf("-------部分省份選擇------\n");
printf("*************************\n");
printf("*** 1. 山東省 ***\n");
printf("*** 2. 安徽省 ***\n");
printf("*** 3. 河南省 ***\n");
printf("*** 4. 山西省 ***\n");
printf("*** 0. 退出 ***\n");
printf("*************************\n");
printf("---->>>>");
scanf("%d", &num);
switch(num)
{
case 0:printf("歡迎下次使用!\n");exit(1);
case 1:
printf("*************************\n");
printf("-------部分市區選擇------\n");
printf("*************************\n");
printf("*** 1. 濟南市 ***\n");
printf("*** 2. 青島市 ***\n");
printf("*** 3. 泰安市 ***\n");
printf("*** 4. 菏澤市 ***\n");
printf("*** 5. 濟寧市 ***\n");
printf("*** 0. 退出 ***\n");
printf("*************************\n");
printf("---->>>>");
scanf("%d", &num);
switch(num)
{
case 0:printf("歡迎下次使用!\n");exit(1);
case 1:printf("你選擇的是濟南市!\n");break;
case 2:printf("你選擇的是青島市!\n");break;
case 3:printf("你選擇的是泰安市!\n");break;
case 4:printf("你選擇的是菏澤市!\n");break;
case 5:printf("你選擇的是濟寧市!\n");break;
default:printf("輸入的數據錯誤!\n");exit(1);
}
break;
case 2:
printf("*************************\n");
printf("-------部分市區選擇------\n");
printf("*************************\n");
printf("*** 1. 合肥市 ***\n");
printf("*** 2. 蚌埠市 ***\n");
printf("*** 3. 蕪湖市 ***\n");
printf("*** 4. 安慶市 ***\n");
printf("*** 5. 阜陽市 ***\n");
printf("*** 0. 退出 ***\n");
printf("*************************\n");
printf("---->>>>");
scanf("%d", &num);
switch(num)
{
case 0:printf("歡迎下次使用!\n");exit(1);
case 1:printf("你選擇的是合肥市!\n");break;
case 2:printf("你選擇的是蚌埠市!\n");break;
case 3:printf("你選擇的是蕪湖市!\n");break;
case 4:printf("你選擇的是安慶市!\n");break;
case 5:printf("你選擇的是阜陽市!\n");break;
default:printf("輸入的數據錯誤!\n");exit(1);
}
break;
case 3:
printf("*************************\n");
printf("-------部分市區選擇------\n");
printf("*************************\n");
printf("*** 1. 鄭州市 ***\n");
printf("*** 2. 開封市 ***\n");
printf("*** 3. 洛陽市 ***\n");
printf("*** 4. 焦作市 ***\n");
printf("*** 5. 新鄉市 ***\n");
printf("*** 0. 退出 ***\n");
printf("*************************\n");
printf("---->>>>");
scanf("%d", &num);
switch(num)
{
case 0:printf("歡迎下次使用!\n");exit(1);
case 1:printf("你選擇的是鄭州市!\n");break;
case 2:printf("你選擇的是開封市!\n");break;
case 3:printf("你選擇的是洛陽市!\n");break;
case 4:printf("你選擇的是焦作市!\n");break;
case 5:printf("你選擇的是新鄉市!\n");break;
default:printf("輸入的數據錯誤!\n");exit(1);
}
break;
case 4:
printf("*************************\n");
printf("-------部分市區選擇------\n");
printf("*************************\n");
printf("*** 1. 太原市 ***\n");
printf("*** 2. 大同市 ***\n");
printf("*** 3. 陽泉市 ***\n");
printf("*** 4. 朔州市 ***\n");
printf("*** 5. 臨汾市 ***\n");
printf("*** 0. 退出 ***\n");
printf("*************************\n");
printf("---->>>>");
scanf("%d", &num);
switch(num)
{
case 0:printf("歡迎下次使用!\n");exit(1);
case 1:printf("你選擇的是太原市!\n");break;
case 2:printf("你選擇的是大同市!\n");break;
case 3:printf("你選擇的是陽泉市!\n");break;
case 4:printf("你選擇的是朔州市!\n");break;
case 5:printf("你選擇的是臨汾市!\n");break;
default:printf("輸入的數據錯誤!\n");exit(1);
}
break;
default:printf("輸入的數據錯誤!\n");exit(1);
}
return 0;
}
運行結果:
*************************
-------部分省份選擇------
*************************
*** 1. 山東省 ***
*** 2. 安徽省 ***
*** 3. 河南省 ***
*** 4. 山西省 ***
*** 0. 退出 ***
*************************
---->>>>1
*************************
-------部分市區選擇------
*************************
*** 1. 濟南市 ***
*** 2. 青島市 ***
*** 3. 泰安市 ***
*** 4. 菏澤市 ***
*** 5. 濟寧市 ***
*** 0. 退出 ***
*************************
---->>>>4
你選擇的是菏澤市!
Press any key to continue
程序分析:程序中每一個外層switch語句中,就嵌套一個的switch語句。通過選擇對應的選項輸出對應省市結果。程序中的exit(1)表示退出程序。