拓冰建站拓冰建站
首页 / 资讯中心 / 正文

C语言知识梳理第三期(分支和循环)

知识梳理第三期分支和循环C 语言是结构化的程序设计语言这里的结构指的是顺序结构、选择结构、循环结构C 语言是能够实现这三种结构的其实我们如果仔细分析我们日常所见的事情都可以拆分为这三种结构或者这三种结构的组合。我们可以使用 if、switch 实现分支结构使用 for、while、do while 实现循环结构。1.if语句1.1嵌套 if在if else语句中else可以与另一个if语句连用构成多重判断。比如要求输入一个整数判断输入的整数是 0还是正数或者负数。请看如下代码#include stdio.h int main() { int num 0; scanf(%d, num); if(num 0) printf(输入的数字是0\n); else **if(num 0) //这里的if 相当于嵌套在else语句中形成了嵌套结构 printf(输入的数字是正数\n); else printf(输入的数字是负数\n);** return 0; }上图中标星号的代码就是嵌套在前面的else子句中的构成了嵌套的 if 语句。练习输入一个人的年龄如果年龄 18 岁打印 “少年”如果年龄在 18 岁至 44 岁打印 “青年”如果年龄在 45 岁至 59 岁打印 “中老年”如果年龄在 60 岁至 89 岁打印 “老年”如果 90 岁及以上打印 “老寿星”参考代码#include stdio.h int main() { int age 0; scanf(%d, age); if(age 18) { printf(少年\n); } else { if(age 44) { printf(青年\n); } else { if(age 59) { printf(中老年\n); } else { if(age 89) printf(老年\n); else printf(老寿星\n); } } } return 0; }1.2 悬空 else 问题如果有多个if和else可以记住这样一条规则else 总是跟最接近的 if 匹配。#include stdio.h int main() { int a 0; int b 2; if(a 1) if(b 2) printf(hehe\n); else printf(haha\n); return 0; }程序运行的结果是啥很多初学者上来以判断 a 是 0不等于 1 那就执行 else 子句打印 haha但是当你去运行代码输出的结果是啥都不输出。为什么呢这就是悬空 else 的问题如果有多个 if 和 else可以记住这样一条规则else 总是跟最接近的 if 匹配。上面的代码排版让 else 和第一个 if 语句对齐让我们以为 else 是和第一个 if 匹配的当 if 语句不成立的时候自然想到的就是执行 else 子句打印 haha但实际上 else 是和第二个 if 进行匹配的这样后边的if...else语句是嵌套在第一个 if 语句中的如果第一个 if 语句就不成立嵌套 if 和 else 就没机会执行了最终啥都不打印。如果代码改成下面这样就更加容易理解了#include stdio.h int main() { int a 0; int b 2; if(a 1) { if(b 2) printf(hehe\n); else printf(haha\n); } return 0; }或者如果我们希望 else 确实和第一个 if 匹配可以这样修改代码#include stdio.h int main() { int a 0; int b 2; if(a 1) { if(b 2) printf(hehe\n); } else { printf(haha\n); } return 0; }只要带上适当的大括号代码的逻辑就会更加的清晰所以大家以后在写代码的时候要注意括号的使用让代码的可读性更高。2. 关系操作符C 语言用于比较的表达式称为“关系表达式”relational expression里面使用的运算符就称为**“关系运算符”relational operator**主要有下面 6 个。大于运算符小于运算符大于等于运算符小于等于运算符相等运算符!不相等运算符下面是一些例子。a b; a ! b; a b; a b; a b; a b;关系表达式通常返回0 或 1表示真假。C 语言中0 表示假所有非零值表示真。比如20 12返回 112 20返回 0。关系表达式常用于if或while结构。if (x 3) { printf(x is 3.\n); }注意相等运算符与赋值运算符是两个不一样的运算符不要混淆。有时候可能会不小心写出下面的代码它可以运行但很容易出现意料之外的结果。if (x 3) ...上面示例中原意是x 3但是不小心写成x 3。这个式子表示对变量 x 赋值 3它的返回值为 3所以 if 判断总是为真。为了防止出现这种错误有的程序员喜欢将变量写在等号的右边。if (3 x) ...这样的话如果把误写成编译器就会报错。/* 报错 */ if (3 x) ...另一个需要避免的错误是多个关系运算符不宜连用。i j k上面示例中连续使用两个小于运算符。这是合法表达式不会报错但是通常达不到想要的结果即不是保证变量 j 的值在 i 和 k 之间。因为关系运算符是从左到右计算所以实际执行的是下面的表达式。(i j) k上面式子中i j返回 0 或 1所以最终是 0 或 1 与变量 k 进行比较。如果想要判断变量 j 的值是否在 i 和 k 之间应该使用下面的写法。i j j k比如我们输入一个年龄如果年龄在 18 岁36 岁之间我们输出青年。如果我们这样写#include stdio.h int main() { int age 0; scanf(%d, age); if(18 age 36) { printf(青年\n); } return 0; }当我们输入 10 的时候依然输出青年。这是因为我们先拿 18 和 age 中存放的 10 比较表达式1810为假18age的结果是 0再拿 0 和 36 比较036为真所以打印了青年所以即使当 age 是 10 的时候也能打印青年逻辑上是有问题这个代码应该怎么写呢#include stdio.h int main() { int age 0; scanf(%d, age); if(age 18 age 36) { printf(青年\n); } return 0; }3. 条件操作符条件操作符也叫三目操作符需要接受三个操作数的形式如下exp1 ? exp2 : exp3条件操作符的计算逻辑是如果exp1为真exp2计算计算的结果是整个表达式的结果如果exp1为假exp3计算计算的结果是整个表达式的结果。练习 1使用条件操作符表示下面代码的逻辑#include stdio.h int main() { int a 0; int b 0; scanf(%d, a); if (a 5) b 3; else b -3; printf(%d\n, b); return 0; }改造后#include stdio.h int main() { int a 0; int b 0; scanf(%d, a); b (a 5 ? 3 : -3); printf(%d\n, b); return 0; }练习 2使用条件表达式实现找两个数中较大值。#include stdio.h int main() { int a 0; int b 0; scanf(%d %d, a, b); int m (a b ? a : b); printf(%d\n, m); return 0; }4. 逻辑操作符 , || , !逻辑运算符提供逻辑判断功能用于构建更复杂的表达式主要有下面三个运算符。!逻辑取反运算符改变单个表达式的真假。逻辑与运算符就是并且的意思两侧的表达式都为真则为真否则为假。||逻辑或运算符就是或者的意思两侧至少有一个表达式为真则为真否则为假。注C 语言中非 0 表示真0 表示假4.1 逻辑取反运算符表格a!a非 0001比如我们有一个变量叫flag如果flag为假要做一个什么事情就可以这样写代码#include stdio.h int main() { int flag 0; if(!flag) { printf(do something\n); } return 0; }如果flag为真!flag就是假如果flag为假!flag就是真所以上面的代码的意思就是flag为假执行if语句中的代码。4.2 逻辑与运算符就是与运算符也是并且的意思是一个双目操作符使用的方式是ab两边的表达式都是真的时候整个表达式才为真只要有一个是假则整个表达式为假。比如如果我们说月份是 3 月到 5 月是春天那使用代码怎么体现呢int month 0; scanf(%d, month); if (month 3 month 5) { printf(春季\n); }这里表达的意思就是month既要大于等于 3又要小于等于 5必须同时满足。4.3 逻辑或运算符||||就是或运算符也就是或者的意思||也是一个双目操作符使用的方式是a || b||两边的表达式只要有一个是真整个表达式就是真两边的表达式都为假的时候才为假。比如我们说一年中月份是 12 月或者 1 月或者 2 月是冬天那么我们怎么使用代码体现呢int month 0; scanf(%d, month); if(month 12 || month 1 || month 2) { printf(冬季\n); }4.4 练习闰年的判断输入一个年份 year判断 year 是否是闰年闰年判断的规则能被 4 整除并且不能被 100 整除是闰年能被 400 整除是闰年//代码1 #include stdio.h int main() { int year 0; scanf(%d, year); if(year % 4 0 year % 100 ! 0) printf(是闰年\n); else if(year % 400 0) printf(是闰年\n); return 0; } //代码2 #include stdio.h int main() { int year 0; scanf(%d, year); if((year % 4 0 year % 100 ! 0) || (year % 400 0)) printf(是闰年\n); return 0; }4.5 短路C 语言逻辑运算符还有一个特点它总是先对左侧的表达式求值再对右边的表达式求值这个顺序是保证的。如果左边的表达式满足逻辑运算符的条件就不再对右边的表达式求值。这种情况称为 “短路”。如前面的代码:if(month 3 month 5)表达式中的左操作数是month 3右操作数是month 5当左操作数month 3的结果是 0 的时候即使不判断month 5整个表达式的结果也是 0不是春季。所以对于操作符来说左边操作数的结果是 0 的时候右边操作数就不再执行。对于||操作符是怎么样呢我们结合前面的代码if(month 12 || month 1 || month 2)如果month 12则不用再判断month是否等于 1 或者 2整个表达式的结果也是 1是冬季。所以||操作符的左操作数的结果不为 0 时就无需执行右操作数。像这种仅仅根据左操作数的结果就能知道整个表达式的结果不再对右操作数进行计算的运算称为短路求值。练习阅读代码计算代码输出的结果//代码1 #include stdio.h int main() { int i 0, a 0, b 2, c 3, d 4; i a b d; printf(a %d\nb %d\nc %d\nd %d\n, a, b, c, d); return 0; }// 上面的代码执行结果是什么如果把 a 的值改成 1结果又是什么答案原代码输出a1,b2,c3,d4。a改为1输出 a2,b3,c3,d5。//代码2 #include stdio.h int main() { int i 0, a 1, b 2, c 3, d 4; i a || b || d; printf(a %d\nb %d\nc %d\nd %d\n, a, b, c, d); return 0; }// 上面的代码执行结果是什么如果把 a 的值改成 0结果又是什么答案原代码输出a2b2c3d4a改为1输出a1b3c3d45. switch 语句除了if语句外C 语言还提供了switch语句来实现分支结构。switch语句是一种特殊形式的if...else结构用于判断条件有多个结果的情况。它把多重的else if改成更易用、可读性更好的形式。switch (expression) { case value1: statement case value2: statement ... default: statement }上面代码中根据表达式expression不同的值执行相应的case分支。如果找不到对应的值就执行default分支。注switch后的expression必须是整型表达式case后的值必须是整形常量表达式5.1 if 语句和 switch 语句的对比练习输入任意一个整数值计算除 3 之后的余数如果使用 if 语句完成如下#include stdio.h int main() { int n 0; scanf(%d, n); if(n % 3 0) printf(整除余数为0\n); else if(n % 3 1) printf(余数是1\n); else printf(余数是2\n); return 0; }如果使用 switch 语句改写就可以是这样的#include stdio.h int main() { int n 0; scanf(%d, n); switch(n % 3) { case 0: printf(整除余数为0\n); break; case 1: printf(余数是1\n); break; case 2: printf(余数是2\n); break; } return 0; }上述的代码中我们要注意的点有case和后边的数字之间必须有空格每一个case语句中的代码执行完成后需要加上break才能跳出这个 switch 语句。5.2 switch 语句中的 break前面的代码中如果我们去掉 case 语句中的 break会出现什么情况呢#include stdio.h int main() { int n 0; scanf(%d, n); switch(n % 3) { case 0: printf(整除余数为0\n); case 1: printf(余数是1\n); case 2: printf(余数是2\n); } return 0; }测试一组看一下结果输入 7余数是1 余数是2我们发现7 除以 3 本来余数是 1但是我们发现程序运行的结果多了一行 “余数是 2” 的打印。问这是为什么呢原因是switch语句也是分支效果的只有在 switch 语句中使用break才能在跳出 switch 语句如果某一个 case 语句的后边没有 break 语句代码会继续往下执行有可能执行其他 case 语句中的代码直到遇到 break 语句或者 switch 语句结束。就比如上面的代码就执行了 case2 中的语句。所以在 switch 语句中 break 语句是非常重要的能实现真正的分支效果。当然break 也不是每个 case 语句都得有这就得根据实际情况来看了。练习输入一个 1~7 的数字打印对应的星期几例如输入1 输出星期一输入2 输出星期二输入3 输出星期三输入4 输出星期四输入5 输出星期五输入6 输出星期六输入7 输出星期天参考代码如下#include stdio.h int main() { int day 0; scanf(%d, day); switch(day) { 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; case 6: printf(星期六\n); break; case 7: printf(星期天\n); break; } return 0; }如果需求发生变化变为输入 1‑5输出的是 “工作日”输入 6‑7输出 “休息日”那参考代码如下#include stdio.h int main() { int day 0; scanf(%d, day); switch(day) { case 1: case 2: case 3: case 4: case 5: printf(工作日\n); break; case 6: case 7: printf(休息日\n); break; } return 0; }上面的练习中我们发现应该根据实际的情况来在代码中觉得是否使用 break或者在哪里使用 break才能正确完成实际的需求。5.3 switch 语句中的 default在使用 switch 语句的时候我们经常可能遇到一种情况比如 switch 后的表达式中的值无法匹配代码中的 case 语句的时候这时候要不就不做处理要不就得在 switch 语句中加入 default 子句。switch (expression) { case value1: statement case value2: statement default: statement }switch 后边的 expression 的结果不是 value1也不是 value2 的时候就会执行 default 子句。就比如前面做的打印星期的练习如果 day 的输入不是 1~7 的值如果我们要提示输入错误则可以这样完成代码#include stdio.h int main() { int day 0; scanf(%d, day); switch(day) { case 1: case 2: case 3: case 4: case 5: printf(工作日\n); break; case 6: case 7: printf(休息日\n); break; default: printf(输入错误\n); break; } return 0; }5.4 switch 语句中的 case 和 default 的顺序问题在 switch 语句中 case 子句和 default 子句有要求顺序吗 default 只能放在最后吗答没有顺序要求。但是习惯把 default 放末尾。6. while 循环6.1 if 和 while 的对比if(表达式) 语句; while(表达式) 语句;//如果循环体想包含更多的语句可以加上大括号代码 1if 示例#include stdio.h int main() { if(1) printf(hehe\n); //if后边条件满足打印一次hehe return 0; }代码 2while 示例#include stdio.h int main() { while(1) printf(hehe\n); //while后边的条件满足死循环的打印hehe return 0; }这就是他们的区别while 语句是可以实现循环效果的。6.2 while 语句的执行流程首先上来就是执行判断表达式表达式的值为 0循环直接结束表达式的值不为 0则执行循环语句语句执行完后再继续判断是否进行下一次判断。6.3 while 循环的实践练习在屏幕上打印 1~10 的值参考代码#include stdio.h int main() { int i 1; while (i 10) { printf(%d , i); i i 1; } return 0; }6.4 练习输入一个正的整数逆序打印这个整数的每一位例如输入1234输出4 3 2 1输入521输出1 2 5题目解析要想得到 n 的最低位可以使用 n%10 的运算得到的余数就是最低位如1234%10 得到 4要想去掉 n 的最低位找出倒数第二位则使用 nn/10 操作就可以去掉最低位的如n1234/10 得到 123123 相较于 1234 就去掉了最低位123%10 就得到倒数第二位 3。循环 1 和 2 两个步骤在 n 变成 0 之前就能到所有的位。参考代码#include stdio.h int main() { int n 0; scanf(%d, n); while (n) { printf(%d , n % 10); n / 10; } return 0; }7. for 循环7.1 语法形式for 循环是三种循环中使用最多的for 循环的语法形式如下for(表达式1; 表达式2; 表达式3) 语句; //如果循环体想包含更多的语句可以加上大括号表达式 1 用于循环变量的初始化表达式 2 用于循环结束条件的判断表达式 3 用于循环变量的调整7.2 for 循环的执行流程首先执行 表达式 1 初始化循环变量接下来就是执行 表达式 2 的判断部分表达式 2 的结果如果 0则循环结束表达式 2 的结果如果0 则执行循环语句循环语句执行完后再去执行表达式 3调整循环变量然后再去 表达式 2 的地方执行判断表达式 2 的结果是否为 0决定循环是否继续。整个循环的过程中表达式 1 初始化部分只被执行 1 次剩下的就是表达式 2、循环语句、表达式 3 在循环。7.3 for 循环的实践练习在屏幕上打印 1~10 的值参考代码#include stdio.h int main() { int i 0; for(i 1; i 10; i) { printf(%d , i); } return 0; }运行结果1 2 3 4 5 6 7 8 9 107.4 while 循环和 for 循环的对比for 和 while 在实现循环的过程中都有初始化、判断、调整这三个部分但是 for 循环的三个部分非常集中便于代码的维护而如果代码较多的时候 while 循环的三个部分就比较分散所以从形式上 for 循环要更优一些。7.5 练习练习 1计算 1~100 之间 3 的倍数的数字之和参考代码#include stdio.h int main() { int i 0; int sum 0; for(i 1; i 100; i) { if(i % 3 0) sum i; } printf(%d\n, sum); return 0; }// 小小的优化// 如果能直接产生 3 的倍数的数字就省去了多余的循环和判断#include stdio.h int main() { int i 0; int sum 0; for (i 3; i 100; i 3) { sum i; } printf(%d\n, sum); return 0; }8. do-while 循环8.1 语法形式在循环语句中 do while 语句的使用最少它的语法如下do 语句; while(表达式);while 和 for 这两种循环都是先判断条件如果满足就进入循环执行循环语句如果不满足就跳出循环而 do while 循环则是先直接进入循环体执行循环语句然后再执行 while 后的判断表达式表达式为真就会进行下一次表达式为假则不再继续循环。8.2 do while 循环的执行流程8.3 do while 循环的实例在屏幕上打印 1~10 的值#include stdio.h int main() { int i 1; do { printf(%d , i); i i 1; }while(i 10); return 0; }运行控制台输出1 2 3 4 5 6 7 8 9 10一般 do while 使用在循环体至少被执行一次的场景下所以较少一些。8.4 练习输入一个正整数计算这个整数是几位数例如输入1234 输出4输入12 输出2参考代码#include stdio.h int main() { int n 0; scanf(%d, n); int cnt 0; do { cnt; n n / 10; } while (n); printf(%d\n, cnt); return 0; }9. break 和 continue 语句在循环执行的过程中如果某些状况发生的时候需要提前终止循环这是非常常见的现象。C 语言中提供了 break 和 continue 两个关键字就是应用到循环中的。break 的作用是用于永久的终止循环只要 break 被执行直接就会跳出循环继续往后执行。continue 的作用是跳过本次循环中 continue 后边的代码在 for 循环和 while 循环中有所差异的。9.1 while 循环中的 break 和 continue9.1.1 break 举例#include stdio.h int main() { int i 1; while(i 10) { if(i 5) break;//当i等于5后就执行break循环就终止了 printf(%d , i); i i 1; } return 0; }执行的结果1 2 3 4打印了 1,2,3,4 后当 i 等于 5 的时候循环在 break 的地方终止不再打印不再循环。所以 break 的作用就是永久的终止循环只要 break 被执行break 外的第一层循环就终止了。那以后我们在循环中想在某种条件下终止循环则可以使用 break 来完成我们想要的效果。9.1.2 continue 举例continue 是继续的意思在循环中的作用就是跳过本次循环中 continue 后边的代码继续进行下一次循环的判断。上面的代码如果把 break 换成 continue 会是什么结果呢#include stdio.h int main() { int i 1; while(i 10) { if(i 5) continue; //当i等于5后就执行continue直接跳过continue的代码去循环的判断的地方 //因为这里跳过了i i1所以i一直为5程序陷入和死循环 printf(%d , i); i i 1; } return 0; }到这里我们就能分析出来continue 可以帮助我们跳过某一次循环 continue 后边的代码直接到循环的判断部分进行下一次循环的判断如果循环的调整是在 continue 后边的话可能会造成死循环。9.2 for 循环中的 break 和 continue9.2.1 break 举例其实和 while 循环中的 break 一样for 循环中的 break 也是用于终止循环的不管循环还需要循环多少次只要执行到了 break循环就彻底终止我们上代码。#include stdio.h int main() { int i 1; for(i 1; i 10; i) { if(i 5) break; printf(%d , i); } return 0; }运行结果1 2 3 4break 的作用是永久的终止循环未来我们在某个条件发生的时候不想再继续循环的时候就可以使用 break 来完成。9.2.2 continue 举例上面的代码如果把 break 换成 continue 会是什么结果呢#include stdio.h int main() { int i 1; for(i 1; i 10; i) { if(i 5) continue;//这里continue跳过了后边的打印来到了i的调整部分 printf(%d , i); } return 0; }运行结果1 2 3 4 6 7 8 9 10所以在 for 循环中 continue 的作用是跳过本次循环中 continue 后的代码直接去到循环的调整部分。未来当某个条件发生的时候本次循环无需再执行后续某些操作的时候就可以使用 continue 来实现。在这里我们也可以对比一下 while 循环和 for 循环中 continue 的区别9.3 do while 循环中的 break 和 continuedo.while 语句中的 break 和 continue 的作用和 while 循环中几乎一模一样大家下来可以自行测试并体会。//break示例 #include stdio.h int main() { int i 1; do { if(i 5) break; printf(%d , i); i i 1; }while(i 10); return 0; }//continue示例 #include stdio.h int main() { int i 1; do { if(i 5) continue; printf(%d , i); i i 1; }while(i 10); return 0; }10. 循环的嵌套前面学习了三种循环 whiledo whilefor这三种循环往往会嵌套在一起才能更好的解决问题就是我们所说的循环嵌套这里我们就看一个例子。10.1 练习找出 100~200 之间的素数并打印在屏幕上。注素数又称质数只能被 1 和本身整除的数字。10.2 题目解析要从 100~200 之间找出素数首先得有 100~200 之间的数这里可以使用循环解决。假设要判断 i 是否为素数需要拿 2~i-1 之间的数字去试除 i需要产生 2~i-1 之间的数字也可以使用循环解决。如果 2~i-1 之间有数字能整除 i则不是素数如果都不能整除则是素数。10.3 参考代码#include stdio.h int main() { int i 0; //循环产生100~200的数字 for(i 100; i 200; i) { //判断i是否为素数 //循环产生2~i-1之间的数字 int j 0; int flag 1;//假设i是素数 for(j 2; j i; j) { if(i % j 0) { flag 0; break; } } if(flag 1) printf(%d , i); } return 0; }11. goto 语句C 语言提供了一种非常特别的语法就是 goto 语句和跳转标号goto 语句可以实现在同一个函数内跳转到设置好的标号处。例如#include stdio.h int main() { printf(hehe\n); goto next; printf(haha\n); next: printf(跳过了haha的打印\n); return 0; }goto 语句如果使用的不当就会导致在函数内部随意乱跳转打乱程序的执行流程所以我们的建议是能不用尽量不去使用但是 goto 语句也不是一无是处在多层循环的代码中如果想快速跳出使用 goto 就非常的方便了。for(...) { for(...) { for(...) { if(disaster) goto error; } } } error: //...本来 for 循环想提前退出得使用 break一个 break 只能跳出一层 for 循环如果 3 层循环嵌套就得使用 3 个 break 才能跳出循环所以在这种情况下我们使用 goto 语句就会更加的快捷。因为这节课主要是定义没有什么难点以及需要拓展的。本文大部分内容来自b站比特鹏哥的讲义如有兴趣大家可以去看他的视频课。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门