第三章 循环与控制流程

第三章 分支控制流程简介

为了能写一个完整一些的程序,需要先学一些分支控制流
文章头可下载笔记

3.1 前导程序

#include <stdio.h>

int main()
{
    int a;
    // 判断语句 判断 scanf() 的返回值 是否 等于 1
    // 如果scanf() 的返回值等于1 表示成功读取到a的值了
    if (scanf("%d", &a) == 1){
        printf("读取到a的值为 %03d \n", a);
    }else {
        printf("读取出错,未能读取到 a 的值\n");
    }
}

3.2 关系运算符

运算符作用
==比较左右两个数是否 相等
<比较左边的数是否 小于 右边的数
>比较左边的数是否 大于 右边的数
<=比较左边的数是否 小于等于 右边的数
>=比较左边的数是否 大于等于 右边的数

3.3 if 语句

3.3.1 if 语法
// expr 意思是  表达式语句  stat是一条语句(语句还包括 复合语句)
if ( expression )
    statement 

if意为如果,表判断,如上面的语句:

// 如果 scanf() 的返回值 等于 1
if (scanf("%d", &a) == 1)

如果 成功读入了一个整数赋给了 a ,那么 scanf() 返回值就是1 ,此时

1 == 1

是对的,用专业术语表达就是 此时 scanf(“%d”, &a) == 1 这个表达式的结果是 true(结果为真);

如果用户输入了 c 等非整数的字符,那么 scanf(“%d”, &a) 的返回值就是0,此时就说 scanf(“%d”, &a) ==1 是 false (结果为假)

不管是 true/false 还是 结果为 真/假 都是可以描述 关系表达式的

注:关于 true / false 这样的值在 C 语言中是由 1/0 表示的。1表示true(真),0表示false(假)

接下来看 if 后面的语句:

​ if 后面可以是一条表达式语句,也可以是一条复合语句(复合语句就是 由花括号{} ,在花括号里面可以有很多条 语句,复合语句不需要在右花括号后面加一个分号 ’ ; ’ )

只有当 if () 括号里的 关系表达式为真 时,才会执行紧跟在 if 后面的 语句(statement)

如:

if (scanf("%d", &a) == 1)
    printf("%d\n", a);
// 或
if (scanf("%d", &a) == 1)
{
    printf("%d\n", a);
}

以上两种写法是一样的

注:if 语句是一种选择语句,在 C 中有 6 种语句。分别是:标号语句,复合语句(上面有说到),表达式语句(比如:if里的条件表达式语句),选择语句(if语句),迭代语句,跳转语句(见过,比如:main函数中的 return 0; 语句)。

对于上面的 6 种语句我在后面会慢慢一一介绍清楚的,不必急,现在只需记住 if 语法需要使用两个语句

关于语句还有两个值得注意的点:

  • int a; 这样的句子不是一条语句,这在学后面的 选择语句 时将会证明,不过现在也可以做一个简单的证明

    // 刚说到 在if 关系表达式 括号之后 需要使用一条语句
    // 1 是 真
    if (1)
        int a; // 声明定义一个变量 a
    

    把这两行代码放到 main 函数中,进行编译,编译器会提示 在int之前预期一条表达式(语句)

    这就已经能够初步验证了 声明定义变量 的句子不是一条语句

  • 空语句

    空语句 由 一个 ’ ; ’ 分号构成,如:

    // 	C中 0 表示 假值false
    if (0)
        ;// 只有一个分号,表示一个空语句
    	printf("空语句\n");
    // 或
    if (0) ;
    	printf("空语句\n");
    

    把这两个形式的代码任意测试一条,都会发现即使 if 括号里面的 值为假; 也依然会执行printf() 函数的句子

    这足以证明 一个分号 是一条语句

    需要注意的是,空语句是C语言中一条特殊的语句,它不属于以上的任何一种语句

3.3.2 if - else

​ else 是搭配 if 语句使用的一种语句,意为 否则

​ 它会自动匹配 相距 最近的一条 if 语句

​ 下面是 else 的语法

// else 需要搭配 if 语句使用
if (expression)
    statement
else
	statement

看前导程序的例子:

else {
        printf("读取出错,未能读取到 a 的值\n");
}

意思表示,如果 if 括号里的 关系表达式值为假时,执行 else 后面的语句

不知道读者有没有注意到 else 后面 需要使用一条语句 ,是不是说 可以在 else 后面跟上上面提到的 六种语句 与特殊的 空语句 呢?

事实上,除了标号语句外,其他的语句都可以跟在else后面(但是有一些语句的使用有一定的限制,所以不能无脑跟除标号语句外的任何语句,实际上也不会无脑跟),这意味着 可以在else 后面接一条 选择语句,以形成嵌套选择语句

嵌套是字面意思,至于如何进行嵌套 笔者已经说清楚了,只需在 else 后面在接一条 if 选择语句,这个嵌套的例子笔者就不给了,就由读者来完成吧。对于嵌套的内容,笔者将在后面的章节中,更加深入的解释它。因此读者现在还是少些使用嵌套吧

注意:虽然 else 是一条语句,但是它需要与 if 搭配,就是说 else 不能成为 if 后面的语句,因此,在 if 与 else 之间一定要有一条语句,哪怕是一条空语句。


3.4 switch 语句

switch 也是一种选择分支语句

3.4.1 switch 语法

看格式:

switch ( 整型表达式 )
{
    case 整型常量1:
        代码块 // 可选
    case 整型常量2:
        代码块
    default:// 可选
        代码块
}

整形表达式的意思大概可为,最后求值为整型的表达式,这里不要求是一个常量,我们可以如下:

int a = 0;
switch (a)
{
    case 0:
        代码块0
    case 1:
        代码块1
    default:
        代码块3
}

不过需要注意的是,case 后面 必须是整型常量,你不能使用 浮点数常量去代替,这时非法的行为(这里指的非法是指不符合甚至是违反 C语言语法规则的意思)

在 case 后面跟着 代码块,代码块的是 由多条代码组成的,最小的代码块只有一条语句,(有时 由花括号{} 括起来的 复合语句 我们也会称为代码块,事实上我们只会把 花括号括起来的 代码 称为代码块),不过在这里的代码块加不加花括号都可以

当a的值 与某个 case 后面的整型常量 相等 时,将会执行其后面的语句,比如上述例子,a为0,则 执行代码块0

default 意思是默认,也就是说 当 a 的值 不等于 任何case 后面的整型常量时,就会执行default 默认 的语句

像 case 和 default 我们都称其为 分支 也可称为 标签 。分支针对的是选择结构,标签针对的是 switch语句

注意:case 后面出现的整型常量只能出现一次!不能出现两个标签值一样的情况

接下来请做一个练习:

要求1:读取用户的一个整型输入,如果输入不是整型,输出错误信息并结束程序

要求2:自己为这个整型输入一个意义(比如是奥运会跳水裁判的评分),接着使用 switch 语句判断 a 的值,只需要写出 2个case ,一个 default 三个分支

要求3:为每个分支 后面接一条 printf 语句,每一条都要输出不同的内容 (只要能辨别执行了哪一个分支即可)

要求4:至少测试3次程序,并且从 default 分支往上测试,看看每次的测试有什么不一样 (比如上面的例子,我第一次给 a 一个2,它将执行default后面的语句,然后再给a 一个 1,然后它执行 case 1: 分支后面的语句)

注意:练习会影响到后面的知识点的展开,请务必敲代码做练习,代码写得慢也没关系!

3.4.2 switch - 运作原理

上面的练习做得如何?是否会感受到编码的乐趣?测试又做得怎么样了?是否发现有什么不妥得地方?

各位可能注意到了,当 输入的整数值是 两个case 分支时,得到的 输出好像不止一句?这是为何?

想要知道这些问题的答案我们需要了解 switch 的运作原理:

  1. 第一步是对 switch () 括号里的表达式进行求值
  2. 第二步是逐个对比 case 后面的 整型常量,找到相等的那个
  3. 第三步如果有对应的case 或 defalut 则跳转到对应的 case 或 default 位置,然后才能执行后面的代码,否则将会结束 switch 语句的执行

想必读者在看到 第三步时已经看出一点端倪了,没错,问题就出在这里,因为在switch 后面紧跟着的 由花括号括起来的代码块中,case 语句 与 default: 语句都属于 switch 的标签,而且这个标签只限制在switch空间中,并且只能由switch跳转,且只会跳转一次

也就是说 不管是 case 还是 default: 都是供给switch 来跳转使用的标签,它们只是告诉switch语句,如果 switch括号里 整型表达式的值 能在 case 找到的话,就 跳转到该 case 标签的位置去执行代码,而不是 由switch 去对比每个case 的值,并且在执行对应的代码块后遇到下一条 case 标签 或 default 标签时,又接着对比 与case 的值

