好,在说完了数据成分和运算成分之后啊,我们再来说一下 C语言的基本构成成分的第3个部分,控制成分。 现在再来讲控制成分,或者说我们回头再来看控制成分啊, 就容易得多了。因为我们写程序的过程中,我们都已经 用过了,这就好办了。在这呢,我们只需要增补一些 大家可能还没有注意到的一些知识,就可以了。 那说到控制成分,我们又回到那个老问题了, 我们曾经提过这么一个问题,就是什么样的结构才能支持程序运行的这种逻辑啊? 有多少种控制语句,才能够满足我们 去描述各种各样的控制逻辑的这个需求呢? 其实啊,这件事情在1966年的时候,有两位牛人, 这两位牛人,在非常牛的期刊上面,就是Communications of the ACM,现在这个期刊仍然存在,而且呢,也是一个非常牛的期刊。 发表了一篇论文,在这篇论文里头, 就证明了,任何具有单入口单出口的程序 都可以用三种基本的结构来表达。 那么这篇论文就帮我们 解决了我们所提出来的那个问题, 只要你的程序逻辑是有单入口单出口的程序, 那么你就可以用3种逻辑结构来表达。 那么在这呢,我给出了这个论文的一个链接,感兴趣的同学啊, 可以到任何一个数字图书馆里头,应该都可以找得到。 这样一篇非常著名的论文, 拿过来瞻仰一下,这是没有问题的。那么有的同学可能就问了,那什么叫单入口 单出口的程序啊?其实我们所写的程序,都具备这个特点, 单入口单出口。任何程序的一次执行, 都是有唯一的一个入口和唯一的一个出口的。 有的同学说,我写的程序里头有很多的if语句,有很多分支语句啊, 我们说的是程序的执行,任何一次的执行过程都是有一个准确的入口和一个准确的出口的。 其实呢,单入口和单出口的程序,是结构化程序的一个很重要的特性, 我们学的是结构化程序设计语言,等到后期的时候我们会着重去讲什么叫结构化程序设计。 到那个时候呢,我们就明确,单入口和单出口的程序实际上是结构化程序的一个很重要的特征。 在这呢,我们只要明白,只要具备单入口和单出口这样的特点,那么 这样的程序我就可以用3种基本的逻辑结构来描述。知道这一点,就ok了。 好,其实这3种逻辑结构呢,我们都已经接触过了,那么我们在这呢。 增补一些小知识。那么关于顺序结构,我想我们不用再说了,只要你会写分号, 你就会用顺序结构了。那么我们来看分支结构。 其实啊,在之前我们给了很简单的一个分支结构的一个例子,我, 不过我已经看到,大家在程序里面写了复杂的分支结构,有的同学, 无论这个程序是抄的还是自己写的,anyway,你已经用过 复杂的分支结构了,那么我们再来看一下的时候你就觉得容易的多了。 以前我们讲的这个分支结构的语句都是这样的, if如果满足条件的话走这边,else不满足条件的话 走这边,两条语句,满足条件执行它,不满足条件执行它, 这是我们以前接触过的if语句。非常非常的明确,非常的简单。 其实呢,if语句在这个基础上啊,还可以有各种各样的变化。其实这些变化, 万变不离其宗,都是一样的。那么你比方说,这是第一种吧,我们把这个称作第1种, 那么一个变化是第2种,if else if,else if,else if, 就是说,当一个条件满足的时候怎样,不满足,否则else if怎样,else if怎样。 这是1种。首先,我们明确这个类别啊,是人为做的一个划分,那么 如果我们在我们使用这个语句的过程中,我们完全可以不去考虑这个类别。 而且呢,这几种类别之间,是可以互相转化的。 关于第2种的这种分支语句呢,我们看一个例子就明白了,比方看这个例子。 我写了这么一个例子,同学们都比较关注自己的身高和体重, 那我就写了一个例子,来测一测,看你的身高和体重的比例是不是协调的。那么输入一个体重, 强调是以公斤为单位, 输入一个身高,强调是以米为单位,然后呢我计算一个health rate, 就是一个健康指数,这个就是 非常普通的一个计算方式,体重除以身高的平方。 然后呢,只要这个,这health rate 它位于18到25之间,那就证明你体重适中,这是一种情况。 else if,如果不是这样的话,if 位于25到30之间,不包括25, 包括30, 那就证明你稍微有一点超重,注意控制。 那else if都不是这两种情况,在else if位于30和35之间,那你就 有点肥胖了,碱减肥吧。 那如果还不是,else if位于35到40之间,那就输出来,啊呀, 重度肥胖,别吃了。 如果还不满足,那么我们剩下的不再细分了, else直接cout请拨打120,因为你已经胖过头了。 其实这样的一个分支,就满足像刚才我们讲的这种情况。这是 第1种,这个是第2种. 还有第3种情况就是嵌套起来使用,比方说在这个, 大的else if else里面嵌套了一个小的,这是允许的,我们再举一个例子。 我们先来看这个例子,然后我们再来分析它的含义。 我们看到啊 ,这个例子里头啊,有很多的if语句。 比方说if else,if else,if else, 那么这些if语句呢,全部都是嵌套在一起的。在这呢, 我们强调一点,那如果要写这样的嵌套结构的话,那么这个缩进关系, 就非常非常的重要。你看,这个缩进的结构就体现出了程序的结构。 所以说如果有一个良好的缩进的关系的话,可以充分的体现程序的这个结构。 ok我们再来看一下这道题到底是什么含义,其实这道题 就是刚才我们提过的,判定闰年的,另一个办法。 那么在运算部分呢,我们曾经用一个表达式来判定,判定一年是否为闰年。 那么在这呢,我们就用一个if程序写成的语句来判定,它的效果是一样的。 还记得闰年的那个条件吗? 被,能被4整除,但是不能被100整除, 能被100整除,又能被400整除的,那么都是闰年。 我们来看一下,如果一个年份, 它能够被4整除, 这是满足闰年的一个最基本的条件了,如果满足了这个条件, 并且呢,它又不能被100整除的话,那么一定是闰年。 第2种情况是,能被4整除,又能被100整除, 同时呢,又能被400整除,那么这种情况,也是闰年。 除此之外,其他情况都不是闰年。非常清楚的一个,一个答案。 从这个题目我们就可以看得出来,用表达式和用这个逻辑语句, 是等效的。那么我有一个印象很深的例子。那么以前呢,我们 测试同学写程序的能力,其中第1道题,是比较简单的一道题。是8皇后问题,请你写一个程序, 判定一个8皇后的问题。我发现有一个同学,全部都用了表达式 来写完了这个程序,从头到尾没有一行控制语句,全部都用表达式。 也是可以的,一样能解答这个问题。只不过那个程序的可读性实在是太差了。 ok这是if语句。最后呢关于if语句我们再多说一句话。 其实呀, 我们都知道,那if语句的执行过程就是,先判定 这个括号内的表达式,如果这个表达式真,那么我就执行后面的语句。 那么在这需要说的是,这个括号内啊,它不一定是一个 结果为true或者false的一个表达式。它完全可以是 任何其他的类型。必方说,你也可以这样来写。 if它,if a,然后cout a,这是允许的。 if 3,然后它,也是允许的。也就是说,只要这个地方, 是个非0的数,那么我就按真来处理。 如果这个地方是个0,那我们就按假来处理。有的时候啊,我们会利用if语句的这一点, 来构造程序。当然我并不倾向于大家这么去做,因为这样去做的话也会降低程序的可读性。 在比较明显的情况下,大家可以选择这样去做,没问题。这是关于if语句。 那么除了if语句,还有什么其它的分支语句吗?有,还有一种分支语句,叫做switch语句。 那么switch语句呢,是多分支语句。 我们来看一下它的基本形式。switch后面有一个表达式。 然后呢,后面有一个case,case是一个关键字,那么case后面呢,跟了一个常量表达式。 然后呢?你可以写很多的case,一个case后面 都跟了一个常量表达式。常量表达式的后面,都跟了不同的程式语句。 而且呢,它还有一个default,后面也跟着程式语句。 那么这个switch语句是什么含义呢?是这样的,这是一个表达式。 那么这个表达式就一定有一个“值”,如果 这个表达式的“值”跟某个case后面的这个常量表达式 是一致的。 那么程序就从常量表达式后面的这条语句 开始一直往下执行。往下执行,下面的这些语句。这就是 case语句的作用。我再说一遍,就是当表达式的这个“值”, 与某一个case后面的常量表达式的“值”是相等的时候;那么 就从这个常量表达式后面的这条语句 往后执行,去执行一系列的下面这些语句。 如果没有发现与这个“值”相匹配的常量表达式,那么我就去执行 default后面的这个语句。这就是switch语句的执行过程。 说完了这个,大家可能有一个, 嗯,大体的认识。我们通过几个例子来看一下 switch语句的使用。因为swtich语句啊,用起来的时候经常会 犯错误。我们看几个例子。第一个例子, 这个例子很简单。 就是说啊!这个程序呢输入是a、b、c、d的时候,它就帮我答应一个 分数的范围出来。那么,比方说我输入的是“a"的话那么它就应该答应出来85到100。 就表示“a“类的成绩是产生85分儿到100分儿。 如果是”b“呢?输入的是b呢?它就答应出来是70到84. 如果是”c"呢?那就是60到69。 如果是“d”的话那就小于60 ,那就不及格儿了。如果iii你输入的是“e"或者是”h"; 那么它就等于error。但是,这个程序的本意是这样的。 按照这样一个本意我就写了这样一个程序。 那么在这个程序里头呢,我定义了一个grade。grade呢是一个字符型的量, 要求输入一个grade。 嗯,在switch后面,嗯,放一个grade的变量。 也就是说,当这个grade等于”a"的时候, 我就应该让它答应这条语句,设想中iii 当grade等于b的时候我就让他答应这条语句。 当grade等于c的时候我就让它答应这条语句。 当grade等于d的时候我就让它答应这条语句。 当grade不是这四个之一的时候我就让它答应default。这是我原本的设想。那么,这个程序是这么执行的吗? 那么我们来看一下这个程序的执行结构。当我输入的是a的时候,答应出了什么呢? 它答应出了85到100、70到84、60到69、小于60 、error。 也就是说把后的这这些语句全部都答出来了。这符合他的语法吗? 符合。因为我们刚才讲过 若果grade的这个变量的”值“符合某一个 ”值“的时候,比方说输入a它就符合这个,我就从 这从这个表达式后面的这条语句开始往下执行。 执行后面的每一条语句。也就是说啊! 一定要注意,实际上就是跟这个 表达式相匹配的这个case语句后面的那个常量,只提供一个程序执行的 入口。他只提供下去的是一个入口,进来以后就是从这儿往下一路执行下去。 这就是case的语句。 好,那有的同学说,如果我想要实现刚才我们那个意图; 也就是说当他输入的是a的时候,我就让它答应这一条,别的不答应。那怎么办呢? 很好办,在每一条语句后面加break。 break、break、break、break。 也就是说,如果这个时候你再输入的是a跟这个a相匹配; 它就会只执行这条语句。因为执行完之后,我就要执行break的语句。 break的含义就是跳当前的switch语句; 不再去执行其他的语句了。这样的话呢,就符合了我们的逻辑。 这是break的这个含义。所以说如果你想 写一个像刚才那样的程序,出了一个确定的字母给grade了的时候, 那么它就执行一条相应的语句。那么千万千万不要忘记了break。 这是第一条 最最最须要注意的。最最最还有一个需要注意的,就是case常量表达式后面的语句呀,是可以共享的。 什么叫共享呢?看这个例子。還是刚才的grade, 然後输入,如果是a的话我就答应这条;如果是b的话我就答应这条。 如果是c的话我不写,d的话不写,e的话不写。f的话我就答应60到69, 这样可以吗? 可以,完全可以。嗯,符合语法。 那么如果你输入的是d,匹配了这个case的时候它执行什么呢? 执行这条。因为在这种情况下, 嗯,那么程序会默认这个 case,这个case,这个case。 它们三个共享了后面的这条语句。我们看一下执行结果你就明白了。 比方说我输入的是d,那输入的是d它执行的是什么呢?因为d后面没有语句,它共享了这条语句。 於是呢?它就从这条语句开始往下执行。 所以输入的是d,答应出来的是60到69,对应了这句。 然後g,小于60。然後error,对应了这句。 那说到这儿,基本上case的语句, 嗯,相关的语法我们就介绍完了。那有几种例外有的同学老问,我干脆在这儿说了。 比方说有的同学问,这个default是不是总是执行的呀? 是不是总是要执行default的呀?嗯,那我们构造一个程序就知道了。 把default写到前面来了。把default写到前面来,可以吗?可以!符合语法。 那如果在这种情况下输入的是default的后面的,匹配的是,default的后面的 case的时候,怎样呢?我们来看一下。如果输入的是b的话那么我就答应出这句。 然後再答应这句,然后再答应这句。Over,结束了。 也就是说,如果我们把default 写在前面的时候 那么它也不会去执行它了。在这种情况下什么时候default才会被执行呢? 没有找到任何的匹配的时候,default就会被执行了。 但是需要特别注意!因为default提供了也是一个程序执行的 入口。比方说,在种情况下我们输入的是h, 那么程序的执行结果将是这样的。因为h没有出现在所有case语句的常量表达式里头, 於是呢?匹配了default。 那么程序的执行呢?就是从error、从default开始往下执行。 这就是default的这个含义。即便是default语句,如她出现在前面,那么, 他依然需要相应的break作为辅助。 需要特比注意这一点。这是switch语句的用法。 那么为了让大家有一个感心的认识,我们给了例子来说明一下switch语句的用法。 嗯,这个例子呢,也很有意思。我们来看,这个例子呀,是把刚才的例子 反过来了。学校要求实行成绩等级制度。 我不知道哪个学校啊!反正不是北大。那么现在呢已经有同学们的百分之成绩了。 要求按照百分之成绩输出相应的等级成绩。 也就是说我给你百分之成绩,那边出来的就应该是它的成绩等级。 比方说,如果你输入的是90到100分儿之间的话,我们的这个等级就是a. 而如果是80到90分而的话那就是b;70到80的话那就是c. 60到70儿的话那就是d;60分儿以下是e。 那就这样了。解这个题有什么好办法呢? 有位同学上来就case语句!你还不太好用case语句,为什么呢? 因为你现在输入的是一个成绩。iii你输入的是97, 你要判定这个成绩处于那一段儿之间。你先要做这样一个 判定,这个不是特别容易。 那有的同学直接想到我不用case的语句,用if语句,用if 语句很好。 比方说,if这个成绩属于大于等于90,小于等于100,那我就答应怎样怎样怎样。 而然後,else if 属于这个期间的时候, 我就再怎样怎样怎样。嗯,非常好的程式。 只不过 在这儿呢,我希望你想一下,怎么样用switch语句去实现。 swich语句应该怎么去实现呢?好好儿想一下。 那么switch语句,我们在来看一下它长得这个样子。 switch语句呀后面是一个表达式,在case的后面 会跟着一些“值”,这通常是一个常量。 这儿是一个表达式;这儿是一个常量。 我必须去要把你输入的任何一个成绩, 规约到一个常量。这是我要做的事情。 拿我怎么规约到某一个常量呢?, 你看,看这个程序的提议,我完全可以这样来处理啊! 其实呢,你的成绩的等级, 是跟你的成绩的个位数没关系的。 比方说你是78,其实我关心的只是十位。 十位是7,那就意味着你的成绩肯定是c。 如果你的成绩比方说是87, 那87这个7也没有意义,我只看这个十位上的数目。是不是这样啊? 所以说我们只需要把他的成绩除以10,求出它的十位上的数。 就可以了,嗯。看一个程序。 看这个程序。它就是这样来做的。 输入你的score,然後我做的事情就是你的score除以10 在这儿我问一下,score除以10,我这个用红色圈起来的这一块儿。 请问它运算完了是个什么数啊? 有同学说,那如果是78除以10的话就应该等于 7.8呀!是这样的吗?那上堂课我们讲过, 两个整数进行运算,算结果仍然是整数。 所以说这个地方,如果是78除以10的话它是这样的。 等于,嗯,不等于7.8,7。 刚好符合我们的提议。 所以说,score除以10我们就得到了一个整数。如果这个整数跟10匹配的当然是a。 毫无疑问,如果他跟9匹配当然也是a。因为90 到100之间。 如果它跟8匹配的就是b,或跟7匹配的就是c,跟6匹配的就是d ,那剩下的就是e。 那是这个程序这么来写,那么是不是我们写这么样的一个程序就可以了呢? 很有可能大家都已经发现了这个程序是错误的。 为什么呢?因为我们忘记了break。 如果加上break,这个程序就正确了。 好,这就是switch语句的基本用法。