小练习
判断下面这段代码的输出是什么:
答案是“m=5 n=3”,需要对switch语句的解读有一定认知,注意break是逐层跳出switch代码块。
循环语句
while循环
while(1)死循环,while的循环结构是这样的:
首先判断表达式是否为真,若为真执行循环语句并且再次判断,直到表达式为假,此时跳出循环。
通过下面这段代码讨论continue的作用:
此时打印出来的结果是“1 2 3 4”,并且打印4之后程序并没有结束而是陷入了死循环,原因是i==5判断为真时continue中止了本次循环,也就是本次循环中continue后面的语句不会再执行,而是直接跳转到下一次的while语句进行下一次的条件判断,进行下一次的入口判断。
对应的break的作用就好理解很多,在一个循环内部执行到break语句,会立刻中止后续所有循环并跳出该循环体。
再来看几个代码:
这里涉及了一对新的函数getchar()和putchar(),为什么这里可以使用int型变量来接收键盘输入的字符型数值,我的理解是getchar接收的是键入的字符对应的ASCII码值,并将这个整型的ASCII码值赋值给ch,而putchar()将这个ASCII码值对应的字符输出打印出来,这里putchar()和直接printf打印效果是一样的。还要注意判断条件不等于EOF,这里键入EOF并不能停止程序,他的意思是end of file文件结束标志,可以用组合键Ctrl+z结束程序。
再研究一段代码:
为什么这里要两次使用getchar()来接收输入缓冲区的值呢?实际操作发现如果只用一个getchar(),输入密码没问题,但是在确认的时候程序不会等待我们输入,而是直接判断确认失败并且打印结果。原因是,我们输入密码之后是以回车键结束的,而scanf读取的缓冲区内容只包括密码留下了回车键”\n“,下一步getchar()读取缓冲区时读到了“\n”,因此不会等待我们进一步输入Y/N而是用“\n”直接进行判断,那么得出的结果永远都是确认失败。
解决办法目前想到的就是使用两次getchar()去读取缓冲区,让第一个去读取掉遗留下来的“\n”,这样第二个判断值就可以读取到正常我们键入的Y或者N。
for循环
for循环是用的最多的循环结构,for循环的语法结构如下:
表达式1是初始化部分,用于初始化循环变量。表达式2是条件判断部分,用于判断循环甚麽时候终止。表达式3为调整部分,用于循环条件的调整。(表达式3是每次循环的最后执行)
最简单的for循环的实现,输出打印1-10:
注意for循环结构不会香while一样因为内部的continue导致的死循环,在for循环中执行到continue会跳过循环体中后续的操作,跳到循环条件的调整这一步,下一步才进行判断,有效的避免了由于跳过调整代码造成的死循环。下例:
输出结果如图:
for循环的一些建议:
- 不可以在for循环体内改变循环变量,防止for循环失去控制。
- 建议for语句的循环控制变量采取“前闭后开区间”写法。
第一个比较好理解,前闭后开指的是i的初始化和判断条件,比如“for(i=0 ; i<10; i++)”这里面i的判断范围就是[0,10 ),方便习惯具有某种意义,在某些情况下更合适。
for循环的一些变种:
- for循环的初始化、调整、判断都可以省略
- for循环的判断部分被省略,那么判断条件默认恒为真
- 在不熟练的情况下,不建议省略for循环中的3个表达式
变种1,下方是错误案例,我们预期省略初始化的这一步,两层for循环嵌套打印100个输出:
但是结果未达到我们的预期,只打印了10个输出:
原因是我们省略了j的初始化,导致外层循环第一次结束之后,当再次进入内层循环时,j的值并为得到初始化,j仍然是10,因此内部循环中的打印语句自然无法执行,最终直到i的值调整到10也并没有再打印任何输出,这就是省略表达式可能造成的一种bug。
变种2,使用两个循环变量来控制一个for循环:
do while
do语句的语法:
小尝试,打印输出1-10,要求使用do循环:
这种循环的特点是先循环后判断,先判断再循环,至少循环一次,这种循环用法在哪里比较突出呢?
练习任务
- 计算n的阶乘。
- 计算1!+2!+...+10!
- 在一个有序数组中查找具体的某个数字n。编写int binsearch(int x,int v[],int n);功能:在v[0]<=v[1]<=v[2]<=...<=v[n-1]的数组中查找x。
第一题:
第二题:
第三题,写的不是很好,但是目前我只能写出这样的,函数用的很不熟练想法也很局限:
运行结果如下图: