news 2026/10/1 4:24:38

C语言while循环详解:语法、执行流程与常见坑全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C语言while循环详解:语法、执行流程与常见坑全解析

我先说个真实场景:很多刚学C语言的读者,第一次写"输出1到100"这个作业时,第一反应是把printf复制一百遍,或者写十遍然后改数字。我当时见过最夸张的一份代码,是用宏定义批处理生生拼出了100行printf,编译倒是过了,输出也对了,但老师让他改成"输出1到200",他愣是又多复制了100行。循环语句的价值,就是在这一刻体现出来的——用while、for这样的小结构,把"重复"这件事交给机器,而不是交给人的手和眼。

这篇博文我打算围绕着C语言的while循环来写,适合三种人看:刚接触循环的初学者、能把for用熟但一遇到while就发怵的过渡期选手、以及想系统梳理while和do-while区别的复习者。我会把while的语法、执行流程、典型场景、常见坑、综合案例全部串一遍,每一处都会解释"为什么这么做",而不是只丢给你一段能跑的代码。

1. 先搞清楚while解决的是什么问题

1.1 重复代码的痛点:不是懒,是错误的来源

重复代码最大的问题不是费手,而是它会把一个错误复制N遍。比如你写了十遍printf("第%d次\n", i),其中第七遍的%d位置写成了%d2,编译可能还能过,输出却错得莫名其妙。机器帮你打印一个数字,和机器帮你判断"还要不要继续打印",本质上是两件完全不同的事。打印机再快,也只能按照你给的单子逐行输出;而循环语句是让你把"判断规则"写出来,让程序自己决定执行多少次,以及什么时候停止。

从工程角度来看,循环的意义是消除重复,同时保留灵活性。你今天要输出100个数,明天要输出1000个,改动的地方只有条件那一处。这一点在后续做文件读取时尤其明显——一个文件有多少行,你根本不可能提前知道,但while循环可以在运行时不断读取,直到文件末尾。

1.2 条件驱动:while只关心"什么时候继续"

while的英文原意是"当……的时候",它的语义可以翻译成:当条件成立的时候,就一直做某件事。这句话里藏着一个重要的设计思路——while并不关心"这件事做了多少次",它只关心"下一个时刻条件还成不成立"。

打个比方:食堂窗口打饭。阿姨不会数"今天打过第几个学生了",她只重复同一个动作——当前面还有人,就继续打;没人了,就停下来。这个"前面还有人"就是条件,是实时的、动态的。这种模式在编程里叫条件驱动循环,知道次数不是必须的,知道条件才必须。

这种"不问次数、只看条件"的机制,决定了while最适合的场景:循环次数未知、运行时才能确定、甚至可能一次都不执行。这一点我后面会在"不可替代场景"那一节展开。

1.3 最小可运行示例:用while从1数到100

先看一个最标准的入门例子,把1到100打印到控制台:

#include <stdio.h> int main(void) { int i = 1; while (i <= 100) { printf("%d\n", i); i = i + 1; } return 0; }

运行结果就是从1到100逐行输出。这个例子中我故意用了i = i + 1而不是i++,是想让初学者看清楚循环的三个关键动作的配合:int i = 1负责设定起点,i <= 100负责判断"还继续吗",i = i + 1负责让状态向停止的方向推进。这三者缺一不可。

需要注意,这个例子里循环次数其实是已知的(100次),严格说用for更顺手。但用它做while的入门例子最直观,因为while的结构比for更简单,你一眼就能看到"条件判断"和"状态更新"这两根支柱,不会被for那套"初始化;条件;更新"的三段式写法干扰。等看懂了while,再去回看for,会发现它就是while的语法糖包装。

2. 纸上推演加调试器,把while的执行过程看穿

2.1 变量追踪法:人肉执行一遍循环

初学者常见的困惑是:明明我理解了每一行代码,但整个循环怎么跑起来的,脑子里还是乱。这里我推荐一个几乎不需要设备的方法——变量追踪表。拿出一张纸,画三列:循环变量i的值、条件i <= 100的结果、本次循环有没有执行。然后一行一行手写执行,哪怕只追踪前三次:

