条件判断 Decision Control Statement
为了应付程式可能遇到的各种状况,C 提供了if
条件判断陈述。情况、情境、状态或条件的陈述,在程式执行时,该陈述只有正确与错误、 成立与不成立、 真与伪等非常明确的「正面或负面」两种状况。可能的运算结果只能有「true (真)」、「false (假)」这两种布林值(Boolean
Value)布林代数 Boolean algebra
布林代数(Boolean algebra),具有真 (true) 与**伪 (false) **两种值,可用来表示是非对错的概念。
在程式语言中,程式流程控制的语法,例如 if
、for
和 while
等,所使用的条件陈述都需要用布林代数来描述。而有趣的是, C 与 C++因为语言特性和发展时机的不同,对于该怎么实现布林代数的想法也有所不同。
C89 中的布林型态
虽然布林代数对于流程控制至为重要,但在 C89 中并没有替布林代数设计一个专有的资料型态。在 C89 中,布林代数是隐约地在多个不同的型态、不同的运算与不同的语法中实现。C89 替所有内建的资料型态做了统一规定:非 0 为真、0 为伪。此外,C89 对于关係运算子与逻辑 运算子的运算结果也做了规定。当运算结果为真时会算出 int 型态的 1,当运算结果为伪时会算出 int 型态的 0。这造成在 C89 容易觉得布林代数就是用 int 型态来表示。不过这是个误解,下一页我们来看看例子。
上面的程式码,因为 C89 的规定,所以都会被判定为 false。不会印出任何结果。
int
型态不能完全表达布林代数的结果。C89 没有替布林代数设计专用的资料型态还造成了其他问题。例如之前提到的,因为关係与逻辑运算子的运算结果是以 int 的 1 与 0 来表示真与伪,因而产生了一些结果不直观的程式码。开始,型别名字为_Bool
。另外,C99 为了让 C 和 C++ 更相容,增加了一个标头档案 stdbool.h
。里面定义了 bool
、true
、false
,让我们可以像C++ 一样的定义布林型别。_Bool
型别不需要引用其他库函式,直接就可以使用。而 bool
型别,则需要 #include <stdbool.h>
。switch
statement
switch 是 C 语言提供的另一种条件判断方式,本身只能比较数值或是字元。但是,使用得当的话,或许会比 if 判断式还要来得有效率。Syntax:switch (expression){ case constant1: statements1; break; case constant2: statements2 break;… default: default statements;}
首先,会先看看 switch
括号里的 expression
,取得 expression
的数值(或字元)之后,会一一与 case
设定的数字(或字元)比较,若符合,就会执行以下之 statement
,直到遇到 breaks
后离开 switch
区块(block)。若都没有符合得数值(或字元),就会执行 default
里的 statements
。default
可省略。
switch
statement flow chart
範例
範例一:BMI 计算
使用者输入身高、体重,计算 BMI 值。
若 BMI 小于 18.5,显示过轻。
若 BMI 介于 18.5 到 24 之间,显示体重正常。
大于 24,则显示过胖。
#include <stdio.h>#include <stdlib.h>int main(){ float bmi, w, h; // declare in floating type printf("Enter your weight(kg) and height(cm):\n"); scanf("%f %f", &w, &h); bmi = w / ((h/100)*(h/100)); printf("BMI = %f\n\n", bmi); if(bmi<=18.5){ printf("Underweight.\n"); }else if(bmi>18.5 && bmi <= 24){ printf("Normal!\n"); }else{ printf("Overweight!\n"); } system("PAUSE"); return 0;}
範例二:生肖
已知 2021 年为牛年,设计一程式,从今年推算输入年分之生肖为何?
#include <stdio.h>#include <stdlib.h>int main(){ int year; printf("Please input a year: "); scanf("%d", &year); int this_year = 2021 % 12; // 2021 % 12 为牛年 switch((year%12)-this_year){ case 0: printf("%d 年为牛年", year); break; case 1: printf("%d 年为虎年", year); break; case 2: printf("%d 年为兔年", year); break; case 3: printf("%d 年为龙年", year); break; case 4: printf("%d 年为蛇年", year); break; case 5: printf("%d 年为马年", year); break; case 6: printf("%d 年为羊年", year); break; case -5: printf("%d 年为猴年", year); break; case -4: printf("%d 年为鸡年", year); break; case -3: printf("%d 年为狗年", year); break; case -2: printf("%d 年为猪年", year); break; case -1: printf("%d 年为鼠年", year); break; } printf("\n\n"); system("PAUSE"); return 0;}
範例三:计算折扣
某百货正在举行周年庆。顾客购物金额折扣如下:
1,000(含) 以上:打 9 折5,000(含) 以上:打 8 折8,000(含) 以上:打 65 折10,000(含) 以上:打 3 折请设计一程式,使用者输入购物金额,并在萤幕显示出
可享的折扣折扣后的金额总共省下多少钱#include <stdio.h>#include <stdlib.h>int main(){ int price, account; printf("Enter a price: "); scanf("%d", &price); if(price >= 10000){ account = price * 30 / 100; printf("打 3 折\n"); }else if(price >= 8000){ account = price * 0.65; printf("打 65 折\n"); }else if(price >= 5000){ account = price * 0.8; printf("打 8 折\n"); }else if(price >= 1000){ account = price * 0.9; printf("打 9 折\n"); }else{ account = price; printf("没有折扣\n"); } printf("折扣后的金额为 %d\n", account); printf("总共省下 %d\n\n", price-account); system("PAUSE"); return 0;}
迴圈叙述句 Loop Statement
在程式里,迴圈(loop)是用来重複执行同一个区块(block)。会在某一个特别设定的条件下跳出迴圈。在 C语言里,总共有三种不同的迴圈叙述句,分别为:for
loop (前测式)while
loop (前测式)do…while
loop (后测式)之后,我们会分别介绍这三种不同的 statement。for loop
flow chart
for loop
步骤:
for(initialization_Statement; test_Expression; update_State){ // statements inside the body of loop}
while loop
flow chart
while loop 执行步骤:
执行 test expression,判定变数是否为真。如果判定为否,则跳过迴圈里的 statement,直接结束迴圈。如果为真,执行迴圈里的 statement。执行完毕,跳回第一步,直到判定变数为否。while(test_Expression){ // the body of loop}
do...while loop
flow chart
两种不同 while 迴圈
这两种while loop
差别在于前测式与后测式迴圈:前测式迴圈:先测试迴圈变数是否符合迴圈终止条件。后测式迴圈:先执行迴圈本体一次,再测试迴圈变数是否符合终止条件。两者的差异在于 do…while
后测式迴圈至少执行一次。要使用哪一种结构是看程式功能需求,如:帐号密码登入功能至少要让使用者输入一次帐号密码,再确认帐号密码是否正确,就可以使用后测式迴圈结构。ref.
怎么表示是非对错 ? 在 C 与 C++ 中布林 (Boolean) 型态的演进 (二) : C++98switch 条件判断範例
範例四:总和计算
请设计一程式,使用者输入一正整数,并显示 1 + 2 + … + N 的总和。
如:输入 9 ,结果为 1~9 的总和。
#include <stdio.h>#include <stdlib.h>int main(){ int n, sum=0; printf("Enter a number: "); scanf("%d", &n); for(int i=1; i <= n; i++){ sum += i; } printf("Summary of 1 ~ %d = %d\n\n", n, sum); system("PAUSE"); return 0;}
範例五:猜大小
猜大小游戏(high or low),由电脑想定一个数字(1-1000),人来猜电脑想定的数。每人每次猜一个数,电脑则会回答:<答对> <太大> <太小>。
答对后在萤幕显示猜了几次才猜到正确答案。
#include <stdio.h>#include <stdlib.h>#include <time.h>void main(){ int answer, n, count = 0; srand( time(NULL) ); // 设定乱数种子 answer = (rand() % 1000) + 1; // 比较常写成这种模式 (rand()%(max-min+1))+min /**while 写法**/ /*while(1){ // while(1) 代表无限迴圈,但是切记,一定要设停止迴圈的机制 printf("Enter your Answer: "); scanf("%d", &n); count++; if(n == answer){ printf("CONGRA!\n\n"); break; // 跳出迴圈,也就是停止无限迴圈的机制 }else if(n < answer){ printf("Higher\n\n"); }else{ printf("Lower\n\n"); } }*/ /**do while 写法**/ do{ printf("Enter your answer: "); scanf("%d", &n); count++; if(n < answer){ printf("Higher\n\n"); }else if(n > answer){ printf("Lower\n\n"); }else{ printf("Congra!\n\n"); } }while(n != answer); printf("第 %d 次猜到结果\n", count);}
补充:产生乱数
C 语言的 stdlib.h 函式库里提供了 rand() 函式来产生乱数。
不过因为 rand() 函式是由它上一个数值来产出下一个乱数,如果不做任何设定,初值系统都预设为 0。
因此这个时候我们可以用 srand() 函式来改变一开始的乱数值(一样定义在 stdlib.h),srand() 需要一个参数作为 seed(种子)。
通常我们会已目前的时间当作乱数种子,使用 time() 函式,而 time() 定义在 time.h 函式库里。
可以参考以下範例
#include <stdio.h>#include <stdlib.h> //乱数相关函数#include <time.h>void main() // 把 main function 改成 void 就可以省掉最后的 return 0{ /** 第一种乱数範例 **/ // 先设定乱数种子 srand( time(NULL) ); //srand定义在stdlib里,用现在时间当作乱数种子 // 产生乱数 int x = rand(); printf("产生乱数 (基本)\n"); printf("x= %d\n", x); /* 这个範例产生的乱数是一个整数,值介于 0~RAND_MAX 之间 不同系统定义的 RAND_MAX 有不同大小 */ printf("======\n"); system("PAUSE"); printf("\n"); // show RAND_MAX printf("RAND_MAX = %d\n", RAND_MAX); // RAND_MAX 32767 /* This is completely useless to us. */ printf("======\n"); system("PAUSE"); printf("\n"); /** 第二种乱数範例 - 特定範围整数乱数 **/ // 指定乱数範围 int min = 1; int max = 100; // 产生 [min, max] 的整数乱数, min <= x <= max int y = rand() % (max - min + 1) + min; printf("产生特定範围整数乱数,範围:[%d,%d]\n", min, max); printf("y = %d\n", y); printf("======\n"); system("PAUSE"); printf("\n"); /** 第三种乱数範例 - [0,1) 浮点数乱数, 0 <= x < 1 **/ double z = (double) rand() / (RAND_MAX + 1.0); printf("产生 [0,1) 範围浮点数乱数\n"); printf("z = %f\n", z); printf("======\n"); system("PAUSE"); printf("\n"); /** 第四种乱数範例 - [min,max) 浮点数乱数, min <= x < max **/ double min_float = 3.6; double max_float = 8.7; double w = (max_float-min_float) * rand() / (RAND_MAX + 1.0) + min; printf("产生特定範围浮点数乱数,範围:[%.2f,%.2f)\n", min_float, max_float); printf("w = %f\n", w); printf("======\n"); system("PAUSE"); printf("\n");}
产生乱数 (基本)x= 26378======请按任意键继续 . . .RAND_MAX = 32767======请按任意键继续 . . .产生特定範围整数乱数,範围:[1,100]y = 84======请按任意键继续 . . .产生 [0,1) 範围浮点数乱数z = 0.412872======请按任意键继续 . . .产生特定範围浮点数乱数,範围:[3.60,8.70)w = 1.801700======请按任意键继续 . . .Process returned 10 (0xA) execution time : 4.756 sPress any key to continue.
範例六:作图
请设计一程式,由使用者输入一整数,萤幕显示如下:
Input
4
Output
**********
Input
5
Output
***************
以此类推
#include <stdio.h>#include <stdlib.h>void main(){ int i, j, num; scanf("%d", &num); printf("\n"); for(i = 0; i < num; i++){ for(j = 0; j <= i; j++){ printf("*"); } printf("\n"); }}