C语言基础第6天:分支循环
一、回顾分支结构
单分支:if...
双分支
- if..else..
- 三目运算符:表达式 1 (条件表达式)? 表达式 2 (语句 1): 表达式 (语句 2); 适用于输出型单语句的双分支。
- 示例:判断一个数是偶数还是奇数
#include <stdio.h>int main()
{int num = 5;// 双分支:if..elseif (num % 2 == 0) printf("%d 是偶数!\n", num);else printf("%d 是奇数!\n", num);// 双分支:三目运算符// 方式1(num % 2 == 0) ? printf("%d 是偶数!\n", num) : printf("%d 是奇数!\n", num);// 方式2printf("%s\n", (num % 2 == 0) ? "偶数" : "奇数");// 方式3char *p = (num % 2 == 0) ? "偶数" : "奇数";printf("%d 是 %s!\n", num, p);return 0;
}
多分支
- if..else.. 嵌套(不推荐)
- if..else if....else
- switch..case..
二、循环结构
(一)循环结构概述
定义:代码在满足某种条件的前提下,重复执行,就叫做循环结构。
分类
- 无限循环:其实就是死循环,程序设计中要谨慎使用。
- 有限循环:循环限定循环次数(for)或者终止循环的条件(while, do..while)。
构成
- 循环条件:如循环次数或者循环的出口。
- 循环体:需要重复执行的代码(也就是 {} 包裹的内容)。
(二)当型循环的实现
特点:先判断,后执行,如果条件不满足,循环体一次都不执行。代表:while、for。
- while 循环
- 语法
【1】循环变量;
while (【2】循环条件)
{【3】循环语句;【4】更新循环变量;
}
- 注意:如果循环语句是单语句,可以省略 {};有些特殊场景下,循环体语句糅合到了循环条件中,所以省略掉循环体。
- 说明:循环条件的返回值必须是逻辑值(使用非 0 表示真,使用 0 表示假,C 语言底层使用 1 表示真)。C99 版本引入了 stdbool.h,可以使用 true 或者 false 来表示真假,这里的 true 和 false 实际上就是定义的两个符号常量,true 的值是 1,false 的值 0。
- {} 包起来的内容整体称之为循环体。
- 要在循环体中控制循环条件的变化,也可以在循环条件中控制循环条件的变化,否则产生死循环。
- 案例:求 1~100 的累加和
#include <stdio.h>int main(int argc, char *argv[]){// 创建一个变量sum = 0,用来存储累加和,因为参与计算,所以必须有初始值int sum = 0;// 创建一个循环变量并初始化int i = 1;// 通过一个循环生成1~100的自然数,并实现累加和运算while (i <= 100) // ()循环条件,限制循环变量的变化,循环的出口限制{// 累加和运算sum += i;// 更新循环变量,逼近出口i++; // 等价于 i = i + 1 、i += 1 、++i}printf("1~100的累加和是%d\n", sum);return 0;
}
运行结果:1~100 的累加和是 5050。
- 案例:求 1~100 以内的偶数和
#include <stdio.h>int main(int argc, char *argv[])
{// 创建一个变量sum = 0,用来存储累加的偶数和int sum = 0;// 创建一个循环变量i = 2,存储参与运算的自然数(最小的偶数是2)int i = 2;// 创建一个循环,设置循环条件 i <= 100while (i <= 100){// 在循环体内,需要用一个if校验i是否是偶数,如果满足条件,就实现偶数和的计算:sum += iif (i % 2 == 0)sum += i;// 在循环体的最后一行,需要更新循环变量,作用是逐渐逼近循环的出口i++;}// 循环结束后,才能输出sum。printf("1~100以内的偶数和是%d\n", sum);return 0;
}
运行结果:1~100 以内的偶数和是 2550。
2. for 循环
原则:for 循环能实现的,while 循环也可以实现,for 循环胜在结构清晰,非常适合于直到循环次数的循环。
- 语法
for (【1】循环变量; 【2】循环条件; 【4】更新循环变量)
{【3】循环语句;
}
说明
() 中可以仅保留两个;;,此时这种写法就是死循环的一种体现。
循环变量:需要赋初始值,循环变量可以是单个,也可以是列表,多个循环变量之间使用逗号分隔。
循环条件:用来限制循环的次数,循环条件支持任意表达式(常用的有关系表达式,逻辑表达式)。
更新循环变量:支持列表,列表使用逗号分隔,这里可以使用赋值表达式。
执行顺序:①②③④ → ②③④ → ②③④ → ... → ②。
- 案例:计算 1~100 以内的偶数和
#include <stdio.h>
/*使用for实现(推荐)
*/
int for_test2()
{int sum = 0;// 循环条件for (int i = 2; i <= 100; i++){// 循环语句if (i % 2 == 0) sum += i;}// 打印输出printf("1~100以内的偶数和是%d\n", sum);return 0;
}
int main(int argc, char *argv[])
{for_test2();return 0;
}
- 案例:用户通过键盘输入一个整数 n,求 n 的阶乘
#include <stdio.h>
// 数学库对应的头文件
#include <math.h>int main(int argc, char *argv[])
{// 创建一个变量,用来存储计算数unsigned long n;// 创建一个变量,用来存储乘积 size_t 是C语言中 unsigned long的别名size_t r = 1;// 通过控制台,给n赋值printf("请输入一个整数:\n");scanf("%lu", &n);// 通过for循环计算for (int i = 1; i <= fabs(n); i++) r *= i;printf("1~%lu的乘积结果是%lu\n", (size_t)fabs(n), r);return 0;
}
注意:阶乘计算,如果乘积超过变量存储的范围,会溢出,结果计算可能不准确。
- for 实现死循环的方式
for(表达式1;;表达式3) {..}for(表达式1;;) {..}for(;;表达式3) {..}for(;;) {}for(表达式1;表达式2;) {}
(三)直到型循环的实现
特点:先执行,后判断,不管条件是否满足,至少执行一次。代表:do..while。
do..while 循环
- 语法
【1】循环变量;
do
{
【2】循环体语句;
【3】更新循环变量;
} while(【4】循环条件);
说明
- 循环条件的返回值必须是逻辑值(0 和非 0(计算机返回 1))。
- {} 包起来的内容称之为循环体。
- 要在循环体中控制循环条件的变化,否则会产生死循环。
- 案例:求 1~100 以内的偶数和
#include <stdio.h>int main(int argc, char *argv[])
{// 创建一个变量,用来存储偶数和sum = 0int sum = 0;// 创建一个循环变量,i = 2int i = 2;// 创建一个do..while循环,在循环体中,校验 i % 2 == 0,如果满足,就实现偶数和计算 sum += ido{if (i % 2 == 0) sum += i;// 计算完成,在do..while循环体的末行,更新循环变量,使其逼近出口i++;} while (i <= 100);// 限制性循环的出口:i <= 100(i > 100,循环结束)// 循环结束,打印输出sum的值printf("1~100以内的偶数和是%d\n", sum);return 0;
}
- 案例:用 C 语言编写简单猜数字游戏代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>int main(int argc, char *argv[])
{// 创建变量number(随机数),guess(用户猜测的数字),count(计数)int number, guess, count = 0;// 设置随机种子srand(time(NULL));number = rand() % 10 + 1;// 设计头printf("----------------------\n");printf("| 猜数字小游戏v1.0 |\n");printf("----------------------\n\n");printf("我已经想了一个1~10之间的整数,你猜猜是多少?\n");// 猜数字,猜不对,就一直猜,猜到对为止do{printf("请输入你的猜测:\n");// 接收scanf的返回值int result = scanf("%d", &guess);if (result != 1){while (getchar() != '\n'); // getchar() 类似于scanf("%c",c);printf("请输入数字!\n");continue; // 这次循环,跳过不算}// 计算count++;// 校验if (guess > number) printf("太大了,再猜一次!\n");else if (guess < number) printf("太小了,再猜一次!\n");else{printf("恭喜你,猜对了!\n");printf("你一共猜了%d次!\n", count);}} while (guess != number); // 等价于 guess > number || guess < numberreturn 0;
}
(四)goto 语句(了解)
语法:goto 标签 (label),标签是标明目标代码的位置,是一个不加 "" 的字符串。
注意事项
- 可读性:goto 语句会破坏代码的结构和可读性,使得代码难以理解和维护。因此,应尽量避免使用。
- 替代方案:大多数情况下,可以使用循环、条件语句、函数等结构来替代 goto 语句,使代码更加清晰和易于管理。
- 嵌套限制:虽然 goto 语句可以跨函数跳转(即跳转到另一个函数中的标签),但这种用法是不合法的,并且会导致编译错误。goto 语句只能在同一函数内部跳转。
- 错误处理:在某些情况下,goto 语句可以用于错误处理,例如从嵌套的多层循环中跳出。但即使在这种情况下,也应谨慎使用,并考虑是否有更好的替代方案。
总结:虽然 goto 语句在 C 语言中是合法的,并且有时可能看起来很方便,但过度使用或不当使用会导致代码质量下降。因此,建议尽量避免使用 goto 语句,而是采用更结构化和可维护的编程方法。
(五)循环的嵌套
定义:3 种循环(while、for、do..while)可以相互嵌套,在前一个循环结构中又嵌套一个循环结构。
案例:九九乘法表
#include <stdio.h>int main(int argc, char *argv[])
{printf("--- 九九乘法表 ---\n");// 外层循环:生成行,1~9for (int i = 1; i <= 9; i++){// 内层循环:生成列,1~(j <= i)for (int j = 1; j <= i; j++){// 生成算式printf("%dx%d=%d\t", j, i, j*i);// printf("*"); // 替换成这行代码,输出下直角三角形}// 每一行所有列生成完毕,一定要换行printf("\n");}printf("\n");return 0;
}
(六)循环结构的典型应用场景
- 求累和:如 1+2+3..+100 的和,sum = 0。
- 求累积:如 123..*100 的积,result = 1。
- 求均值:如 (1+2+3...+100)/100 的值。
- 求极值:如 12,34,56,67 中的最大值、最小值。
- 元素遍历:常用于数组元素的遍历。
(七)基础算法模型
累和
- 定义一个变量(sum),并赋初值为 0。
- 该变量累加(+=)每一个数据项(i)。
- 当访问完每一个数据项,此时该变量的取值就是累加和的结果。
累乘
- 定义一个变量,并赋初值为 1。
- 用该变量累乘(*=)每一个数据项。
- 当访问完每一个数据项,此时该变量的取值就是累乘的结果。
极值(多应用于数组)
- 定义一个变量,并赋初值为第一个数据项。
- 从第二个数据项开始,依次于该变量进行比较,如果大于 / 小于该变量,则将当前数据项的数据赋值给该变量。
- 当访问完每一个数据项,此时该变量的取值就是求极值的结果。