【C++ 循环语句】while、do-while、for、范围 for 循环
引言在实际编程中我们经常需要重复执行某段代码多次例如遍历数组元素、累加求和、反复读取用户输入直到正确等。C提供了多种循环语句来实现重复执行while循环先判断后执行、do-while循环先执行后判断、for循环集初始化、条件、更新于一体以及 C11 引入的范围 for 循环简化容器遍历。掌握它们可以让你写出更简洁、高效的重复逻辑。本文将逐一介绍每种循环的语法、适用场景并通过内存模型解释循环在底层如何通过跳转指令实现最后给出练习题巩固。1.while循环语法while(条件){// 循环体}先判断条件若为真则执行循环体执行完后再次判断直到条件为假时退出。代码示例计算 1 到 100 的和#includeiostreamintmain(){intsum0;inti1;while(i100){sumi;i;}std::cout12...100 sumstd::endl;return0;}注意循环体内必须有能改变条件变量的语句如i否则会变成无限循环。2.do-while循环语法do{// 循环体}while(条件);先执行一次循环体再判断条件若为真则继续执行。至少执行一次适用于需要先执行再判断的场景如菜单输入验证。代码示例至少读取一次有效输入#includeiostreamintmain(){intnum;do{std::cout请输入一个正数;std::cinnum;if(num0){std::cout无效请重新输入。std::endl;}}while(num0);std::cout你输入了numstd::endl;return0;}3.for循环语法for(初始化语句;条件;更新表达式){// 循环体}执行顺序执行初始化语句只执行一次。判断条件若为假则退出。执行循环体。执行更新表达式。回到第 2 步。代码示例遍历数组#includeiostreamintmain(){intarr[]{10,20,30,40,50};intlengthsizeof(arr)/sizeof(arr[0]);for(inti0;ilength;i){std::coutarr[i] arr[i]std::endl;}return0;}灵活用法初始化、条件、更新都可以省略但分号不能省如for (;;)是无限循环。可以同时定义多个变量for (int i0, j10; ij; i, --j)4. 范围for循环C11 起语法for(元素声明:容器或数组){// 循环体}用于遍历整个数组、std::vector、std::string等支持迭代器的容器无需手动管理索引或迭代器。代码示例#includeiostream#includevectorintmain(){std::vectorintvec{1,2,3,4,5};// 只读遍历for(intx:vec){std::coutx ;}std::coutstd::endl;// 修改元素需要引用for(intx:vec){x*2;}// 使用 auto 简化类型for(autox:vec){std::coutx ;}std::coutstd::endl;// 遍历字符串std::string strHello;for(charc:str){std::coutc-;}std::coutstd::endl;return0;}注意范围 for 不能直接修改容器大小如插入、删除元素否则迭代器失效。5. 内存模型讲解循环的底层实现循环在 CPU 层面是通过条件跳转指令实现的和if-else类似但会形成向后跳转的环路。5.1while循环的伪汇编inti1;while(i100){sumi;i;}对应的伪汇编简化mov i, 1 ; i 1 loop_start: cmp i, 100 ; 比较 i 和 100 jg loop_end ; 如果 i 100跳出循环 mov eax, sum add eax, i ; sum i mov sum, eax inc i ; i jmp loop_start ; 无条件跳回 loop_start loop_end: ...jmp指令使 CPU 回到循环开始处形成向后跳转。循环变量i在内存或寄存器中不断更新。5.2for循环的等价转换for (int i0; in; i) { ... }可以被编译器转换为{inti0;// 初始化while(in){// 循环体i;// 更新}}内存布局上没有额外开销只是语法糖。5.3 范围for的底层范围for被编译器展开为基于迭代器的传统for循环。例如for(intx:vec){...}等价于for(autoitvec.begin();it!vec.end();it){intx*it;...}迭代器通常是指针或封装指针的对象内存上依次指向容器元素。5.4 循环对栈的影响循环体内定义的局部变量如int tmp在每次迭代中都会在栈上分配和释放作用域结束。尽量将不变的计算移出循环避免重复分配大对象。6. 常见错误与避坑错误说明正确做法忘记更新循环变量导致无限循环while (i 10) { sum i; }中忘记i确保循环体改变条件变量在do-while后忘记分号do {...} while (cond)后面必须有分号加上;范围 for 中试图删除容器元素迭代器失效使用传统 for 并小心处理浮点数作为循环条件精度问题可能导致多一次或少一次使用整数或比较时加容差循环体内定义大数组如int arr[10000];每次迭代都分配栈空间可能溢出将定义移到循环外或使用动态内存7. 练习题题目编写一个 C 程序完成以下任务使用while循环计算斐波那契数列的前 20 项第一项为 0第二项为 1并输出到控制台。使用do-while循环反复提示用户输入一个 1~10 之间的整数直到输入正确为止然后输出该数的平方。使用for循环输出 100 以内的所有质数质数定义大于1且只能被1和自身整除。使用范围 for 循环遍历一个std::vectorstd::string内容为{apple, banana, cherry}将每个字符串转换为大写并输出提示可以使用toupper或循环修改字符。输出示例仅示意斐波那契前20项: 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 请输入1~10的整数: 12 无效请重新输入: 5 5 的平方是 25 100以内的质数: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 大写水果: APPLE BANANA CHERRY上期参考答案#includeiostreamintmain(){inta,b;charop;std::cout请输入两个整数;std::cinab;std::cout请输入运算符;std::cinop;switch(op){case:std::couta b abstd::endl;break;case-:std::couta - b a-bstd::endl;break;case*:std::couta * b a*bstd::endl;break;case/:if(b0){std::cout错误除数不能为零std::endl;}else{std::couta / b a/bstd::endl;}break;case%:if(b0){std::cout错误取模除数不能为零std::endl;}else{std::couta % b a%bstd::endl;}break;default:std::cout不支持的运算符std::endl;break;}return0;}总结while、do-while、for和范围for覆盖了几乎所有重复执行的需求。while适合条件不确定的循环do-while保证至少执行一次for最适合计数循环范围for让容器遍历变得极其简洁。理解循环的底层跳转机制有助于你写出更高效的代码。通过本次练习题你应能熟练运用这四种循环解决实际问题。下一篇文章我们将学习跳转语句break、continue、goto进一步控制循环流程。