文章目录调试调试目标核心调试方法使用 VS 集成调试器设置断点启动调试单步执行与观察C语言的语句if语句语法结构if语句书写推荐if...else实例switch语句switch语句的特点核心switch语句与if...else语句的相同点switch语句与if...else语句的主要区别switch语句实例scanf函数读取scanf函数易错while循环while中的breakwhile中的continueEOF笔记《C语言经典范式解析while ((ch getchar()) ! EOF)》while ((ch getchar()) ! \n)的应用调试调试本质上就是赋予了我们掌控程序运行节奏的能力将原本不可见的代码执行过程变成了全程可视的白盒。就像在物品加工流水线上我们不仅能随时按下暂停键、以单步模式放慢动作还能通过断点直接定位到可疑环节甚至实时干预和修改变量数据来验证假设。这种步步紧盯、直击细节的方式让我们能够彻底拒绝凭空猜测亲眼看清数据流转的每一个微小步骤将排查问题变成一场有据可依的现场勘查。调试目标定位并修复代码中的编译错误、运行错误如崩溃、异常和逻辑错误结果不正确通过逐步分析代码执行过程找到问题根源。核心调试方法使用 VS 集成调试器设置断点在代码行左侧灰色区域点击或按 F9 快捷键设置/取消断点。断点处程序暂停执行便于观察状态。启动调试按 F5或工具栏 “启动调试” 按钮运行程序程序会在首个断点处暂停。单步执行与观察逐行执行F10Step Over执行当前行不进入函数内部。F11Step Into进入函数内部理解函数调用细节。观察变量“局部变量” 窗口自动显示当前作用域内的变量值。“监视” 窗口手动输入变量名如 myArray 实时查看值变化 。鼠标悬停在代码中的变量上直接显示当前值。C语言的语句C语言的语句就像编程时的“指令清单”,告诉计算机一步步干啥。顺序语句按照顺序一条一条执行比如赋值、输入输出。例子a 10;或printf(“Hello”);特点代码从上到下像排队一样一个一个来。条件语句根据条件决定是否执行。比如if … else和switch:if(a0){…}else{…} -“如果a大于0就做这事否则做那事”。特点让程序能“做选择题”根据不同情况干不同的事。循环语句重复执行某段代码。比如while、do…while、forwhilei10{…} -“只要i小于10就反复执行括号里的代码”。特点适合需要“重复劳动”的场景比如批量处理数据。跳转语句突然改变执行顺序比如break、continue、return、gotobreak -跳出循环比如循环到一半不想玩了就直接退出continue -跳出本次循环直接进入下一次return -结束函数可能带回一个值返回值goto -直接跳到指定标签的位置慎用容易把代码搞乱特点像“紧急通道”让程序不按照计划走。复合语句用大括号{}抱起来的一组语句。例子if(a 0){x 1;y 2;} -如果a大于0就同时执行x 1和y 2。特点把多条语句当做一个整体常用于条件或者循环里空语句只有一个分号啥也不干。if语句语法结构if(表达式)//如果表达式为真则下方语句执行语句;单支if(表达式)语句1else语句2示例int main(){int a 0;if (a 1)printf(“真的”);elseprintf(“假的”);return 0;}多分支if(表达式1)语句1else if(表达式2)语句2…else语句n;示例int main(){int a 1;if (a 0)printf(“红色”);else if (a 1)printf(“黄色”);else if (a 2)printf(“蓝色”);else;return 0;}代码块{ }if(表达式){语句列表1}else{语句列表2}示例int main(){int age 14;//执行多条语句时花括号不能省略。//if后面可以时一个语句也可以是代码块。但if后是代码块时必须用花括号括起来否则语法错误。//else后面与if类似不同点是当后面跟代码块时若不用花括号括起来程序正常运行。但只有第一行语句与条件有关其他语句与条件无关统一执行。if (age 17){printf(“成年\n”);printf(“可饮酒\n”);}else{printf(“未成年\n”);printf(“不可饮酒\n”);}return 0;}if语句书写推荐反面示范可读性差if(表达式){语句1;}else 语句2;正面示范可读性强if(表达式){语句1;}else语句2;if…else实例//一个48人的班级举行班级活动每组8人进行随机分组。int main(){int i 0;scanf(“%d”, i);//错误写法if (0 i 8)//编译器执行逻辑//1.先算0i结果是1真或0假。//2.再拿这个结果去和8比较即18或08.//3.结论无论i是多少结果永远为真。输出结果始终有“第1组”。if (0 i i 8)printf(“第1组\n”);if (i8 i 16)printf(“第2组\n”);if (i 16 i 24)printf(“第3组\n”);if (i 24 i 32)printf(“第4组\n”);if (i 32 i 40)printf(“第5组\n”);if (i 40 i 48)printf(“第6组\n”);else;return 0;}书写技巧int main(){int num 3;//if(num 5)//漏写“”语法正确不会报错if (5 num)//优化写法⭐⭐⭐⭐⭐printf(“hehe\n”);return 0;}//判断一个数是否为奇数int main(){int i 0;scanf(“%d”, i);if (1 i % 2)printf(“奇数\n”);elseprintf(“不是奇数\n”);return 0;}switch语句switch语句的特点核心基本语法结构switch表达式{case常量1:语句块1break;case常量2:语句块2;break;…default:默认语句块;}执行机制入口定位先计算switch后括号中表达式的值然后直接跳转到匹配的case标签处执行。贯穿执行Fall-through如果某个case执行完后没有break程序会继续向下执行后续所有case的语句直到遇到break或switch结束。default分支当所有case都不匹配时执行可放在switch中的任意位置不一定在最后。switch语句与if…else语句的相同点都是分支选择结构用于根据条件执行不同的代码块实现程序的流程控制。都基于条件判断通过判断某个条件是否成立决定走哪条执行路径。都可以实现多分支逻辑都能处理多个条件分支的场景。都支持嵌套使用switch语句内部可以嵌套if…elseif…else中也可以嵌套switch。本质上可以互相代替绝大多数情况下switch能实现的逻辑if…else也能实现反之亦然。switch语句与if…else语句的主要区别判断条件的类型不同switch语句只能做等值比较即判断表达式的值是否等于某个case后面的常量。if…else语句支持任何条件表达式可以使用关系运算符、、、、以及逻辑运算符、||、来组合出复杂的判断条件。支持的数据类型不同switch语句对数据类型有明确限制。在C/C、Java等语言中表达式通常只能是整型、字符型、枚举型。if…else语句没有类型限制只要表达式最终能求值为布尔类型true或false即可适用于所有数据类型。执行效率不同switch语句在编译时编译器通常会将其优化为跳转表。程序运行时根据表达式的值直接定位到对应的分支入口类似于数组的随机访问时间复杂度接近O(I)。分支数量越多switch的效率优势越明显。if…else语句采用的是自上而下逐个判断的方式每遇到一个else if就计算一次条件直到某个条件为真才执行对应代码块。最坏的情况下需要判断所有条件时间复杂度为O(n)。代码结构与可读性不同switch语句在处理同一个变量对多个固定值的判断时结构非常清晰- -所有分支平铺在同一层级一目了然代码整洁。if…else语句在条件复杂、涉及范围判断或多种逻辑组合时更加灵活自然。但当分支数量很多时大量的else…if层层堆叠代码会显得冗长可读性明显下降。灵活性不同switch语句的限制较多case后的值必须是编译期常用不能是变量或运行时才能确定的表达式。不支持范围判断比如无法直接写出“1到10之间的数”这样的分支只能逐个列举。-不支持复杂逻辑组合无法像if…else那样用、||连接多个条件。执行流程特性不同switch语句有一个独特的贯穿机制当某个case匹配并执行后如果该分支末尾没有写break程序不会自动跳出switch而是继续向下执行后续所有case的代码直到遇到break或switch结束。这个特性既可以被巧妙利用也容易因疏忽忘记写break而引发难以排查的逻辑错误。default和else的位置灵活度不同switch语句中的default分支可以放在任何位置程序会根据表达式的值跳转到匹配的case或default处执行。if…else语句中的else必须放在最后作为所有if/else if条件都不满足时的兜底分支位置不可调整。总结switch胜在效率高、结构清晰但使用场景受限只适合“单变量对多变量”的等值判断if…else胜在灵活通用能应对各种复杂条件但分支过多效率和可读性都会下降。两者各有优势应根据实际需求选择。switch语句实例实例1int main(){int day 0;scanf(“%d”, day);//%d内不能加\nswitch (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;}实例2int main(){int day 0;scanf(“%d”,day);switch (day){case 1:case 2:case 3:case 4:case 5:printf(“weekday\n”);break;case 6:case 7:printf(“weekdend\n”);break;default:printf(“选项错误\n”);break;}return 0;}实例3int main(){int a 0;int b 1;int c 2;switch (a){//switch是“跳转”指令根据变量的值直接跳转到对应的case行如若没有对应的case行则直接跳过整个//switch的穿透特性匹配到case 0后按照顺序一直向下执行所有的代码直出现break或switch的大括号处停下来。case 0:b;c;case 1:a c;b;c;printf(“%d %d %d \n”, a, b, c);//此时a3,b3,c4case 2:b;c;//3 4 5case 3://switch的穿透性是“同层case间的顺序执行”。//内部switch是“基于当前a的值重新匹配case行”属于新的分支选择switch (a){case 1:a;case 2:b;case 3:b;c;}printf(%d %d %d , a, b, c);//输出a3 ,b5,c6break;}return 0;}scanf函数读取缓存区有数据直接读取缓存区没有数据键盘输入按回车将数据存储到缓存区再被读取。scanf函数易错在scanf的格式字符串中空白字符包括空格、\t、\n的含义并不是“匹配一个换行符”而是告诉程序“请忽略并跳过输入流中所有的空白字符直到遇到下一个非空白字符为止。”int main(){int day 0;scanf(“%d”, day);//%d内不能加\nswitch (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;}分析:⭐⭐⭐scanf(“%d”, day);//%d内不能加\n程序现在像个“贪吃蛇”它把你按的回车键当成空气吃掉了还在傻等你再给它喂点别的东西。那个\n是个大坑你写的代码是scanf(“%d\n”, day); 。在C语言里\n放在scanf里意思不是“换行”而是“忽略所有空白”空格、回车都算空白。我的操作输入3然后按了 回车。程序的反应%d把数字3拿走了。接着遇到\n程序心想“哦主人让我忽略空白。”于是它把你按的回车键当成了空白直接吞掉忽略了。关键点来了因为它还在执行“忽略空白”的任务它会一直停在那里不动死死盯着键盘心想“怎么还没来个非空白的东西比如字母或数字让我停下来”所以光标会一直在那闪看起来像死机了一样。只有当你再随便输入一个字符比如输入个a再回车程序才会醒过来继续往下跑。while循环示例1int main(){while (1){printf(“hehe\n”);break;//注释掉此行将无限循环}return 0;}示例2//输出0~100内全部偶数int main(){int i 0;while (i 101){if (0 i % 2)printf(%d , i);i;}return 0;}while中的break//添加break语句后输出结果是149而非1100。int main(){int n 1;while (n 101){if (50 n)//循环中断//{break;//立刻终止整个循环//}printf(%d , n);n;}return 0;}while中的continuecontinue的作用跳过本循环内后面的所有程序进入到下次循环。示例1int main(){int n 1;while (n 101){//n 50时跳出本次循环不再执行printf与n。因此之后n恒等于50陷入死循环。if (50 n)continue;printf(%d , n); n;}return 0;}示例2//输出为1~100没有50int main(){int i 0;while(i101){i;if(50i)continue;printf(%d , i);}return 0;}EOF笔记int main(){//getchar()这是一个标准库函数用于从标准输入通常是键盘获取下一个字符。//EOF//end of file,其返回整数-1//! EOF判断获取到的字符是否等于文件结束符。只要不是结束符循环就会继续。//printf(“%c\n”, ch);打印字符ch//putchar(ch);输出字符ch//”Ctrlz“让getch获取返回EOFint ch 0;while ((ch getchar()) ! EOF){putchar(ch);}return 0;}本质它不是字符而是stdio.h里定义的一个宏 #define EOF (-1) 用来表示输入流结束的状态标记。为什么是-1正常字符的范围是 0~255用 -1 这个负整数来代表“结束”就能和所有正常字符区分开不会混淆。避坑指南接收getchar()返回值时变量一定要用int类型别用char否则容易截断导致死循环。代码习惯判断时永远用if(ch EOF)千万别直接写if(ch -1)用宏更规范以后换平台也不容易出错。《C语言经典范式解析while ((ch getchar()) ! EOF)》语句整体逻辑解读1.这句代码是C语言处理输入流的标准写法在一个步骤内高效完成了两件事2.获取数据赋值调用getchar()从键盘缓冲区读取一个字符并立即赋值给变量ch。3.判断条件循环控制检查刚才读到的字符是否等于EOFEnd Of File文件结束符。4.若读到有效字符ch的值不等于EOF条件为真进入循环体执行putchar(ch)输出字符。5.若读到结束信号ch的值等于EOF循环条件为假循环体终止执行。6.EOF并不是一个可以通过键盘直接敲出来的“字符”而是一个由操作系统发送的信号。Windows下通常通过按CtrlZ触发。为什么要给ch getchar()加括号1.核心原因强制改变运算优先级。2.原理分析在C语言中关系运算符!不等于的优先级高于赋值运算符。3.如果不加括号编译器会尝试先执行getchar() ! EOF 将比较结果0 或 1赋值给ch这会导致逻辑错误。4.加上括号后强制程序 先执行赋值操作。即先读取字符并存入变量ch然后再拿这个值去和EOF进行比较。总结这种写法既简洁又避免了重复调用函数是C语言中“读取并判断”的经典范式。while ((ch getchar()) ! ‘\n’)的应用示例1//getchar()////函数功能//1.getchar()这是C语言标准库中的一个函数它的作用是从标准输入通常是键盘读取下一个可用字符。//2.它会暂停程序的执行等待用户按下按键。一旦用户输入了字符并按下回车它就会获取缓冲区中的第一个字符。////变量存储//1.int tag这里定义了一个整数变量tag来接收getchar()的返回值。//2.gatchar()读的是字符但返回值类型是int。这是为了能容纳所有可能的字符值以及特殊的结束标识EOF。//输入10名学生的数学成绩并确认输入是否正确int main(){char mark[40] { 0 };printf(“请输入成绩”);scanf(“%s”, mark);//用户按下的那个回车符换行符\n并没有被scanf读取。而是留在了输入缓存区中。printf(“请确认成绩”);getchar();//检查缓冲区读取换行符从而使程序停下来等待用户再次输入。//确认输入成绩无误时再次输入Y即可。int tag getchar();//读取用户输入的第一个字符用于后续的确认判断。if (‘Y’ tag)printf(“正确\n”);elseprintf(“错误\n”);return 0;}示例2int main(){char mark[40] { 0 };printf(“输入成绩”);scanf(“%s”, mark);printf(“请确认成绩”);int ts 0;//清理缓存区while ((ts getchar()) ! ‘\n’){;}int tag getchar();if (‘Y’ tag)printf(“正确\n”);elseprintf(“错误\n”);return 0;}示例3//只打印数字字符int main(){int ch ‘\0’;while ((ch getchar()) ! EOF){//在C语言中char类型本质上就是整数。当我们用或比较字符时底层其实是在比较它们的ASCII码值。//字符’0’9’对应的ASCLL码值是4857其它ASCLL码值皆为非数字字符if (ch ‘0’ || ch ‘9’)continue;//跳出本次循环剩余的语句直接进入下一次循环判断putchar(ch);}return 0;}