当i的值条件i <= 100执行printf?执行i+1后i变成
1真是2
2真是3
3真是4
............
100真是101
101假否,循环结束-

关键在第100次之后那一步:i变成101,回到循环顶部判断,发现101 <= 100为假,于是跳过循环体,程序继续执行return 0。很多同学以为循环是"到100就自动停",其实它多走了一步,是等到i变成101才发现该停。这一步的理解比什么语法都重要——它解释了为什么你的循环有时候会"多执行一次"或者"少执行一次"。

这种纸笔推演,我建议每个初学者至少完整做一次,选一个循环次数为3的小例子做全程追踪,比在电脑上瞎试半小时效率高得多。

2.2 用调试器观察真实状态

纸笔推演能建立思维模型,但人总有算错的时候。这时就得请出调试器。现在主流环境都能做到,Visual Studio Code配合C语言插件按F5就能进入调试模式;命令行派可以用gdb。

调试while循环的关键操作只有三个:在循环体第一行下断点、逐个观察变量的实时值、用"单步执行"让循环一步一步走。你会在调试器的变量窗口里亲眼看到i从1变成101的完整过程,条件判断的结果也会在"监视表达式"里实时显示真假。这个过程不用太久,把上面那个1到100的例子走一遍,你就彻底理解了while的运行顺序。

我在大学时教过的很多学生都卡在这一步:他们相信代码"应该"是对的,却不愿用调试器核实变量到底变成了什么。结果就是对着屏幕猜。实际上,学会在循环里看变量变化,比多做十道习题都值。

2.3 循环三要素:初始化、条件、更新

以我多年写代码和帮人排查代码的经验,绝大多数while循环的bug,最后都能归到这三件事上:初始化是否正确、条件是否会在某个时刻变假、更新是否真的被执行。这就是很多教材强调的循环三要素。

在while循环写完之后,记得像下面这样自查一遍:

int count = 0; // 要素一:初始化,决定循环从哪里开始 while (count < 10) { // 要素二:条件,决定何时停止 printf("%d\n", count); count++; // 要素三:更新,决定能否朝停止方向推进 }

三个要素任何一个出问题,结果就是死循环、不执行、或者次数不对。这也是为什么我说,理解while的关键不是记住"条件为真就执行"这句话,而是能把三要素在具体代码里一眼标出来。

提示:在实际工程项目里,如果循环体很长,尽量把更新语句放在循环体尾部且仅出现一次。如果更新语句散落在多个if分支里,你会容易踩continue跳过更新的坑,这在第6节会专门讲。

3. while真正不可替代的场景:次数未知的重复

3.1 用户输入校验:程序不知道用户什么时候才肯输对

循环次数不确定的经典场景,就是用户输入校验。你写一个要求输入整数的程序,用户却输了"abc",你必须让他重新输,直到输对为止。那你事先知道他要输几次吗?不知道。可能是1次,可能是10次,也可能他一直打算跟你耗到下班。

这种"次数未知"的场景,for没法优雅处理,while是天然选择。常见写法如下:

#include <stdio.h> int main(void) { int num; printf("请输入一个整数:"); while (scanf("%d", &num) != 1) { // 清空输入缓冲区中的错误字符 while (getchar() != '\n'); printf("输入无效,请重新输入:"); } printf("你输入的是:%d\n", num); return 0; }

这里有几个细节值得解释。scanf的返回值是成功读取的变量个数,这里要求是1。如果用户输入的不是整数,scanf返回0,说明这次转化失败,我们需要清掉缓冲区里残留的字符,再提示用户重新输入。你有没有发现这里内层又是一个while?它利用getchar()反复读字符,直到读走换行符,把缓冲区清理干净。两层while嵌套,解决的是现实中"错误输入后怎么办"的问题。

3.2 文件读取:要读到文件末尾才知道停

另一个"次数未知"的极典型场景是读文件。普通文本文件有多少行,程序在运行前不可能知道,除非你提前数好写死在代码里——但这显然不合理。用while配合fgets读取,就是标准解法:

#include <stdio.h> int main(void) { FILE *fp = fopen("data.txt", "r"); if (fp == NULL) { printf("文件打开失败\n"); return 1; } char line[256]; while (fgets(line, sizeof(line), fp) != NULL) { printf("%s", line); } fclose(fp); return 0; }

fgets每读一行,成功就返回字符串指针,读到文件末尾就返回NULL。这个NULL就是循环终止条件。你根本不用关心文件里是3行还是3000行,条件会替你判断。这里while循环体现出的优势是"优雅应对未知边界"——在实际开发里,这种动态结束条件的场景占比非常高。

3.3 菜单循环和状态机:让程序"活"起来

如果程序要呈现一个菜单,让用户反复选择操作,直到选"退出"为止,这也是未知次数的循环。这种场景用do-while会比纯while舒服,因为菜单至少要展示一次:

#include <stdio.h> int main(void) { int choice; do { printf("\n===== 学生成绩管理 =====\n"); printf("1. 录入成绩\n"); printf("2. 查看成绩\n"); printf("0. 退出\n"); printf("请选择:"); scanf("%d", &choice); while (getchar() != '\n'); // 清空残留的换行符 switch (choice) { case 1: printf("执行录入逻辑...\n"); break; case 2: printf("执行查看逻辑...\n"); break; case 0: printf("再见\n"); break; default: printf("无效选项,请重新选择\n"); break; } } while (choice != 0); return 0; }

注意do-while和while的关键差异:do-while先执行循环体,再判断条件,所以循环体至少执行一次。这个特性用在"必须先弹出菜单再判断要不要退出"的场合,比while少一次条件判断。老生常谈的"while和do-while区别",在这个例子里可以说讲透了。

4. while、for、do-while:三种循环到底怎么选

4.1 一张表说清语义差异

C语言让人纠结的不是"循环怎么用",而是"到底用哪个循环"。很多初学者在while和for之间反复横跳,代码里一会儿写for一会儿写while,风格混乱。我先给一张选型对照表:

循环判断时机最少执行次数最典型场景语义重心
while先判断后执行0条件驱动的重复什么时候继续做
do-while先执行后判断1菜单、用户交互至少要做一次
for先判断后执行0次数明确、范围遍历初始化-条件-更新集中管理

这张表的记忆方法很简单:while和for都是"先看条件再说",do-while是"先干一票再看要不要继续"。所以do-while最适合那种"不管三七二十一,先把菜单显示出来/先把动作执行一次"的程序。

4.2 for其实就是while的语法糖

很多人学for的时候不理解为什么for (i = 0; i < 5; i++)能一行搞定三要素,其实它的本质就是把while的"初始化、条件、更新"压缩到一行,让程序员无法忘记任何一环。看下面的对照:

// 用while实现 int i = 0; while (i < 5) { printf("%d\n", i); i++; } // 用for实现 for (int i = 0; i < 5; i++) { printf("%d\n", i); }

两种写法完全等价。当你用for时,C语言其实是把i = 0放在循环开始前先执行一次,然后判断i < 5,执行循环体,再执行i++,再回到条件判断。这个执行顺序,和while版本一模一样。区别只在于:for的结构强制你把三要素放在一起,阅读代码时一目了然;while则更灵活,但同时也更容易让你漏掉某个要素。

提示:在C语言项目中,for循环里的int i = 0写法要求C99或更高标准。如果你的编译器比较老,可能要写成int i;再在for里赋值i = 0,或者自己把握标准版本。

4.3 我的选型规则

基于上面的分析,我的选型习惯是三条规则。

第一,循环次数一开始就明确(从0到N遍历数组、算1加到100),用for。这个场景属于计数驱动循环,for的三段式结构是天然匹配的,也方便其他人一眼看懂边界。

第二,循环结束条件取决于运行时动态数据(读文件读到头、等待有效输入、状态机切换),用while。这个场景的重点是"条件何时为假",for的计数语义反而不合适。

第三,至少要执行一次的交互逻辑(菜单、协议握手、先尝试后判断),用do-while。这样代码里根本不需要在while之前手动写一次重复逻辑,也不会出现"忘了先执行一次"的bug。

这条规则帮我处理过非常多代码评审里的风格问题。本质上,选循环不是在比谁更炫,而是看哪一种写法能最小化"读代码的人理解成本",最小化"你将来改条件时改错"的风险。

5. 死循环的两副面孔:翻车事故和有意的设计

5.1 事故现场:为什么你的程序停不下来

我见过太多初学者写这样的代码,然后整个终端疯狂刷屏:

int i = 1; while (i <= 10) { printf("%d\n", i); // 忘了写 i++; }

这个循环里,i永远等于1,条件i <= 10永远为真,于是一直打印1。程序不会停,直到你强制关闭。英文里管这叫infinite loop,也就是死循环。

问题根源是三要素里的"更新"被漏掉了。初学者往往觉得printf已经写在循环体里了,怎么还要再写点什么?关键就在于:循环体必须改变某个跟条件相关的变量,让条件有从真变假的可能。没有这一步,循环体执行的再欢,条件判断也会永远为真。

还有一种更隐蔽的死循环,来自变量的类型边界。比如:

unsigned int i = 10; while (i >= 0) { printf("%u\n", i); i--; }

i是无符号整数,当它从0减1时,不是变成-1,而是下溢回了一个很大的正数,所以i >= 0永远为真。这种bug在带符号int里不会出现(因为i会负到满足条件停止),但恰恰因为平时用int习惯了,很多人掉进unsigned的坑里还没意识到。排查方法是:用调试器看每次循环结束时i到底变成了什么值,别靠猜。

5.2 死循环不一定都是bug

死循环不一定都是坏事。相反,很多程序的骨架就是刻意构造的死循环。最典型的是while (1),它的条件是永远为真的整数常量1,所以循环体永远执行。这种写法广泛用于事件循环、服务器主循环、嵌入式系统主程序、以及图形界面的消息循环。

一个服务器进程启动后,需要不停地接受连接、处理请求、返回响应。如果循环条件很快变假,服务器就会退出——这显然不行。所以你会看到类似下面的骨架:

while (1) { // 等待并处理业务事件 // 收到退出指令时,用break或return跳出 }

这里面有个重要的工程原则:死循环的退出方式,必须由循环体内显式控制,而不能指望自然结束。显式退出的手段主要有三种:

  • break:跳出当前循环层,继续执行循环后面的代码。
  • return:直接结束当前函数,常用于main函数里直接退出程序。
  • 标志变量:定义一个整型flag,条件写成while (flag),循环体内在合适时机把flag改成0。

我推荐在业务逻辑复杂的循环里优先考虑标志变量,因为它在循环条件处就暴露了"什么时候结束"的语义,比藏在循环体中间的break更容易被后来维护的人发现。break当然快,但可读性差一些——尤其当break藏在几十行代码深处时,他人都未必知道这里其实是退出的唯一出口。

6. while实战避坑清单:初学阶段最容易翻车的细节

6.1 scanf返回值不检查:你以为用户会规规矩矩输入?

前面用户输入校验的例子已经提到scanf有返回值。实际项目里,很多C语言老写手在写快速验证程序时,也会跳过返回值检查。但既然讲while实战,我得把话说重一点:凡是循环里依赖输入的代码,必须检查scanf返回值。

一个典型的反例是用户输入时手滑输入了"12abc",scanf读取%d时遇到a就会停止,把a留在缓冲区。下次再调用scanf,可能还是读不走a,于是循环条件判断和实际读取就错位了。更麻烦的是换行符,scanf读取数字后通常不会消耗掉后面的换行符,如果后续还有字符输入函数,就会读到那个残留的换行。

处理方案是同步清空缓冲区,我用过最顺手的就是:

while (getchar() != '\n');

这段代码就是一个极简while循环:不断读取字符,直到把换行符读掉。把它放在一次scanf之后,能省掉后续大半的输入不干净问题。

注意:清空缓冲区的写法在不少教程里会展开成while ((c = getchar()) != '\n' && c != EOF);,这是更健壮的版本。它额外判断了EOF,防止输入流意外结束时陷入死循环。如果是严谨项目,建议用带EOF判断的完整版。

6.2 边界条件是用"<"还是"<=",就差一次机会

边界条件是C语言循环里最经典的低级错误。你要打印1到10,写while (i < 10),结果只会打印1到9;写while (i <= 10)才对。反过来,你要用0到9遍历数组,写while (i <= 9)也行,但社区更普遍的习惯是while (i < 10),因为它直接对应数组长度10。

为什么大家偏爱左闭右开[0, 10)这种写法?因为当你用i < 数组长度时,循环变量i的取值天然落在0到9,正好是数组下标的合法范围;while的最终判断时机是i变成10的时候,那时不会再访问数组。这是一种约定俗成的安全写法。

我的建议是:涉及数组下标、迭代次数明确的场景,一律写i < 长度,不要写i <= 长度-1,省一次减法,也让可读性更好;涉及"从1到N"的自然数场景,写i <= N更贴近问题描述。关键是每次写完循环,拿边界值代入验证一次——比如i=0和i=长度-1,再加上越界的长度,脑子里过一遍。这样做两个月,就不用再担心边界错了。

6.3 条件里写成赋值:while (x = 5)的天坑

在C语言里,赋值表达式的值就是被赋的那个值,所以while (x = 5)不会报错,甚至条件恒为5,永远为真。它本意可能是判断x == 5,手滑少写一个等号,结果程序写成死循环。

这个坑在C语言面试题里属于常客。写出这句的后果是:x在每次进入条件判断时被重置为5,在任何想靠x变化来结束循环的逻辑下,循环都停不下来。而且由于它对x有副作用,即使你用调试器看,也可能一头雾水——因为x确实被改变了,只是被改回了5。

如何防?两个习惯。第一,写条件时把常量放在等号左边,写成while (5 == x),这样如果漏写等号变成while (5 = x),编译器会直接报错,因为你不能给常量赋值。这个习惯虽然看起来别扭,但能拦下大量手误。第二,开启编译器警告,主流编译器对while (x = 5)都会给出"建议加括号或使用=="的提醒,别忽略它。

还有一个和它类似但合法的经典写法,是while (ch = getchar())。这种代码在字符处理的C语言老代码里很常见,它把"读取字符"和"判断是否读到终止符"合并到条件表达式里。新手看它觉得高深,老手看它觉得危险——因为一旦输入流异常,getchar返回EOF,你在条件里赋值的ch如果是char类型,返回的int的EOF可能被截断,导致判断失效。所以我的建议是:学习时理解它,实际写代码时拆开写,一行读、一行判断,不要追求这种炫技写法。

6.4 continue跳过更新语句:更新写错位置的经典死循环

continue的语义是结束本次循环体的执行,直接进入下一次条件判断。看起来简单,但配合while会埋一个雷:如果循环体里的状态更新写在continue之后,那么continue一执行,更新就被跳过了。

int i = 0; while (i < 10) { if (i % 2 == 0) { printf("%d是偶数\n", i); continue; // 跳到条件判断,不会执行下面的i++ } printf("%d是奇数\n", i); i++; }

这段代码在i=0时执行continue,i永远不更新,然后死循环。改成for之后同样的问题就不容易犯,因为for的更新语句i++写在for那行的括号里,跟循环体结构上分离,continue跳不到它。这就是为什么前面我说for在"次数明确的循环"里更稳的一个具体原因。

如果必须用while,我建议把更新语句写在循环体最前面,或者干脆每处需要continue之前都手动更新一次。但最干净的方案是:这种情况直接换用for,别跟while较劲。

6.5 break只跳出一层:嵌套循环的退出困局

嵌套循环里如果写了break,它只跳出包含它的最近一层循环,而不是跳出所有循环。比如你在双重循环里要找到第一个满足条件的坐标,break之后写在新循环体里,结果外层还在继续跑。

常见解法是标志变量。我在第5节提到过,这里正好用它解决实际问题:

int found = 0; for (int i = 0; i < 10 && !found; i++) { for (int j = 0; j < 10; j++) { if (a[i][j] == target) { found = 1; break; // 只跳出内层循环,外层因为!found为假也会停止 } } }

这里break负责跳出内层,外层循环的条件!found负责让外层也结束。这个模式很经典,比用goto跳出的冒进方案稳健,也比纯靠break记数级数优雅。当然,极端复杂的情况下goto并非绝对不可用,但作为初学者,先把标志变量方案练熟,今后读代码时你会发现到处都是这个套路。

7. 两个综合案例:九九乘法表和5×5鞍点

7.1 九九乘法表:双重while的排版细节

九九乘法表是C语言作业里的"老朋友",很多同学的第一个嵌套循环就写的它。while版本可以这样写:

#include <stdio.h> int main(void) { int i = 1; while (i <= 9) { int j = 1; while (j <= i) { printf("%d*%d=%-2d ", j, i, i * j); j++; } printf("\n"); i++; } return 0; }

输出效果是阶梯状的乘数表。注意几个细节:内层循环的条件是j <= i,所以第i行只输出i个乘积,形成左下三角形;%-2d的负号让结果左对齐、占两位,两个空格做间隔,表格才能对齐。这个程序完整体现了嵌套循环的逻辑:外层的i控制行数,内层的j控制每一行的列数。内层循环每次从头开始,所以在进入内层前要把j重新设为1——这个"重置内层循环变量"的动作,是嵌套循环最容易漏的一步。

我把这题放在文章靠后的位置,是因为它已经把"循环嵌套""边界选择""格式化输出"三个知识点拉通了。如果你能不看答案自己写出来,说明你对while的执行顺序已经形成了手感。

7.2 鞍点问题:用while输入,再理解什么时候不用while

再上一个稍微硬核的题:一个5×5矩阵,找鞍点。鞍点的定义是:该位置的值是它所在行的最大值,同时也是它所在列的最小值。教材作业和数据结构的同学应该很熟悉这个题。

#include <stdio.h> #define ROW 5 #define COL 5 int main(void) { int a[ROW][COL]; int i, j, k; int found = 0; printf("请输入5x5矩阵:\n"); i = 0; while (i < ROW) { j = 0; while (j < COL) { scanf("%d", &a[i][j]); j++; } i++; } i = 0; while (i < ROW && !found) { int max_col = 0; for (j = 1; j < COL; j++) { if (a[i][j] > a[i][max_col]) { max_col = j; } } int is_saddle = 1; for (k = 0; k < ROW; k++) { if (a[k][max_col] < a[i][max_col]) { is_saddle = 0; break; } } if (is_saddle) { printf("鞍点位于第%d行第%d列,值为%d\n", i + 1, max_col + 1, a[i][max_col]); found = 1; } i++; } if (!found) { printf("不存在鞍点\n"); } return 0; }

这个例子我做了一个很刻意的设计:矩阵输入用while,因为输入时行数和列数虽然是已知的2D结构,但此时重点在"按行逐列填满",用while能直观展示两层循环的逐格推进。而寻找每行最大值时我换回了for,原因就是第4节说的选型规则——扫描固定列数时,for的计数语义更清晰,也更不容易出现漏更新。

鞍点问题的核心思路分两步:第一步,在某一行里找到最大值所在列;第二步,验证这个最大值是否也是该列的最小值。只要有一列的元素比它小,它就不是鞍点,跳到下一行继续找。如果没有找到任何一个鞍点,最后输出提示。这个"先定位候选,再验证候选"的思路,比直接暴力比较所有点要清晰得多,将来你在算法题里会反复看到它。

7.3 循环代码的工程卫生:给以后的自己留条活路

两个案例跑通之后,我想聊几句循环代码的"长期健康"问题。

第一个建议是循环控制尽量集中。while循环体超过15行时,条件、更新、退出机制会散落在各处,读代码的人(包括三个月后的你自己)很难一眼看清循环到底怎么运转。工程上常见做法是把循环体封装成函数,循环内只保留主要流程,真正做到"条件在头、更新在尾、退出有显式路径"。

第二个建议是变量命名要有语义。写while (i < n)当然没问题,但在业务里,用count、pos、index这样有含义的名字,能避免大量"这个i到底是第几层循环"的迷惑。我在维护老项目的过程中,见过最崩溃的循环变量名是a、b、c三层循环,中间还夹杂一个叫temp的状态标志,改起来只能边猜边试。

第三个建议是留注释不要只吐槽。对循环边界、退出条件这些容易出错的点,一行注释说清楚"为什么条件是<长度而不是<=长度",能免去后面的维护者踩同样的坑。

我的学习顺序建议和最后的体会

如果让我给一个从零开始的学习路径,大概是:先用手写变量追踪表跑通一个简单的while例子,再用调试器观察同一段代码,对比人肉运行和机器运行是否一致;然后写三四个次数未知的场景练习,比如不断读整数直到输入0为止,统计输入个数和总和;接着做九九乘法表和鞍点这样的综合题,把嵌套循环和问题建模练熟;最后再看自己能不能用do-while重写一个菜单程序。这个顺序的好处是每一步都建立在前一步的直接体验上,而不是死记语法。

我自己在实际教学和写代码中观察到一个现象:大部分while用不好的同学,问题不在while本身,而在于没想清楚"循环到底什么时候停"。条件、更新、退出这三件事,只要有一个模糊,代码就会在各种边界上翻车。所以我对你只有一个核心建议:拿到任何循环题,先别急着敲代码,用一句话把"什么情况下继续,什么情况下停止"说清楚,再动手。这句话想通了,while就通了一大半。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 4:24:36

外挂检测原理揭秘:反作弊系统如何识别与封禁违规玩家

打游戏最烦的不是掉线&#xff0c;不是猪队友&#xff0c;而是你在认真对枪的时候&#xff0c;屏幕上突然弹出一句"游戏安全组件运行时发生异常&#xff0c;请关闭不必要的软件"&#xff0c;然后游戏直接把你踢下线。最近好几个朋友都跑来问我这个问题&#xff0c;尤…

作者头像 李华
网站建设 2026/10/1 4:24:21

开源版Jev本地部署全攻略:从Ollama到RAG实战

1. 为什么“本地部署”这件事值得认真对待1.1 从“调用接口”到“把模型搬回家”的转变这两年我身边做开发的朋友&#xff0c;聊天话题从“你调哪个接口”慢慢变成了“你本地跑什么模型”。这个转变不是赶时髦&#xff0c;而是被现实逼出来的。接口调用有它的好处&#xff0c;开…

作者头像 李华
网站建设 2026/10/1 4:24:16

Python字母数字识别实战:从OpenCV预处理到Tesseract与CNN

简介&#xff1a;这是一份面向课程设计场景的字母数字识别工程&#xff0c;基于 Python 3.7 与 TensorFlow 2.1 实现&#xff0c;在 EMNIST 数据集上完成手写英文字母和数字的分类&#xff0c;同时以 ResNet 的简易实现展示卷积网络在图像识别任务中的落地过程。压缩包共 50 个…

作者头像 李华
网站建设 2026/10/1 4:22:29

生成式推荐新范式:端到端可学习分词如何突破物品表示瓶颈

我最近在系统地扫生成式推荐方向的论文&#xff0c;坦白讲&#xff0c;大多数工作还停在"把LLM套到推荐上"的层面&#xff1a;要么把物品ID塞进词表&#xff0c;让语言模型去预测&#xff1b;要么用文本描述作为物品的软标识。这类做法都有个共同的问题——物品对语言…

作者头像 李华
网站建设 2026/10/1 4:22:13

用Python与Twilio搭建短信通知系统:从监控告警到验证码

半夜手机突然震动&#xff0c;屏幕上跳出“服务器CPU使用率超过90%&#xff0c;请立即处理”的短信。这个场景对于任何一个运维或者独立开发者来说都不陌生。项目不大&#xff0c;但价值极高&#xff1a;用Python调用Twilio的API&#xff0c;几十行代码就能搭起一套可靠、可扩展…

作者头像 李华
网站建设 2026/10/1 4:22:11

Java面试官实录:三轮问答揭开高并发候选人的真实水平

我见过不少简历很唬人的Java候选人&#xff0c;但很少见到简历和实际水准能差成蔡虚昆这个程度的。上个月我作为技术面试官&#xff0c;面了一位自称“精通Java、擅长高并发、在电商核心链路摸爬滚打三年”的后端开发。看完简历我挺兴奋&#xff0c;聊完第一轮我挺失望&#xf…

作者头像 李华