C语言-分支与循环(1)-学习笔记

JonlyMay 2024-09-16 08:05:07 阅读 75

目录

1、if 语句

1.1 if

1.2 else

1.3 分支中包含多条语句

1.4 嵌套 if

1.5 悬空else问题(多个if和一个else对应关系)

2、switch语句

2.1 switch语句中的break

2.2 switch语句中的default

2.3 switch语句中的case和default的顺序问题

3、关系操作符

4、条件操作符

4.1 什么是条件操作符?

4.2 条件操作符的作用

5、逻辑操作符:!、&&、||

5.1逻辑 取反运算符 !

5.2 逻辑 与运算符 &&

5.3 逻辑 或运算符 ||

5.4 短路

5.5 短路求值


恭喜你发现了一篇超级实用的长文。如果你正在寻找具体的模块,可以先查看目录,找到自己需要的内容。在这里,你将会发现我们为你准备的各种有趣、有用的信息。快来一起探索吧!

注意:文中代码直接复制到vs可能会提醒无法识别,可以先复制到vs,然后删除重新复制一下。应该可以解决一部分问题。

正文开始:

C语言是结构化的程序设计语言,这里的结构指的是顺序结构、选择结构、循环结构,C语言是能够实现这三种结构的,其实我们如果仔细分析,我们日常所见的事情都可以拆分为这三种结构或者这三种结构的组合。

我们可以使用 if、switch 实现分支(选择)结构,使用 for、while、do while 实现循环结构。

本篇文章即将为您带来if,switch用法的全面解读,以及三种操作符的精彩介绍。

1、if 语句

1.1 if

if 语句的语法形式如下:

<code>if (表达式)

语句 (0不执行,非0执行)

表达式成立(为真),则语句执行,表达式不成立(为假),则语句不执行

在C语言中,0为假,非0表示真,也就是表达式的结果 如果是 0,则语句不执行,表达式的结果 如果不是 0,则语句执行。

例子:输入一个整数,判断是否为奇数

int main()

{

int num = 0;

//输入

scanf("%d",num);

//判断

if(num%2 == 1) //判断相等用两个等号

printf( "%d 是奇数\n",num);

return 0;

}

注:判断相等用两个等号表示,符号为 ==

1.2 else

如果一个数不是奇数,那就是偶数了,如果任意给一个整数,我们要清楚的知道是奇数还是偶数该怎么表示呢?

这时候就要引入一个语句了 if...else...,语法形式如下:

if(表达式)

语句1(为真)

else

语句2(为假)

为真的话执行语句1,为假执行语句2

例子:输入一个年龄,>=18就输出:成年;否则就输出:未成年

#include<stdio.h>

int main()

{

int age = 0;

//输入

scanf("%d", &age);

//判断

if (age >= 18)

printf("成年\n");//语句1

else

printf("未成年\n");//语句2

return 0;

}

注:C语言里的大于等于符号是 >=, 与数学不同。

1.3 分支中包含多条语句

默认情况下 ifelse 语句都只能控制一条语句,比如

#include<stdio.h>

int main()

{

int age = 0;

//输入

scanf("%d", &age);

//判断

if (age >= 18)

printf("成年了\n");//语句

printf("可以谈恋爱\n")//语句

return 0;

}

代码演示结果: 

44d1083f57274743955fc6346cc51ce3.png

 到这里是不是觉得,哎,这不是正确的吗?别急,继续看下去。

b9d0fb3b73aa4ee197cec32e86cd01e6.png

八岁也可以也可以谈恋爱!!!

这时你会发现关于上面的代码,你输入的值不管是>=18还是<18,"可以谈恋爱了"都会打印在屏幕上。

为什么会这样呢?

这是因为if 语句只能控制一条语句,就是 printf("成年了\n");if 语句为真,则打印成年了,if 语句为假,则不打印,对于 printf("可以谈恋爱了\n”);是独立存在的,不管 if 语句的条件的真假,都会被执行。

那如果我们要if语句同时控制2条语句,怎么办呢?那就要使用 大括号{} 将代码括起来,else后也可以跟上大括号。如下:

代码展示:

<code> #include<stdio.h>

int main()

{

int age = 0;

//输入

scanf("%d", &age);

//判断

if (age >= 18)

{

printf("成年了\n");//语句1

printf("可以谈恋爱\n");//语句2

}

else

printf("未成年\n");

return 0;

}

代码结果:

a0566291887f433ca585c42891affa48.png

61037596032340e69800a1d8fe4e3882.png

1.4 嵌套 if

if else 语句中,else 可以与另一个 if 语句连用,构成多重判断。

比如:要求输入一个整数,判断输入的整数是0,还是正数或者负数。

代码演示:

1 #include <stdio.h>

2

3 int main()

4 {

5      int num = 0;

6      scanf("%d",&num);

7      if (num >= 0)

8         printf("输入的数字是0\n");

9      else  if(num >0)//这里的 if 相当于嵌套在else语句中,形成了嵌套结构

10           printf("输入的数字是正数\n");

11             else

12           printf("输入的数字是负数\n");

13 

14        return 0;

15 }

上面中红色背景的代码就是嵌套在前面的else子句中的,构成了嵌套的if语句。

再来一个复杂一点的例子:

输入一个人的年龄,如果年龄 <18岁,打印“少年“;如果年龄在18~30打印”青年“;如果年龄咋子31~55打印“壮年”;如果年龄在56~90打印”老年“如果年龄在90以上打印“老寿星”

代码演示:

<code> int main()

{

int age = 0;

//输入

scanf("%d", &age);

if (age < 18)

printf("少年\n");

else //>=18

{

if(age <=30)//18~30

printf("青年\n");

else //>=30

{

if (age <= 55)

printf("壮年\n");

else //>=55

{

if (age <= 89)//56~89

printf("老年\n");

else

printf("老寿星\n");

}

}

}

return 0;

}

1.5 悬空else问题(多个if和一个else对应关系)

如果有多个if和else,可以记住这样一条规则,else总是跟最接近的 if 匹配。

代码演示:

#include <stdio.h>

int main()

{

int a = 0;

int b = 2;

if(a == 1)//第一个if

if(b == 2)//第二个if

printf("hehe\n");

else

printf("haha\n");

return 0;

}

运行结果会是什么呢?或许你会认为这不是一看就知道输出“haha”吗?

但是,当你去运行代码,输出的结果是:啥都不输出。 

bbd9b0c0bab741e7b5cae02719868848.png

为什么呢?

这就是 悬空else 的问题,如果有多个 if else,可以记住这样一条规则,else 总是跟最接近的if匹配。上面的代码排版,让 else 和第一个 if 语句对齐,让我们以为 else 是和第一个if匹配的,当if 语句不成立的时候,自然想到的就是执行else 子句,打印 haha,但实际上else 是和第二个 if 进行匹配的,这样后边的 if...else 语句是嵌套在第一个 if  语句中的,如果第一个 if 语句就不成立,嵌套 if else 就没机会执行了,最终啥都不打印。

2、switch语句

除了 if 语句外,C语言还提供了 switch语句来实现分支结构。

switch 语句是一种特殊形式的 if...else 结构,用于判断条件有多个结果的情况。它把多重的 else if 改成更易用、可读性更好的形式。

1 switch (expression) 

2 {

3     case constant-expression :

4        statement(s);

5        break; / /可选的 

6     case constant- expression :

7        statement(s);

8        break; // 可选的 

9      default : // 可选的 

10       statement(s);

11 }

上面代码中,根据表达式 expression 不同的值,执行相应的 case 分支。如果找不到对应的值,就执行default 分支。

注:

- switch 后的 expression 必须是整型表达式

- case 后的值,必须是整形常量表达式

代码展示:

<code> int main()

{

     int num =0;

     scanf("%d",&num);  //num % 3;//0 1 2

     

    switch (num % 3)

       {

      case 0:

            printf("余数是0\n");

            break;

    case 1:

           printf("余数是1\n");

          break;

    case 2:

          printf("余数是2\n");

          break;

    }

return 0;

}

注意:

1. case 和后边的数字之间必须有空格

2. 每一个case语句中的代码执行完成后,需要加上break,才能跳出switch语句。

2.1 switch语句中的break

如果上述代码不加入break,会出现什么结果呢?

int main()

{

     int num =0;

     scanf("%d",&num);  //num % 3;//0 1 2

     

    switch (num % 3)

       {

      case 0:

            printf("余数是0\n");

    case 1:

           printf("余数是1\n");

    case 2:

          printf("余数是2\n");

    }

return 0;

}

代码结果:

580deb47775c4ad79584ec21dcf55e20.png

我们可以看到,9除以3本来余数是0,但是我们发现程序运行的结果多了两行行“余数是1” “余数是2”的打印。

这是为什么呢?

原因是switch 语句也是分支效果的,只有在 switch 语句中使用break才能在跳出switch语句,如果某一个case 语句的后边没有break语句,代码会继续往下执行,有可能执行其他case语句中的代码,直到遇到break 语句或switch语句结束。就比如上面的代码就执行了 case 2和3中的语句。

所以在 switch 语句中 break语句是非常重要的,能实现真正的分支效果

当然,break也不是每个case语句都得有,这就得根据实际情况来看了。

2.2 switch语句中的default

在使用 switch 语句的时候,我们经常可能遇到一种情况,比如 switch 后的表达式中的值无法匹配代码中的 case 语句的时候,这时候要不就不做处理,要不就得在 switch 语句中加入default子句。

<code> int main()

{

int day= 0;

//输入

scanf("%d",&day);

switch (day)

{

   case 1:

   case 2:

   case 3:

   case 4:

  case 5:

      printf("工作日\n");

       break;

case 6:

case 7:

      printf("休息日\n");

       break;

default:

       pnmntf("输入错误,重新输入\n");

       break;

}

      return 0;

}

如果day 的输入不是1~7的值,就会执行default子句。如果我们要提示:输入错误,则可以这样完成代码

2.3 switch语句中的case和default的顺序问题

switch 语句中 case 子句和 default 子句有要求顺序吗? default只能放在最后吗?

其实,在 switch 语句中 case 语句和default语句是没有顺序要求的,只要你的顺序是满足实际需求的就可以。

不过我们通常是把 default 子句放在最后处理的。

3、关系操作符

C语言用于比较的表达式,称为“关系表达式”,里面使用的运算符就称为“关系运算符”,主要有下面6个。

• > 大于运算符

• < 小于运算符

• >= 大于等于运算符

• <= 小于等于运算符

• == 相等运算符 

• != 不相等运算符

在C语言中,=是赋值,==是判断相等

下面有一些例子。

a == b;

a != b;

a < b;

a > b;

a < b;

a <= b;

a >= b;

关系表达式通常返回 0 或 1,用来表示真假。

C语言中,0 表示假,非零值表示真。例如: 20 > 12 返回 112 > 20 返回 0.

代码演示:

#include <stdio.h>

int main()

{

int a = 12;

int b = 20;

int c = (a < b);

printf("%d\n", c);

return 0;

}

代码结果: 

aee1450a2616435681a0b12543592303.png

a59e45017cb3410aac357a20e0ad035f.png

关系表达式常用与 if 或 while 结构。

<code> #include <stdio.h>

int main()

{

int x = 0;//初始化,这里=是赋值

scanf("%d", &x);

if (x == 3)//这里==是判断相等

{

printf("x is 3.\n");

}

}

 解读代码:如果 x 等于 3,这可以在屏幕上打印x is 3.

要注意:

相等运算符 ==  与赋值运算符 = 是两个不一样的运算符,不要混淆,有时候,可能会不小心将代码写成 = ,它可以运行,但很容易出现意料之外的结果。

比如,上卖弄代码中,原意是 x == 3 ,但是不小心写成 x = 3,这个式子表示对变量 x 赋值 3,它的返回值为 3 ,所以 if 判断总为真。

这里有一个好办法可以防止出现这种错误:判断一个变量和一个常量是否相等的时候,可以将常量放在等号左边,这样如果把 == 误写成 = ,编译器就会报错,起到提示的作用。

还有一个错误需要避免:多个关系运算符不易连用。

i < j < k

上面示例中,连续使用两个 小于运算符。这是合法表达式,不会报错,但是通常达不到想要的结果,即不是保证变量 j 的值在 ik 之间。因为关系运算符是从左到右计算,所以实际执行的是下面的表达式。

(i < j )< k

代码演示:

int main()

{

     int x = 6;

     int y = 4;

     int k = 5;

    if (x < y < k)

    {

        printf("hehe\n");

     }

     else

     {

         printf("haha\n");

     }

     return 0;

}

代码结果:

639f13c3edcc4b0fa46e6e2da96719ab.png

上面式子中,i<j 返回 0 1,所以最终是 0 或 1 与变量 k 进行比较。如果想要判断变量 j 的值是否在 i

 之间,应该使用下面的写法。

<code>  if (x < y && y < k)  //&& 并且

比如:我们可以输入一个年龄,如果年龄在18岁~36岁之间,我们输出青年。

代码演示:

#include <stdio.h>

int main()

{

int age = 0;

scanf("%d", &age);

if (age >= 18 && age <= 36)

{

printf("青年\n");

}

return 0;

}

关系操作符到这里就告一段落啦!其它的只需要按照字面意思理解使用就可以了。

接下来登场的是条件操作符。

4、条件操作符

4.1 什么是条件操作符?

条件操作符也叫三目操作符,需要接受三个操作数的。

在介绍三目操作符之前,我们先来回忆一下双目操作符和单目操作符

双目操作符:+  -  *  /  %

单目操作符: ++  --  +  -

那什么是三目操作符呢?三目操作符只有一种 (? :)

  三目操作符:表达式1   ?表达式2   : 表达式3

三目操作符是用 问号冒号 组成的.

条件操作符的计算逻辑是:如果 表达式1 为真,表达式2 计算,计算的结果是整个表达式的结果;如果表达式1为假,表达式3 计算,计算的结果是整个表达式的结果。

用条件操作符表示下面代码逻辑:

#include <stdio.h>

int main()

{

int a = 0;

int b = 0;

scanf("%d", &a);

if (a > 5);

b = 3;

else

b = -3;

printf("%d\n", b);

return 0;

}

改造地方:

 if (a > 5);

        b = 3;

 else

       b = -3;

改造后:

b = (a > 5 ?3 :-3);//如果a > 5 ,则 b = 3 成立;反之,b = -3成立。

4.2 条件操作符的作用

在编程过程中,熟练掌握和灵活运用条件操作符,可以让代码更加简洁明了,提高程序的可读性和可维护性。

5、逻辑操作符:!、&&、||

逻辑运算符提供逻辑判断功能,用于构建更复杂的表达式,主要有下面三个运算符。

•!:逻辑取反运算符(改变单个表达式的真假)。

• &&:逻辑与运算符,就是并且的意思(两侧的表达式都为真,则为真,否则为假)。

•||:逻辑或运算符,就是或者的意思(两侧至少有一个表达式为真,则为真,否则为假)。

| 注:C语言中,非0表示真,0表示假

5.1 逻辑 取反运算符 !

a !a
非0(真) 0(假)
0(假) 1(真)

比如说,我们有一个变量 flag ,如果flag为假,要做一个什么事情,就可以这样写代码:

<code> #include <stdio.h>

int main()

{

   int flag = 0;

   if ( !flag )                   

   {

       printf("do something\n");

    }

      return 0;

}

 如果 flag 为真,!flag就是假,如果 flag 为假,!flag就是真

因此上面代码的意思就是:flag为假,!flag为真 ,执行if语句中的代码

5.2 逻辑 与运算符 &&

逻辑与运算符

a b a&&b
非零 非零 1
非零 0 0
0 非零 0
0 0 0

&& 就是 与运算符,也是 并且 的意思,&& 是一个双目操作符,使用的方式是 a&&b && 两边的表达式都是真的时候,整个表达式才为真,只要有一个是假,则整个表达式为假。

四字口诀:一假全假(只要有一个是假的,这个表达式就是假的。)

例如:如果我们说月份3月到五月,是春天,那使用代码该怎么表示呢?

<code> int month = 0;

scanf("%d",&month);

if(month >= 3 && month <= 5);//表达式

{

printf("春季\n");

}

这里表达式的意思就是month既要大于等于3 ,又要小于等于5,且必须同时满足。

只要其中有一个不成立,都不能得到想要结果,假如month大于等于2,则结果不成立;或者month小于等于6,结果也不成立。一假全假

5.3 逻辑 或运算符 ||

逻辑或运算符

a b a||b
非0(真) 非0 1
非0 0(假) 1
0 非0 1
0 0 0

|| 就是或运算符,也就是或者的意思,|| 也是一个双目操作符,使用的方式是 allb 两边的表达式

只要有一个是真,整个表达式就是真,两边的表达式都为假的时候,才为假。

四字口诀:一真全真(只要有一个是真的,表达式就是真的)

例如:我们说一年中月份是12月或者1月或者2月是冬天,那么我们还怎么使用代码体现呢?

<code> int month = 0;

scanf("%d",&month);

if(month == 12 || month == 1 || month == 2));//表达式

{

printf("冬季\n");

}

这里表达式的意思是在12月、 1月 、2 月中,只要有一个 是真(即是冬季) 表达式都成立。

5.4 短路

C语言逻辑运算符还有一个特点,它总是先对左侧的表达式求值,再对右边的表达式求值,这个顺序是保证的。

如果左边的表达式满足逻辑运算符的条件,就不再对右边的表达式求值。这种情况称为“短路”。

如前面代码:

 1 if(month >= 3 && month<= 5)

表达式中&&的左操作数是month >=3,右操作数是month <= 5,当左操作数 month >=3的结果是0的时候,即使不判断month <=5,整个表达式的结果也是 0 (不是春季)。

所以,对于&&操作符来说,左边操作数的结果是 0(假) 的时候,右边操作数就不再执行。

对于 || 操作符是怎么样呢?我们结合前面的代码:

1 if(month == 12 || month==1 || month == 2)

如果month == 12,则不用再判断 month 是否等于1或者2,整个表达式的结果也是1(是冬季)。

所以,|| 操作符的左操作数的结果不为 0(假) 时,就无需执行右操作数。

5.5 短路求值

像上述种仅仅根据左操作数的结果就能知道整个表达式的结果,不再对右操作数进行计算的运算称为短路求值。

在C语言中,短路求值机制是由逻辑与(&&)逻辑或(||)运算符来实现的。这种机制允许我们构建更为简洁且高效的逻辑表达式,因为它允许编译器在表达式结果确定后避免不必要的计算。

潜在问题:

短路求值可能导致一些不易察觉的错误,尤其是当表达式中的操作数有副作用时。

例如,如果 printSomething() 有副作用(比如打印信息、修改全局变量等),那么由于短路求值机制,这些副作用可能不会发生,从而可能导致逻辑错误。

如何避免问题:

- 仔细检查逻辑表达式,确保即使存在短路求值,也不会遗漏必要的副作用。

- 在需要确保每个操作数都被评估的情况下,避免使用短路求值。

- 使用括号明确表达计算顺序,以避免短路求值带来的意外后果。

总结:

短路求值是C语言中一个强大而灵活的特性,但使用时需要谨慎,以确保代码的逻辑正确性和可预测性。


由于该模块知识点过多,本篇文章决定先行奉上if,switch的用法以及三种操作符的精彩介绍。别着急,下篇文章我们会有更多惊喜,包括while,for,do-while等知识的更新,小编期待您的持续关注,不见不散哦!



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。