5.C语言流程控制语句

流程控制语句

通过一些语句,控制程序执行的流程。主要包括条件语句、循环语句和跳转语句。

分类:

  1. 顺序结构:程序默认的执行顺序,从上到下依次执行。
  2. 选择结构(分支结构):根据条件选择执行不同的代码块。
  3. 循环结构:重复执行某段代码,直到满足终止条件。

1. 顺序结构

程序默认的执行顺序,从上到下依次执行。

c 复制代码
// 代码按从上到下的顺序执行
int a = 10;      // 第一步
int b = 20;      // 第二步
int sum = a + b; // 第三步
printf("%d", sum); // 第四步

2. 选择结构(分支结构)

根据条件选择执行不同的代码块。

2.1 if语句系列

  • 利用if语句对数据进行判断,从而执行不同的代码

2.1.1 单分支if

  • 使用场景: 某些代码,在满足条件的时候才执行
  • 格式:
c 复制代码
if (条件) {
    // 条件为真时执行的代码
}
  • 流程:
  • 代码
c 复制代码
#include <stdio.h>

int main ()
{
	// 判断变量age里记录的值,如果大于等于18,就打印"已成年"
	// 1. 定义变量
	int age = 20;
	// 2. 判断
	if (age >= 18) {
		printf("已成年\n"); // 已成年
	};
	return 0;
}
  • 注意:
  1. 在C语言中,如果判断的结果是一个数字,任何非0值都视为真,0视为假
c 复制代码
if (0) {
	printf("0为假,不执行哦");
};
  1. 如果语句块中只有一条语句,可以省略花括号{},但为了代码清晰和避免错误,建议始终使用花括号。
c 复制代码
int age = 19;
if (age >= 18)
		printf("已成年\n");

2.1.2 双分支if-else

  • 格式:
c 复制代码
if (条件) {
    // 条件为真时执行的代码
} else {
    // 条件为假时执行的代码
}
  • 流程:
  • 代码
c 复制代码
#include <stdio.h>

int main ()
{
	int score = 75;
	if (score >= 60) {
		printf("及格\n");
	} else {
		printf("不及格\n");
	}
	return 0;
}

2.1.3 多分支 else if

  • 说明:
    1. 从上往下一次进行判断
    2. 只要有一个判断(条件)成立,就执行对应的代码
    3. 如果所有判断都不成立,则执行else的代码
  • 格式:
c 复制代码
if (条件1) {
    // 条件1为真时执行的代码
} else if (条件2) {
    // 条件2为真时执行的代码
} else {
    // 以上条件都不满足时执行的代码
}
  • 流程:
  • 代码:对分数进行等级划分
c 复制代码
#include <stdio.h>

int main() {
    int score = 85;
    
    // 多条件判断
    if (score >= 90) {
        printf("优秀\n");
    } else if (score >= 80) {
        printf("良好\n");
    } else if (score >= 60) {
        printf("及格\n");
    } else {
        printf("不及格\n");
    }
    
    return 0;
}

嵌套if语句

  • 格式:
c 复制代码
if (条件1) {
    if (条件2) {
        if (条件3) {
            // 三层嵌套
        }
    }
}
  • 代码
c 复制代码
#include <stdio.h>

int main() {
    int score = 85;
    
    if (score >= 0 && score <= 100) {
		 if (score >= 90) {
	        printf("优秀\n");
	    } else if (score >= 80) {
	        printf("良好\n");
	    } else if (score >= 60) {
	        printf("及格\n");
	    } else {
	        printf("不及格\n");
	    }
	} else {
		printf("分数超出范围\n");
	}
    
    return 0;
}

2.2 switch语句

  • 用于多分支选择,注意每个case后通常要加break,否则会继续执行下一个case。

  • 作用: 把所有的选择一一列举出来,根据不同的条件任选其一。

  • 执行流程:

    1. 首先计算表达式的值
    2. 依次和case后面的值进行比较,如果有对应的值,就会执行相应的代码,在执行的过程中,遇到break就会结束
    3. 如果所以的case后面的值和表达式都不匹配,就会执行 default 里面的代码,然后结束整个switch语句
  • 格式:

