C的條件運算符
switch語句
break、 continue和goto語句
使用C的字符I/O函數(shù): getchar()和putchar()
ctype.h頭文件提供的字符分析函數(shù)系列
while循環(huán)的測試條件利用scanf()的返回值來結(jié)束循環(huán)抵栈, 因為scanf()在讀到非數(shù)字字符時會返回0佛玄。 temperature的類型是float而不是int, 這樣程序既可以接受-2.5這樣的值惠赫, 也可以接受8這樣的值目锭。
該程序示例把計算后的百分比強(qiáng)制轉(zhuǎn)換為 float類型和泌。 其實村缸, 也不必使用強(qiáng)制類型轉(zhuǎn)換, 因為在表達(dá)式100.0 * cold_days /all_days中武氓, 將首先對表達(dá)式100.0 * cold_days求值梯皿, 由于C的自動轉(zhuǎn)換類型規(guī)則, 乘積會被強(qiáng)制轉(zhuǎn)換成浮點數(shù)县恕。
使用強(qiáng)制類型轉(zhuǎn)換可以明確表達(dá)轉(zhuǎn)換類型的意圖东羹, 保護(hù)程序免受不同版本編譯器的影響。 if語句被稱為分支語句(branching statement) 或選擇語句(selection statement) 忠烛, 因為它相當(dāng)于一個交叉點属提, 程序要在兩條分支中選擇一條執(zhí)行。
if else語句
簡單形式的if語句可以讓程序選擇執(zhí)行一條語句, 或者跳過這條語句冤议。C還提供了if else形式斟薇, 可以在兩條語句之間作選擇。
if (all_days != 0)
printf("%d days total: %.1f%% were below freezing.\n",
all_days, 100.0 * (float) cold_days / all_days);
if (all_days == 0)
printf("No data entered!\n");
如果程序發(fā)現(xiàn)all_days不等于0恕酸, 那么它應(yīng)該知道另一種情況一定是all_days等于0堪滨。
if (all_days!= 0)
printf("%d days total: %.1f%% were below freezing.\n",
all_days, 100.0 * (float) cold_days / all_days);
else
printf("No data entered!\n");
如果if語句的測試表達(dá)式為真, 就打印溫度數(shù)據(jù)蕊温; 如果為假袱箱, 就打印警告消息。
if else語句的通用形式是:
if ( expression )
statement1
else
statement2
如果expression為真(非0) 义矛, 則執(zhí)行statement1发笔; 如果expression為假或0, 則執(zhí)行else后面的statement2凉翻。 statement1和statement2可以是一條簡單語句或復(fù)合語句了讨。
if語句用于選擇是否執(zhí)行一個行為, 而else if語句用于在兩個行為之間選擇噪矛。
另一個示例: 介紹getchar()和putchar()
getchar()函數(shù)不帶任何參數(shù)量蕊, 它從輸入隊列中返回下一個字符。
ch = getchar();
該語句與下面的語句效果相同:
scanf("%c", &ch);
putchar()函數(shù)打印它的參數(shù)艇挨。
putchar(ch);
該語句與下面的語句效果相同:
printf("%c", ch);
由于這些函數(shù)只處理字符, 所以它們比更通用的scanf()和printf()函數(shù)更快韭赘、 更簡潔缩滨。 而且, 注意 getchar()和 putchar()不需要轉(zhuǎn)換說明泉瞻, 因為它們只處理字符脉漏。 這兩個函數(shù)通常定義在 stdio.h頭文件中
ctype.h系列的字符函數(shù)
C 有一系列專門處理字符的函數(shù), ctype.h頭文件包含了這些函數(shù)的原型袖牙。 這些函數(shù)接受一個字符作為參數(shù)侧巨, 如果該字符屬于某特殊的類別, 就返回一個非零值(真) 鞭达; 否則司忱, 返回0(假) 。如果isalpha()函數(shù)的參數(shù)是一個字母畴蹭, 則返回一個非零值坦仍。
字符映射函數(shù)不會修改原始的參數(shù), 這些函數(shù)只會返回已修改的值叨襟。
多重選著else if
在程序中也可以用else if擴(kuò)展if else結(jié)構(gòu)模擬這種情況繁扎。
用符號常量表示不同的費率和費率分界點, 以便把常量統(tǒng)一放在一處。
該程序由一個ifelse語句組成梳玫, else部分包含另一個if else語句爹梁, 該if else語句的else部分又包含另一個if else語句。 第2個if else語句嵌套在第 1個if else語句中提澎, 第3個if else語句嵌套在第2個if else語句中姚垃。
整個if else語句被視為一條語句, 因此不必把嵌套的if else語句用花括號括起來虱朵。
else與if配對
if (number > 6)
if (number < 12)
printf("You're close!\n");
else
printf("Sorry, you lose a turn!\n");
else與第2個if匹配莉炉。 也就是說, 輸入的數(shù)字和匹配的響應(yīng)如下:
數(shù)字 響應(yīng)
5 None
10 You’re close!
15 Sorry, you lose a turn!
如果沒有花括號碴犬, else與離它最近的if匹配絮宁, 除非最近的if被花括號括起來。
要縮進(jìn)“語句”服协, “語句”可以是一條簡單語句或復(fù)合語句绍昂。
多層嵌套的if語句
從一系列選項中選擇一個執(zhí)行。 有時偿荷, 選擇一個特定選項后又引出其他選擇窘游, 這種情況可以使用另一種嵌套if。
這種形式的嵌套if應(yīng)用在下面的程序中跳纳。 給定一個整數(shù)忍饰, 顯示所有能整除它的約數(shù)。 如果沒有約數(shù)寺庄, 則報告該數(shù)是一個素數(shù)艾蓝。
要總體設(shè)計一下程序。 為方便起見斗塘, 程序應(yīng)該使用一個循環(huán)讓用戶能連續(xù)輸入待測試的數(shù)赢织。 這樣, 測試一個新的數(shù)字時不必每次都要重新運行程序馍盟。
提示用戶輸入數(shù)字
當(dāng)scanf()返回值為1
分析該數(shù)并報告結(jié)果
提示用戶繼續(xù)輸入
回憶一下在測試條件中使用scanf()于置, 把讀取數(shù)字和判斷測試條件確定是否結(jié)束循環(huán)合并在一起。
設(shè)計如何找出約數(shù)贞岭。
for (div = 2; div < num; div++)
if (num % div == 0)
printf("%d is divisible by %d\n", num, div);
該循環(huán)檢查2~num之間的所有數(shù)字八毯, 測試它們是否能被num整除。
必須測試的數(shù)只要到num的平方根就可以了曹步, 不用到num宪彩。
不使用平方根而用這樣的測試條件, 有兩個原因讲婚。 其一尿孔, 整數(shù)乘法比求平方根快。 其二, 我們還沒有正式介紹平方根函數(shù)活合。
for (div = 2; (div * div) <= num; div++)
{?
if(num % div == 0)
{?
if(div * div != num)
printf("%d is divisible by %d and %d.\n",num, div, num / div);
else
printf("%d is divisible by %d.\n", num, div);
}
}
if else語句作為一條單獨的語句雏婶, 不必使用花括號。 外層if也是一條單獨的語句白指, 也不必使用花括號留晚。 但是, 當(dāng)語句太長時告嘲, 使用花括號能提高代碼的可讀性错维, 而且還可防止今后在if循環(huán)中添加其他語句時忘記加花括號。
如何知道一個數(shù)字是素數(shù)橄唬? 如果num是素數(shù)赋焕, 程序流不會進(jìn)入if語句。 要解決這個問題仰楚, 可以在外層循環(huán)把一個變量設(shè)置為某個值(如隆判, 1) , 然后在if語句中把該變量重新設(shè)置為0僧界。 循環(huán)完成后侨嘀, 檢查該變量是否是1, 如果是捂襟, 說明沒有進(jìn)入if語句咬腕, 那么該數(shù)就是素數(shù)。 這樣的變量通常稱為標(biāo)記(flag) 葬荷。
C都習(xí)慣用int作為標(biāo)記的類型郎汪, 其實新增的_Bool類型更合適。 另外闯狱, 如果在程序中包含了stdbool.h頭文件, 便可用bool代替_Bool類型抛计, 用true和false分別代替1和0哄孤。
小結(jié): 用if語句進(jìn)行選擇
關(guān)鍵字: if、 else
一般注解:
下面各形式中吹截, statement可以是一條簡單語句或復(fù)合語句瘦陈。 表達(dá)式為真說明其值是非零值。
形式1:
if (expression)
statement
如果expression為真波俄, 則執(zhí)行statement部分晨逝。
形式2:
if (expression)
statement1
else
statement2
如果expression為真, 執(zhí)行statement1部分懦铺; 否則捉貌, 執(zhí)行statement2部分。
形式3:
if (expression1)
statement1
else if (expression2)
statement2
else
statement3
如果expression1為真, 執(zhí)行statement1部分趁窃; 如果expression2為真牧挣, 執(zhí)行statement2部分; 否則醒陆, 執(zhí)行statement3部分瀑构。
if (legs == 4)
printf("It might be a horse.\n");
else if (legs > 4)
printf("It is not a horse.\n");
else /* 如果legs < 4 */
{?
legs++;
printf("Now it has one more leg.\n");
}
邏輯運算符
要編寫一個程序, 計算輸入的一行句子中除單引號和雙引號以外其他字符的數(shù)量刨摩。 這種情況下可以使用邏輯運算符寺晌, 并使用句點(.) 標(biāo)識句子的末尾。
if語句的測試條件中使用了邏輯與運算符&&澡刹。 該 if語句翻譯成文字是“如果待測試的字符不是雙引號呻征, 并且它也不是單引號,那么charcount遞增1”像屋。
邏輯運算符兩側(cè)的條件必須都為真怕犁, 整個表達(dá)式才為真。 邏輯運算符的優(yōu)先級比關(guān)系運算符低己莺, 所以不必在子表達(dá)式兩側(cè)加圓括號奏甫。
備選拼寫:iso646.h頭文件
C99標(biāo)準(zhǔn)新增了可代替邏輯運算符的拼寫, 它們被定義在ios646.h頭文件中凌受。 如果在程序中包含該頭文件阵子, 便可用and代替&&、 or代替||胜蛉、 not代替!挠进。
if (ch != '"' && ch != '\'')
charcount++;
改寫為:
if (ch != '"' and ch != '\'')
charcount++;
C一直堅持盡量保持較少的關(guān)鍵字。 參考資料V“新增C99和C11的標(biāo)準(zhǔn)ANSI C庫”列出了一些運算符的備選拼寫誊册。
優(yōu)先級
!運算符的優(yōu)先級很高领突, 比乘法運算符還高, 與遞增運算符的優(yōu)先級相同案怯, 只比圓括號的優(yōu)先級低君旦。 &&運算符的優(yōu)先級比||運算符高, 但是兩者的優(yōu)先級都比關(guān)系運算符低嘲碱, 比賦值運算符高金砍。 因此, 表達(dá)式a >b && b > c ||b > d相當(dāng)于((a > b) && (b > c)) || (b > d)麦锯。
也就是說恕稠, b介于a和c之間, 或者b大于d扶欣。
求值順序
除了兩個運算符共享一個運算對象的情況外鹅巍, C 通常不保證先對復(fù)雜表達(dá)式中哪部分求值千扶。
C 把先計算哪部分的決定權(quán)留給編譯器的設(shè)計者, 以便針對特定系統(tǒng)優(yōu)化設(shè)計昆著。 但是县貌, 對于邏輯運算符是個例外, C保證邏輯表達(dá)式的求值順序是從左往右凑懂。 &&和||運算符都是序列點煤痕, 所以程序在從一個運算對象執(zhí)行到下一個運算對象之前, 所有的副作用都會生效接谨。 而且摆碉, C 保證一旦發(fā)現(xiàn)某個元素讓整個表達(dá)式無效, 便立即停止求值脓豪。
while ((c = getchar()) != ' ' && c != '\n')
第1 個子表達(dá)式把讀取的值賦給c巷帝, 后面的子表達(dá)式會用到c的值。 如果沒有求值循序的保證扫夜, 編譯器可能在給c賦值之前先對后面的表達(dá)式求值楞泼。
if (number != 0 && 12/number == 2)
printf("The number is 5 or 6.\n");
如果number的值是0, 那么第1個子表達(dá)式為假笤闯, 且不再對關(guān)系表達(dá)式求值堕阔。 這樣避免了把0作為除數(shù)。 許多語言都沒有這種特性颗味, 知道number為0后超陆, 仍繼續(xù)檢查后面的條件。
小結(jié): 邏輯運算符和表達(dá)式
邏輯運算符:
邏輯運算符的運算對象通常是關(guān)系表達(dá)式浦马。 !運算符只需要一個運算對象时呀, 其他兩個邏輯運算符都需要兩個運算對象, 左側(cè)一個晶默, 右側(cè)一個谨娜。
當(dāng)且僅當(dāng)expression1和expression2都為真, expression1 && expression2才為真磺陡。 如果 expression1 或 expression2 為真瞧预, expression1 || expression2 為真。 如果expression為假仅政, !expression則為真, 反之亦然盆驹。
邏輯表達(dá)式的求值順序是從左往右圆丹。
范圍
&&運算符可用于測試范圍。要測試score是否在90~100的范圍內(nèi)躯喇, 可以這樣寫:
if (range >= 90 && range <= 100)
printf("Good show!\n");
由于<=運算符的求值順序是從左往右辫封, 所以編譯器把測試表達(dá)式解釋為:
(90 <= range) <= 100
子表達(dá)式90 <= range的值要么是1(為真) 硝枉, 要么是0(為假) 。 這兩個值都小于100倦微, 所以不管range的值是多少妻味, 整個表達(dá)式都恒為真。 因此欣福, 在范圍測試中要使用&&责球。
一個統(tǒng)計單詞的程序
編寫一個統(tǒng)計單詞數(shù)量的程序(即, 該程序讀取并報告單詞的數(shù)量) 拓劝。 該程序還可以計算字符數(shù)和行數(shù)雏逾。
首先, 該程序要逐個字符讀取輸入郑临, 知道何時停止讀取栖博。 然后, 該程序能識別并計算這些內(nèi)容: 字符厢洞、 行數(shù)和單詞仇让。
讀取一個字符
當(dāng)有更多輸入時
遞增字符計數(shù)
如果讀完一行, 遞增行數(shù)計數(shù)
如果讀完一個單詞躺翻, 遞增單詞計數(shù)
讀取下一個字符
輸入循環(huán)的模型:
while ((ch = getchar()) != STOP)
{?
...
}
STOP表示能標(biāo)識輸入末尾的某個值丧叽。
要查找一個單詞里是否有某個字符, 可以在程序讀入單詞的首字符時把一個標(biāo)記(名為 inword) 設(shè)置為1获枝。 也可以在此時遞增單詞計數(shù)蠢正。 然后, 只要inword為1(或true) 省店, 后續(xù)的非空白字符都不記為單詞的開始嚣崭。 下一個空白字符, 必須重置標(biāo)記為0(或false) 懦傍, 然后程序就準(zhǔn)備好讀取下一個單詞雹舀。
如果c不是空白字符, 且inword為假
設(shè)置inword為真粗俱, 并給單詞計數(shù)
如果c是空白字符说榆, 且inword為真
設(shè)置inword為假
在讀到每個單詞的開頭時把inword設(shè)置為1(真) , 在讀到每個單詞的末尾時把inword設(shè)置為0(假) 寸认。 只有在標(biāo)記從0設(shè)置為1時签财, 遞增單詞計數(shù)。 如果能使用_Bool類型偏塞, 可以在程序中包含stdbool.h頭文件唱蒸, 把inword的類型設(shè)置為bool, 其值用true和false表示灸叼。 如果編譯器不支持這種用法神汹, 就把inword的類型設(shè)置為int庆捺, 其值用1和0表示
如果使用布爾類型的變量, 通常習(xí)慣把變量自身作為測試條件屁魏。
用if (inword)代替if (inword == true)
用if (!inword)代替if (inword == false)
可以這樣做的原因是滔以, 如果 inword為true, 則表達(dá)式 inword == true為true氓拼; 如果 inword為false你画, 則表達(dá)式inword == true為false。 所以披诗, 還不如直接用inword作為測試條件撬即。 類似地, !inword的值與表達(dá)式inword == false的值相同(非真即false呈队, 非假即true)剥槐。
該程序使用邏輯運算符把偽代碼翻譯成C代碼。如果c不是空白字符宪摧, 且inword為假翻譯成如下C代碼:
if (!isspace(c) &&!inword)
注意粒竖, !inword 與 inword == false 等價。 上面的整個測試條件比單獨判斷每個空白字符的可讀性高:
if (c != ' ' && c != '\n' && c != '\t' && !inword)
如果c不是空白字符几于, 且如果c不在單詞里”蕊苗。 如果兩個條件都滿足, 則一定是一個新單詞的開頭沿彭, 所以要遞增n_words朽砰。 如果位于單詞中, 滿足第1個條件喉刘, 但是inword為true瞧柔, 就不遞增 n_word。 當(dāng)讀到下一個空白字符時睦裳, inword 被再次設(shè)置為 false造锅。 檢查代碼, 查看一下如果單詞之間有多個空格時廉邑, 程序是否能正常運行哥蔚。