小小总结一下:首先switch 由整形表达式 与 后面的代码块组成,开始时 switch 对 整型表达式 进行求值,然后对比 它与case标签后的值(实际上编译器会用比直接对比值还要高效的方式在 case 中查找 整型表达式的值),如果有对应的值则跳转到该标签位置 执行一切可到达的代码,如果没有则跳到 default 标签(如果有default标签),否则就执行 switch 之后的代码

读者在读到什么叫 执行一切可到达的代码 ,意思是 程序在逻辑上可以运行到的地方,比如:

if (1)
    printf("逻辑上  程序可运行到");
else
    printf("逻辑上  程序永远运行不到这里");

因为 if 中的 关系表达式的值 永远为 真(true),其后的printf() 就会 一直可以运行到,而在 与其搭配使用的 else后的 printf() 表达式语句在代码逻辑上永远也不会执行

因此可以有下代码:

int a;
scanf("%d", &a);
switch (a)
{
    case 1:
        printf("a=%d\n", a);
        if (a > 2){
    case 2:
        	printf("a可能大于 2 ,也可能等于 2\n");
        }
}

我们把上面的代码放进 **主函数 main(也叫程序入口)**中,进行编译,发现编译器并未报错或有提示警告

接着运行它,发现,当我们 键入 1 (敲键盘输入 1, 就叫键入1)时,程序只有一行输出,且不会运行第二条 printf() 打印语句,因为此时,a==1,在执行第一条语句后,进行 if 语句中的判断 a>2 的 关系表达式 的值为 ,因此 case 2 标签后的 printf() 表达式语句在逻辑上是不可到达的,因此会跳过这一句

再次重新运行程序,这次我们键入 2 ,发现 会直接打印第二条 printf()表达式语句里面的字符,虽然 a>2 的关系表达式的值依然为假(因为 2等于2 ,而不大于 2),但是我们 的switch语句丝毫不在乎这件事,它只知道有一个 case标签 的值为2,于是它让程序直接 跳转 到case2 中继续执行代码,这与 if语句的关系表达式无关,因为根本就没有运行 if语句的关系表达式

初学者 与 学过部分C或其他语言的 读者可能会对 上面这样的代码结构感到新奇,因为 直接把 case标签 插入if语句的复合语句中可能是见所未见的

但是我们还是要清楚 switch的 本质概念,switch本质上就是 switch + 小括号与整型表达式 + 后面代码块, 即:

switch (/* 整型表达式 */)
{
        /* 代码块 */
}

然后再根据自己的需要在里面 插入 一些 case标签 或 default标签 ,然后当 整形表达式 求到的值与之有对应时,就跳转到对应的地方执行代码。根据需要插入……? 也就是说我们还可以有下面这样颠倒思维的代码:

switch (/* 任意整型表达式 */)
{
        /* 没有任何case标签 与 default标签 的代码块 */
}

对,即使我们写出上面这样令人费解的代码(不插入 case 为什么要使用switch 和 这段代码块),也能通过编译,只不过编译器会发出一个 提示警告:表示 代码块中的代码将永远都不会执行!。虽然编译器发出了警告,但是我们也可以选择忽略掉它们(然而在任何情况下都不要轻易胡罗编译器发出的警告,因为有时这些警告可能恰恰就是让我们程序崩溃的原因),继续运行程序,发现果然永远不会执行代码块里的代码

还可以有下面这样颠倒思维的代码:

switch (/* 任意整型表达式 */)
{
        /* 没有任何case标签 与 default标签 的代码块 */
}

对,即使我们写出上面这样令人费解的代码(不插入 case 为什么要使用switch 和 这段代码块),也能通过编译,只不过编译器会发出一个 提示警告:表示 代码块中的代码将永远都不会执行!。虽然编译器发出了警告,但是我们也可以选择忽略掉它们(然而在任何情况下都不要轻易胡罗编译器发出的警告,因为有时这些警告可能恰恰就是让我们程序崩溃的原因),继续运行程序,发现果然永远不会执行代码块里的代码

练习

自己搜文心一言,使用ai “目前我正在学习C语言,但是仅仅学了 printf() 与 sanf()函数、与if和switch、还有变量的定义,没有学运算符,请帮我出几道我能做的题给我做”
向 ai 表达以上的大概意思即可,然后自己练

总结

自己在做完练习后做一些总结,没必要一定要使用手写做笔记,效率太低了
可以使用一些 如 《有道云笔记》 这样的电脑软件工具
也可以自己学习一些 md 文件的语法来做笔记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值