c 复制代码
switch (表达式) {
    case 值1: // 拿表达式和值1做对比,两者相同就执行代码块1,两者不相同就跳过,表达式去下面的case后面的值做对比。
        // 代码块1
        break; // 退出循环
    case 值2: // 上面表达式与值1不相同才执行这里
        // 代码块2
        break;
    // 可以有多个case
    default:
        // 以上都不匹配时执行的代码
        break;
}
  • 细节说明:
    1. 表达式:计算结果只能为(字符/整数
    2. case:值只能是(字符/整数)的字面量,不能是变量
    3. case:不允许重复
    4. break:表示中断,结束的意思,结束 switch 语句,不执行下面的内容
    5. default:所有情况都不匹配,执行该处内容
  • 流程图
  • 代码
c 复制代码
#include <stdio.h>

int main ()
{
	int week = 3;
	switch(week)
	{
		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;
		default:
			printf("没有这个星期\n");
			break;

	}
	return 0;
}
  • default
    1. default子句不是必须的,如果不需要处理默认情况,可以省略。
    2. default子句可以出现在switch语句中的任何位置(开头、中间或结尾),但通常放在最后。
    3. 如果default不在最后,且没有break语句,则会继续执行后面的case或default,直到遇到break或switch结束。

代码:省略default子句,如果没有default且没有匹配的case,则跳过整个switch

c 复制代码
switch (num) {
    case 1:
        printf("一");
        break;
    case 2:
        printf("二");
        break;
    // 没有default,如果num不是1或2,什么都不做
}

代码:default子句放在前面

c 复制代码
switch (num) {
    default:  // 放在开头
        printf("其他");
        break;
    case 1:
        printf("一");
        break;
    case 2:
        printf("二");
        break;
}
  • case 穿透
    1. 首先还是根据小括号中表达式的结果去匹配对应的case
    2. 执行对应case里面的代码
    3. 如果执行过程中,遇到break,那么直接结束整个switch
      但是如果没遇到break,就会继续执行下面的case中的代码
      知道遇到break,或者把switch中所有的代码全部执行完了,才会结束
    4. case穿透只会往下,不会回到上面,执行上面的代码
      代码
    5. 多个case共享同一个代码块。
c 复制代码
#include <stdio.h>

int main ()
{
	int num = 1;
	switch(num)
	{
		case 1: // num 匹配到数字 1,执行代码
			printf("数字是1\n"); // 执行完,没有遇到break,继续执行下一个case的代码
		case 2:
			printf("数字是2\n"); // 执行代码
			break; // 遇到break,退出switch语句
		default:
			printf("数字是其他\n");
			break;
		
	}
	return 0;
}

执行结果:

代码:输出对应月份的季节(多个case共享同一个代码块)

c 复制代码
#include <stdio.h>

int main ()
{
	// 1. 键盘录入月份
	int month;
	printf("请输入月份\n");
	scanf("%d", &month);
	// 2. 输出对应月份的季节
	switch (month)
	{
		case 1:
		case 2:
		case 12:
			printf("冬季\n"); // 1 2 12都执行这里
			break;
		case 3:
		case 4:
		case 5:
			printf("春季\n");
			break;
		case 6:
		case 7:
		case 8:
			printf("夏季\n");
			break;
		case 9:
		case 10:
		case 11:
			printf("秋季\n");
			break;
		default:
			printf("输入月份错误\n");
			break;
	}

	return 0;
}

代码:穿透的高级用法

c 复制代码
// 根据权限级别执行累积操作
int permissions = 0;
int level = 3;

switch (level) {
    case 3:  // 最高权限
        permissions |= ADMIN_PERM;
        // 穿透,继续添加更多权限
    case 2:  // 中级权限
        permissions |= WRITE_PERM;
        // 穿透
    case 1:  // 基础权限
        permissions |= READ_PERM;
        break;
    default:
        permissions = NO_PERM;
        break;
}
// level=3时:permissions包含所有权限
// level=2时:permissions包含WRITE和READ
// level=1时:permissions只有READ

穿透特性是C语言switch语句的一个强大但危险的功能。正确使用可以提高代码简洁性,滥用则会导致难以调试的错误。

2.3 switch 和 if 的区别

特性 if语句 -- switch语句
条件类型 任意表达式,结果为0/非0 整型或字符型表达式
比较方式 关系运算、逻辑运算等 与常量值相等比较
多分支 使用else if 使用case标签
默认分支 else default
穿透 有(不加break会穿透)
可读性 条件复杂时较好 多常量比较时较好
效率 可能需要多次判断 通常使用跳转表,效率高

3. 循环结构

循环语句用于重复执行一段代码,直到满足终止条件。

  • 构成:开始条件,结束条件,控制开关,循环体语句
  • 循环结构包含:for 循环,while 循环,do...while 循环

3.1 for循环

  • 语法:
c 复制代码
for (初始化语句; 条件判断语句; 条件控制语句) {
    // 循环体语句
}
  • 代码:
c 复制代码
#include <stdio.h>

int main ()
{
	// 在VC编辑器中,初始化声明要放在上面。
	int i;

	// i = 1; : 初始化语句, 循环开始的条件。
	//			在循环开始前执行一次,通常用于初始化循环变量。
	// i <= 3; : 条件判断语句,循环结束的条件。
	// 			 每次循环开始前都会检查这个条件,如果为真(非0),则执行循环体;如果为假(0),则终止循环。
	// i++ :条件控制语句。控制循环的次数。
	//		每次循环体执行后执行,通常用于更新循环变量。
	// printf("吃西瓜的年年\n"); : 循环体语句,需要重复执行的语句。

	for(i = 1; i <= 3; i++)
	{
		printf("吃西瓜的年年\n");
	}
	return 0;
}
  • 执行流程:
    1. 执行初始化语句(只执行一次)
    2. 执行条件判断语句,如果为真,执行循环体;如果为假,跳出循环。
    3. 执行循环体
    4. 执行条件控制语句
    5. 回到2,直到条件表达式为假

以上面代码为例子

第一次循环:

第二次循环

第三次循环

第四次循环

我们发现进行循环的是后面这三段代码

  • 总结:
  1. 初始化语句只执行一次
  2. 判断语句成立,循环继续
  3. 判断语句不成立,循环结束
  • 练习
  1. 打印 5-1
c 复制代码
#include <stdio.h>

int main ()
{
	// 打印5-1
	// 技巧:
	// 1. 循环开始条件 i = 5
	// 2. 循环结束条件 i >= 1
	// 3. 重复执行的事情
	// 4. 每次循环结束之后,变量i如何改变 i--

	// 第一次循环 i = 5
	// 第二次循环 i = 4
	// 第三次循环 i = 3
	// 第四次循环 i = 2
	// 第五次循环 i = 1
	int i;
	for(i = 5; i >= 1; i--)
	{
		printf("%d\n", i);
	}

	return 0;
}
  1. 求和 1-5之间的和
c 复制代码
#include <stdio.h>

int main ()
{
	int i;
	// 定义一个变量用来累加数据
	int sum = 0;

	// 执行流程
	/*
		在循环中,获取1-5的每一个数
		第一次循环中:i = 1, sum = 0,循环体执行:sum = 0 + 1,sum = 1
		第二次循环中:i = 2, sum = 1,循环体执行:sum = 1 + 2,sum = 3
		第三次循环中:i = 3, sum = 3,循环体执行:sum = 3 + 3,sum = 6
		第四次循环中:i = 4, sum = 6,循环体执行:sum = 6 + 4,sum = 10
		第五次循环中:i = 5, sum = 10,循环体执行:sum = 10 + 5,sum = 15
		...
	*/
	for (i = 1; i <= 5; i++)
	{
		sum = sum + i;
	}
	printf("%d\n", sum); // 15

	return 0;
}

扩展知识:作用域:{}

在C语言中,一对花括号 {}定义了一个代码块,而一个代码块就是一个独立的作用域。

  • 在函数内部,{}内定义的变量(局部变量)其作用域从定义点开始,到所在代码块结束为止。
  • 不同代码块(即使是嵌套的)中可以定义同名变量,内层变量会暂时"遮蔽"外层变量。
  • 代码块通常用于控制语句(如 if, for, while)的函数体,或者单独使用以限定变量的生命周期。

生命周期:变量只在所属的大括号中有效

c 复制代码
#include <stdio.h>

int main ()
{
	if (1) {
		// 这里生命的 a 只在当前大括号内生效
		// {} 是一个作用域,在里面声明的变量只能在里面生效。
		// {} 里面代码运行结束后,就会把变量销毁,外面无法再获取里面的变量
		int a = 10;
		printf("%d\n", a); // 10
	}

	printf("%d\n", a); // 会报错
	return 0;
}

可获取外部的变量

c 复制代码
#include <stdio.h>

int main ()
{
	int b = 20;
	if (1) {
		int a = 10;
		printf("%d\n", a); // 10
		// 获取外部的变量能打印出来
		// 先看里面有么有变量b, 没有就会往作用域外部去寻找,找到了就拿来用
		printf("%d\n", b); // 20
	}
	printf("%d\n", a); // 会报错
	printf("%d\n", b); // 20
	return 0;
}
// main 函数 执行完才会把 变量b 销毁

变量遮蔽:内层作用域可以定义与外层同名的变量,此时内层变量会暂时"覆盖"外层变量,退出内层作用域后,外层变量恢复可见。

c 复制代码
#include <stdio.h>

int main ()
{
	// main 函数 声明了一个 变量 a
	int a = 20;
	if (1) {
		// if 语句声明了一个 变量 a
		// 这里的 a 覆盖外面的变量 a,
		// 或者说 虽然名字相同,但存储是两个地方,所以这只是名字相同的两个变量
		// if 语句里开辟的作用域(空间),读取的是里面的变量,既然读取到里面的变量,就不会往外层去寻找
		// 如果里面读取不到变量才会去外层找;
		int a = 10;
		printf("%d\n", a); // 10
	}
	// 外部作用域无法读取 if 里面的,因为 if 执行完,里面的变量已经销毁
	// 所以它读取的是  main 函数 声明变量 a
	printf("%d\n", a); // 20
	return 0;
}

所以,上面代码的 sum 可以被循环用来累计。它不会被销毁。如果写在for循环里,那么循环一次就会被销毁一次,无法用来累计。

c 复制代码
#include <stdio.h>

int main ()
{
	int i;
	
	// 执行流程
	/*
		在循环中,获取1-5的每一个数
		第一次循环中:i = 1, sum = 0,循环体执行:sum = 0 + 1,sum = 1
					当第一次循环后,变量 sum 就会从程序消失
		第二次循环中:i = 2, sum = 0,循环体执行:sum = 0 + 2,sum = 2
					当第一次循环后,变量 sum 就会从程序消失
		...
	*/
	for (i = 1; i <= 5; i++)
	{
		// 定义一个变量用来累加数据,然后你会发现定义在for循环里面累加不了
		int sum = 0;
		sum = sum + i;
	}
	printf("%d\n", sum); // 报错,没有 sum 这个变量

	return 0;
}
  1. 键盘录入两个数,算出他们即能被6整除又能被8整除的个数
c 复制代码
#include <stdio.h>

int main24 ()
{
  // 循环的变量
	int i;
	// 定义用来统计的个数的变量
	int quantity = 0;
	// 键盘录入的两个数字
	int num1;
	int num2;

	// 最大值和最小值的变量声明
	int max;
	int min;

	printf("请输入两位整数:");
	scanf("%d %d", &num1, &num2);

	// 比较两个值的大小
	min = num1 < num2 ? num1 : num2; // 哪个小取哪个
	max = num1 > num2 ? num1 : num2; // 哪个大取哪个

	// 变量范围中的每一个数字
	for (i = min; i <= max; i++)
	{
		// 判断是否能被6整除,和被8整除。用取余的方式,余数为0则能被整除
		if (i % 6 == 0 && i % 8 == 0) {
			// 符合要求在,则 quantity + 1
			quantity++;
		}
		
	}
	printf("既能被6整除,又能被8整除的个数有:%d个\n", quantity); // 4

	return 0;
}

3.2 while循环

先判断条件,条件为真则执行循环体。

  • 语法:
c 复制代码
初始化语句
while (条件判断语句 / 循环条件) {
    // 循环体
    // 条件控制语句
}
  • 代码:
c 复制代码
#include <stdio.h>

int main ()
{
	// 初始化语句
	int i = 1;
	while (i <= 3) // i <= 3: 条件判断语句,符合条件才执行循环体
	{
		printf("吃西瓜的年年\n"); // 循环体:要执行的代码
		i++; // 条件控制语句,避免无限循环(无限循环后面会讲到)
	}

	return 0;
}
  • 执行流程:和for循环一样,只是写法不一样
  • 练习
  1. 求某个数是否为2的幂次方,是打印 yes,不是打印 no
c 复制代码
#include <stdio.h>

int main ()
{
	// 1.求是否为2的幂次方
	/*
		规律:
		2的0次方 1
		2的1次方 2
		2的2次方 4
		2的3次方 8
		2的4次方 16
		2的5次方 32
		2的6次方 64

		* 任意一个数字不断除以2,最终结果都会等于 1

		循环结束的条件
		1. 结束是1的时候,就可以结束,yes
		2. 结果无法被2整除了,就可以结束,no
	*/

	int num = 100;

	// 用 while 来循环,不断除以2
	// 小括号里的为 继续执行的条件,即继续循环的条件
	// 能被整除 num % 2 == 0,且这个数要大于 1。
	// 如果这个数等于1,那就满足2的0次方。
	// "2的幂次方"通常指的是2的非负整数次幂,即正整数,所以要 > 1。
	while (num > 1 && num % 2 == 0)
	{
		// 不断除以2并赋值
		num = num / 2;
	}

	// 判断,最终数字为1,则是2的幂次方
	if (num == 1) {
		printf("yes\n");
	} else {
		printf("no\n");
	}

	return 0;
}
  1. 世界最高山峰是珠穆朗玛峰(8844.43米=8844430毫米),假如我有一张足够大的纸,它的厚度是0.1毫米。我折叠多少次,可以折成珠穆朗峰的高度?
c 复制代码
#include <stdio.h>

int main ()
{
	// 声明珠穆朗峰高度和纸张的厚度
	int height = 8844430;
	double paper = 0.1;

	// 计算折叠次数
	int count = 0;

	// 继续循环的条件:当paper的高度没有穆朗峰高度高时
	while(paper < height)
	{
		// 折叠一次,纸张厚度乘以2
		paper = paper * 2; // 或写成 paper *= 2
		// 折叠次数 + 1
		count++;
	}

	// 打印
	printf("%d\n", count); // 27

	return 0;
}
  1. 将一个整数进行反转,如:将 123 ----> 321
c 复制代码
#include <stdio.h>

int main ()
{
	// 3. 整数反转
	/*
		思路:依次获取每一位数,再拼接起来

		1. 从右边开始依次获取每一个数 可以用取余,如: 123
			第一次获取:123 % 10 = 3 (等于 12 余 3)
			第一次获取:12 % 10 = 2 (等于 1 余 2)
			第一次获取:1 % 10 = 1 (等于 0 余160 1)

		2. 再把这三个数拼接起来
			定义变量 int reverse = 0 用来拼接,公式:reverse = reverse * 10 加上获取的余数
			第一次拼接 reverse = reverse(0) * 10 + 3 // 3
			第二次拼接 reverse = reverse(3) * 10 + 2 =  // 32
			第二次拼接 reverse = reverse(32) * 10 + 1 =  // 321
	*/

	int number = 123456;
	int reverse = 0;

	// 循环条件:number 不等于 0,就是还没除到最后
	while (number != 0)
	{
		// 取余,取出最右边的数
		int temp = number % 10;
		// 去掉刚刚获取的数字
		number = number / 10;
		// 把余数拼接到reverse中
		reverse =reverse * 10 + temp;
	}

	printf("%d\n", reverse); // 654321

	return 0;
}

3.3 while 和 for 的对比

相同点:运行规则都一样

不同点:

  1. 写法不一样
  2. 使用场景:
    • for循环:通常用于已知循环次数的情况,例如遍历数组或固定次数的迭代。由于初始化、条件和更新集中,代码可读性更高。
    • while循环:更适合循环次数未知或依赖动态条件的情况,例如读取输入直到特定值出现。它更灵活,但需要额外管理循环变量。

3.4 do-while循环

先执行一次循环体,然后判断条件,条件为真则继续循环。

c 复制代码
初始化语句
do {
    // 循环体
    // 至少执行一次
} while (循环条件);
  • 流程
c 复制代码
#include <stdio.h>

int main ()
{
	// 打印 1- 5
	int i = 1;
	do
	{
		// 先执行
		printf("%d\n", i);
		i++;
	} while(i <= 5); // 再判断

	return 0;
}

这个很少用,知道有这个东西就可。

4. 跳转语句

  • 跳转语句用于改变程序的正常执行流程。
  • 再循环的过程中,跳转到其他语句上执行

4.1 break 语句

  • 不能单独写,只能写在循环或switch语句中,表示结束,跳出当前循环或switch。

  • 就是循环到某个条件时,不需要后面的循环,就用 break 直接结束循环

  • 代码:在数字1-100中,找出第一个既能够被3整除,又能被5整除的数字

c 复制代码
int main ()
{
	int i;
	for (i = 1; i<= 100; i++)
	{
		if (i % 3 == 0 && i % 5 == 0) {
			printf("%d\n", i); // 15
			// 找到后退出循环,不再循环,执行for循环下面的代码
			break;
		}
	}
	return 0;
}

4.2 continue 语句

  • 用于跳过当前循环的剩余代码,直接进行下一次循环的条件判断(在while和do-while中)或更新表达式(在for循环中)。

  • 结束本循环,继续下次循环

  • 代码:打印数字1-5,遇到3不打印

c 复制代码
#include <stdio.h>

int main ()
{
	int i;
	for (i = 1; i<= 5; i++)
	{
		if (i == 3) {
			// 不执行下面打印代码(跳过本次循环),继续下一次循环
			continue;
		}
		printf("%d\n", i);
	}
	return 0;
}

4.3 return 语句

用于从函数中返回,可以携带返回值(如果函数返回类型非void)。等学到函数再详解

5. 循环进阶

5.1 无限循环

  • 在C语言中,无限循环通常用于需要一直运行直到满足特定条件(如用户输入、信号触发等)才退出的情况。
  • 退出无限循环:关闭控制台 或 CTRL + C

while无限循环

c 复制代码
// 循环条件 1 代表 true,会一直有效,不可省略
while(1) {
    // 循环体
    printf("吃西瓜的年年\n");
}

for无限循环

c 复制代码
for(;;) {
    // 循环体
    printf("吃西瓜的年年\n");
}

do-while无限循环

c 复制代码
do {
    // 循环体
    printf("吃西瓜的年年\n");
} while(1);
  • 无限循环因为永远停不下来,所以下面不能再写其他代码
c 复制代码
for(;;) {
    // 循环体
    printf("吃西瓜的年年\n"); 
}
printf("这一句打印不出来,因为上面在无限循环\n"); 

break 跳出无限循环

  • 在无限循环中,通常需要在循环体内设置跳出循环的条件,否则程序将永远执行下去。例如,可以使用break语句在满足某个条件时跳出循环。
c 复制代码
#include <stdio.h>

int main() {
    char ch;
    while(1) {
        printf("请输入一个字符(输入'q'退出):");
        scanf(" %c", &ch);
        if(ch == 'q') {
            break;
        }
        printf("你输入了:%c\n", ch);
    }
    return 0;
}

运行结果:

总结:

  • 最常用:while(1)和 for(;😉
  • 一定要有退出机制,否则程序无法正常终止
  • 实际应用:无限循环常用于服务器、游戏主循环、事件监听等场景

5.2 嵌套循环

  • 在C语言中,嵌套循环是指在一个循环体内包含另一个循环。
  • 嵌套循环的执行顺序是:外层循环每执行一次,内层循环会完整地执行一遍。
  • 语法:
c 复制代码
for (外层初始化; 外层条件判断; 外层更新) {
    for (内层初始化; 内层条件判断; 内层更新) {
        // 循环体
    }
}
  • 代码
  1. 打印三行五列的*,效果如下:
    *****
    *****
    *****
c 复制代码
#include <stdio.h>

int main ()
{
	// 我们先来看看一行 * 怎么打印
	// 是这样吗
	// printf("*****\n");
	// 难道,莫非你是个天才?
	// 但我们想要灵活点,可以用for循环来打印

	int i;

	for (i = 1; i <= 5; i++)
	{
		printf("*");
	}
	printf("\n");

	return 0;
}

打印结果:

那么我们要打印三行,就只需把上面的代码循环三次就可以

c 复制代码
int j;

	for (j = 1; j <= 3; j++) {
		// 放入上面代码
	}

完整代码

c 复制代码
#include <stdio.h>

int main ()
{
	// for嵌套循环
	// 先确定内循环做了什么
	// 外循环就是把里面的代码重复了几次
	int i;
	int j;

	// 外循环
	for (j = 1; j <= 3; j++) {
		// 内循环
		for (i = 1; i <= 5; i++) {
			printf("*");
		}
		printf("\n");
	}
	
	return 0;
}

很好,完美结束!让我们来看下一题。

  1. 打印两个5行5列的三角形,效果如下:
    *****
    ****
    ***
    **
    *


    *
    **
    ***
    ****
    *****

先学习第一个三角形。

c 复制代码
#include <stdio.h>

int main ()
{
	int i;
	int j;

	// 1.先打印出矩形
	int i;
	int j;

	for (j = 1; j <= 5; j++) {
		for (i = 1; i <= 5; i++) {
			printf("*");
		}
		printf("\n");
	}

	return 0;
}

当我们打印矩形,下一步我们就要给每一行递减一个 *,决定每一行打印多少个的是在内循环,请看内循环

c 复制代码
#include <stdio.h>

int main ()
{
	// 1.先打印出矩形
	int i;
	int j;

	// 内循环代码解析
	// i = 1:打印第一行的*;内循环初始值:1,循环条件判断:5,5个*
	// i = 2:打印第二行的*;内循环初始值:2,循环条件判断:5,4个*
	// i = 3:打印第三行的*;内循环初始值:3,循环条件判断:5,3个*
	// i = 4:打印第四行的*;内循环初始值:4,循环条件判断:5,2个*
	// ...

	for (j = 1; j <= 5; j++) {
		// 决定了每一行打印多少个* 
		// 5 4 3 2 1
		// 内循环初始化的值 = j
		for (i = j; i <= 5; i++) {
			printf("*");
		}
		printf("\n");
	}

	return 0;
}

学习第二个三角形,同样先打印矩形,再看看详解

c 复制代码
#include <stdio.h>

int main ()
{
	// 1.先打印出矩形
	int i;
	int j;

	// 内循环代码解析
	// i = 1:打印第一行的*;内循环初始值:1,循环条件判断:1,1个*
	// i = 2:打印第二行的*;内循环初始值:1,循环条件判断:2,2个*
	// i = 3:打印第三行的*;内循环初始值:1,循环条件判断:3,3个*
	// i = 4:打印第四行的*;内循环初始值:1,循环条件判断:4,4个*
	// ...

	for (j = 1; j <= 5; j++) {
		// 决定了每一行打印多少个* 
		// 1 2 3 4 5
		// 改变条件判断,递增
		for (i = 1; i <= j; i++) {
			printf("*");
		}
		printf("\n");
	}

	return 0;
}
  1. 打印九九乘法表

用上面的 * 的循环来进行改造。我们把它改成九行

c 复制代码
#include <stdio.h>

int main ()
{
	int i;
	int j;
	// 循环条件改成 9
	for (j = 1; j <= 9; j++) {
		for (i = 1; i <= j; i++) {
			printf("*");
		}
		printf("\n");
	}

	return 0;
}

目前已经实现了样式,现在就来看看内容。我们不再打印 * 了,要打印数字。

我们要打印的数字都是 1-9,我们发现, i和 j 每次循环也是1 -9 ,我们把他们拿来试试填进去看看

c 复制代码
#include <stdio.h>

int main ()
{
	int i;
	int j;
	// 循环条件改成 9
	for (j = 1; j <= 9; j++) {
		for (i = 1; i <= j; i++) {
			// 这里改成我们要打印的乘法
			printf("%d * %d = %d ", j, i, i * j);
		}
		printf("\n");
	}

	return 0;
}

看看效果

看起来 i 和 j 的位置不对,我们把他们换一下位置就好

c 复制代码
#include <stdio.h>

int main ()
{
	int i;
	int j;
	// 循环条件改成 9
	for (j = 1; j <= 9; j++) {
		for (i = 1; i <= j; i++) {
			// 把这里 j 和 i位置换一下
			printf("%d * %d = %d ", i, j, i * j);
		}
		printf("\n");
	}

	return 0;
}

再次打印

好像没啥问题,但有些地方对不起,看着不大舒服。

我们换成 \t 制表符(Tab),让它的长度对齐变大

  • 原理:会根据前面字母的个数在后面补空格,让整体的长度达到8或者8的倍数,最少补1个,最多补8个
  • 作用:打印表格数据的时候,可以对齐
c 复制代码
#include <stdio.h>

int main ()
{
	int i;
	int j;
	// 循环条件改成 9
	for (j = 1; j <= 9; j++) {
		for (i = 1; i <= j; i++) {
			// 把最后面的空格换个 \t
			printf("%d * %d = %d\t", i, j, i * j);
		}
		printf("\n");
	}

	return 0;
}

5.3 goto 语句

  • 在C语言中,goto语句是一种无条件跳转语句,它允许程序跳转到同一函数内的任何位置。常用来跳出循环。
  • 过度使用goto语句会导致程序结构不清晰,难以理解和维护。
  • 现代编程中一般建议尽量避免使用goto语句,而是使用结构化的控制语句(如if、while、for等)来代替。
  • 语法:
c 复制代码
goto label;
...
label: statement;
  • 代码:
  1. 嵌套循环
c 复制代码
#include <stdio.h>

int main ()
{
	int i;
	int j;
	// 外循环
	for (i = 1; i <= 3; i++) {
		// 内循环
		for(j = 1; j <= 5; j++) {
			printf("内循环执行%d\n", j);
		}
		printf("内循环结束\n");
		printf("----------------\n");
	}

	printf("外循环结束\n");
	return 0;
}

我们在内循环使用 goto 来中止循环,看看会发生什么

c 复制代码
#include <stdio.h>

int main ()
{
	// 使用 goto 语句退出循环

	int i;
	int j;
	// 外循环
	for (i = 1; i <= 3; i++) {
		// 内循环
		for(j = 1; j <= 5; j++) {
			printf("内循环执行%d\n", j);
			// 循环完一次后就结束了
			goto a; // 跳转到 a 标签
		}
		printf("内循环结束\n");
		printf("----------------\n");
	}

	// 标签名定义
	a: printf("外循环结束\n");

	return 0;
}

这里直接跳出内外循环,再看看下面的,我们换个位置

c 复制代码
#include <stdio.h>

int main ()
{
	// 使用 goto 语句退出循环

	int i;
	int j;
	// 外循环
	for (i = 1; i <= 3; i++) {
		// 内循环
		for(j = 1; j <= 5; j++) {
			printf("内循环执行%d\n", j);
			goto a; // 跳转到 a 标签

		}
		// 标签名定义
		a: printf("内循环结束\n");
		printf("----------------\n");
	}

	
	printf("外循环结束\n");

	return 0;
}

这里只是跳出了内循环后面的内容,会把外循环执行完。

好,接下来看下内循环 break 是怎么跳转的

c 复制代码
#include <stdio.h>

int main ()
{
	int i;
	int j;
	// 外循环
	for (i = 1; i <= 3; i++) {
		// 内循环
		for(j = 1; j <= 5; j++) {
			printf("内循环执行%d\n", j);
			break;
		}
		printf("内循环结束\n");
		printf("----------------\n");
	}
	printf("外循环结束\n");

	return 0;
}

我们发现放在内循环的 break,它终止的也是内循环,无法终止外循环,外循环还是会继续运行,直到结束。

  1. 向前跳转制造循环,不推荐
c 复制代码
#include <stdio.h>

int main ()
{
	int i = 0;
	start:
	if (i < 10) {
		printf("%d ", i);
		i++;
		goto start;  // 应该用for/while循环
	}
	return 0;
}


使用建议:

  1. 限制使用范围:只在同一函数内使用
  2. 只向后跳转:避免向前跳转(loop标签除外)
  3. 用于错误处理:这是goto最有价值的用途
  4. 避免用于普通流程控制:用if/else、for/while等代替
  5. 添加清晰注释:说明为什么使用goto

6. 总结

注意事项:

  1. 条件语句中,条件表达式的结果应为整型(0为假,非0为真)。
  2. 在循环语句中,注意避免死循环。
  3. 使用break和continue时,注意它们只影响最内层的循环。
  4. goto语句虽然灵活,但会破坏程序的结构,应尽量避免使用。

分类对比表:

相关推荐
萧曵 丶2 小时前
Java 泛型详解
java·开发语言·泛型
码上宝藏2 小时前
从解耦到拓展:Clapper 0.10.0 插件化架构设计与 Lua 脚本集成
linux·开发语言·lua·视频播放器·clapper
qq_117179072 小时前
海康威视球机萤石云不在线问题解决方案
开发语言·智能路由器·php
superman超哥2 小时前
Rust 并发性能调优:线程、异步与无锁的深度优化
开发语言·后端·rust·线程·异步·无锁·rust并发性能
csbysj20202 小时前
Python 多线程
开发语言
superman超哥2 小时前
Rust Trait 对象与动态分发权衡:性能与灵活性的深度权衡
开发语言·后端·rust·rust trait·对象与动态发布·性能与灵活性
ftpeak2 小时前
Burn:纯 Rust 小 AI 引擎的嵌入式物体识别之旅(一步不踩坑)
开发语言·人工智能·rust
越努力^越幸运2 小时前
C中内存函数
c语言·开发语言
flysh052 小时前
C#和.NET简介
开发语言·c#·.net