第03章_运算符与流程控制

第03章_运算符与流程控制

讲师:尚硅谷-宋红康(江湖人称:康师傅)

官网:http://www.atguigu.com


本章专题脉络

1. 运算符(Operator)

运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等。

运算符的分类:

  • 按照功能分为:算术运算符、赋值运算符、比较(或关系)运算符、逻辑运算符、位运算符、条件运算符、sizeof运算符
分类运算符
算术运算符+、-、+、-、*、/、%、++、–
赋值运算符=、+=、-=、*=、/=、%=等
比较(或关系)运算符>、>=、<、<=、==、!=
逻辑运算符&&、||、!
位运算符&、|、^、~、<<、>>
条件运算符(条件表达式)?结果1:结果2
sizeof运算符sizeof()
  • 按照操作数个数分为:一元运算符(单目运算符)、二元运算符(双目运算符)、三元运算符 (三目运算符)
分类运算符
一元运算符(单目运算符)正号(+)、负号(-)、++、–、!、~
二元运算符(双目运算符)除了一元和三元运算符剩下的都是二元运算符
三元运算符 (三目运算符)(条件表达式)?结果1:结果2

1.1 算术运算符

算术运算符专门用于算术运算,主要有下面几种。

image-20240107124909948

举例1:

int x = -12;
int y = -x;
int z = +y; //+可以省略

举例2:

int a = 4 + 2;int num = 5;
printf("%d\n", num * num); // 输出 25float x = 6 / 4;
printf("%f\n", x); // 输出 1.000000float x = 6.0 / 4; // 或者写成 6 / 4.0
printf("%f\n", x); // 输出 1.500000

举例3:%,运算结果的符号与被模数相同

int x1 = 6 % 4; // 2
int x2 = -6 % 4; // -2
int x3 = 6 % -4; // 2
int x4 = -6 % -4; // -2

举例4:自加自减运算

理解:++ 运算,表示自增1。同理,-- 运算,表示自减1,用法与++ 一致。

1、单独使用

  • 变量在单独运算的时候,变量前++和变量后++,是没有区别的。
  • 变量前++ :例如 ++a
  • 变量后++ :例如 a++
int main() {int a = 10;//++a;a++;//无论是变量前++还是变量后++,结果都是11printf("%d\n",a);return 0;
}

2、复合使用

  • 其他变量放在一起使用或者和输出语句放在一起使用前++后++就产生了不同。
  • 变量前++ :变量先自增1,然后再运算。
  • 变量后++ :变量先运算,然后再自增1。
int main() {// 其他变量放在一起使用int x = 3;//int y = ++x; // y的值是4,x的值是4,int y = x++; // y的值是3,x的值是4printf("%d\n",x);printf("%d\n",y);printf("==========\n");// 和输出语句一起int z = 5;//printf("%d\n",++z);// 输出结果是6,z的值也是6printf("%d\n",z++);// 输出结果是5,z的值是6printf("%d\n",z);return 0;
}

与此对应的:

  • 变量前-- :变量先自减1,然后再运算。
  • 变量后-- :变量先运算,然后再自减1。

案例1:

随意给出一个整数,打印显示它的个位数,十位数,百位数的值。
格式如下:
数字xxx的情况如下:
个位数:
十位数:
百位数:例如:
数字153的情况如下:
个位数:3
十位数:5
百位数:1
#include <stdio.h> int main() {int num = 153;int bai = num / 100;int shi = num % 100 / 10;//int shi = num / 10 % 10;int ge = num % 10;printf("百位为:%d\n", bai);printf("十位为:%d\n", shi);printf("个位为:%d\n", ge);return 0;
}

**案例2:**为抵抗洪水,战士连续作战89小时,编程计算共多少天零多少小时?

#include <stdio.h>int main() {int hours = 89;int day = hours / 24;int hour = hours % 24;printf("为抵抗洪水,战士连续作战%d小时:是%d天%d小时\n",hours,day,hour);return 0;
}

1.2 赋值运算符

  • 符号 =
    • 当“=”两侧数据类型不一致时,可以使用自动类型转换或使用强制类型转换原则进行处理。
    • 支持连续赋值
  • 扩展赋值运算符: +=、 -=、*=、 /=、%=
运算符名称实例展开形式
+=复合加赋值a+=ba=a+b
-=复合减赋值a-=ba=a-b
*=复合乘赋值a*=ba=a*b
/=复合除赋值a/=ba=a/b
%=复合模赋值a%=ba=a%b

举例:

i += 3;  // 等同于 i = i + 3
i -= 8;  // 等同于 i = i - 8
i *= 9;  // 等同于 i = i * 9
i /= 2;  // 等同于 i = i / 2
i %= 5;  // 等同于 i = i % 5

举例:

//连续赋值的测试
//以前的写法
int a1 = 10;
int b1 = 10;//连续赋值的写法
int a2,b2;
a2 = b2 = 10;int a3 = 10,b3 = 20;

举例:

int a = 10;
a += 1.7;  // a=a+1.7 => 11.7 => 11
printf("a=%d", a);  // a=11

举例:

int a, b, c;
a = (b = 5);    //表达式的值为5,将5赋值给b,接着将b的值赋值给a
a = 5 + (c = 6);        //表达式值为11,a值为11,c值为6
a = (b = 4) + (c = 6);    //表达式值为10,a值为10,b等于4,c等于6
a = (b = 10) / (c = 2);    //表达式值为5,a等于5,b等于10,c等于2
a = (b = 3 * 4);        //表达式值为12,a,b值均为12

【武汉科技大学2019研】

若a、b和t都为int变量,则下面不能交换变量a和b值的是(  )。
A.t=a; a=b; b=t;
B.a=t; t=b; b=a;
C.t=b; b=a; a=t;
D.a=a+b; b=a-b; a=a-b;

【答案】B

【解析】B中首先把t的值赋值给了a,则a的值已经被取代了,后面执行b=a,则ab的值都等于t的值。

【中央财经大学2018研】以下程序运行后的输出结果是(  )。

int main(){  double d;  float f;  long l;  int i;  i = f = l = d = 20/3;  printf("%d %ld %.1f %.1f\n",i,l,f,d);  return 0;
} 

A.6 6 6.0 6.0
B.6 6 6.7 6.7
C.6 6 6.0 6.7
D.6 6 6.7 6.0

【答案】A

【解析】赋值运算符是自右向左结合的,所以首先执行d=20/3=6,同时i、l、f也全为6,在进行输出时,f和d要保留一位小数,所以答案选A。

练习:

以下选项中正确的定义语句是(  )。
A.double a;b;
B.double a=b=7;
C.double a=7,b=7;
D.double,a,b;

【答案】C

【解析】同一类型变量的定义时,不同变量之间需要用“,”分隔,选项A错误;定义变量时初始化赋值不能用等号连接,选项B错误;变量类型说明后面不能用逗号,而是用空格分离,选项D错误。答案选择C选项。

1.3 比较运算符(或关系运算符)

常用的比较运算符:

关系运算符含义举例
>大于num > 10
>=大于等于num >= 10
<小于num < 10
<=小于等于num <= 10
==等于num == 10
!=不等于num != 10
  • 比较运算的结果只有两个取值,要么是真(非0 表示,默认使用1),要么是假(0 表示)。
    • 比如, 20 > 12 返回 1 , 12 > 20 返回 0 。
  • 比较运算符“==”不能误写成“=

举例1:

int i1 = 10;
int i2 = 20;printf("%d\n",i1 == i2);//0
printf("%d\n",i1 != i2);//1
printf("%d\n",i1 >= i2);//0int m = 10;
int n = 20;
printf("%d\n",m == n);//0
printf("%d\n",m = n);//20

举例2:多个关系运算符不宜连用。

i < j < k   //期望判断j是否大于i,且小于k

这是合法表达式,不会报错,但是通常达不到想要的结果,即不是保证变量 j 的值在 i 和 k 之间。比如:

//i < j < k
int j = 10;
if(15 < j < 20){printf("j大于15,且小于20"); //输出此语句
}else{printf("j不在15到20之间");
}

因为关系运算符是从左到右计算,所以实际执行的是:

(i < j) < k; //i < j 返回 0 或 1 ,所以最终是 0 或 1 与变量 k 进行比较

期望的效果应该写为:

//i < j < k
int j = 10;
if(15 < j && j < 20){printf("j大于15,且小于20"); 
}else{printf("j不在15到20之间"); //输出此语句
}

【北京航空航天大学2018研】若变量a,b,c的取值分别是1,2,3,则表达式“!((b+c)>(a+4))”的值是( )。
A.0
B.1
C.2
D.3

【答案】B

【解析】首先b+c等于5,a+4也等于5,因此 (b+c)>(a+4)为“假”,即0,对0取非结果为1,因此答案为B。

1.4 逻辑运算符

主要有下面三个运算符:

逻辑运算符描述功能举例
&&与运算符两个条件都要满足num1 >= 10 && num2 >= 20
||或运算符两个条件只需满足其一num1 >= 10 || num2 >= 20
!非运算符否定条件!(num1 >= 10)(等价于 num1 < 10)

逻辑运算符提供逻辑判断功能,用于构建更复杂的表达式。

举例:

aba && ba || b!a
1(真)1(真)1(真)1(真)0(假)
1(真)0(假)0(假)1(真)0(假)
0(假)1(真)0(假)1(真)1(真)
0(假)0(假)0(假)0(假)1(真)

对于逻辑运算符来说,任何非零值都表示真,零值表示伪。比如, 5 || 0 会返回 1 , 5 && 0 会返回0 。

举例1:

int x = 5;
int y = 11;
if (x < 10 && y > 20)printf("今天天气真晴朗\n");

举例2:短路现象

  • &&:a && b
    • 当 a 为假(或0)时,因为a && b 结果必定为 0,所以不再执行表达式 b
    • 当 a 为真(非0)时,因为a && b 结果不确定,所以会继续求解表达式b
int i = 0;
int j = 10;
if(i && j++ > 0){printf("床前明月光");
}else{printf("我叫郭德纲");
}printf("%d\n",j); //10
  • || :a || b
    • 当 a 为真(非0)时,因为a || b 结果必定为 1,所以不再执行表达式 b
    • 当 a 为假(或0)时,因为a || b 结果不确定,所以会继续求解表达式b
int i = 1;
int j = 10;
if(i || j++ > 0){printf("床前明月光");
}else{printf("我叫郭德纲");
}printf("%d\n",j); //10

练习:请写出如下程序运行后的结果

int main() {int x = 1;int y = 0;short z = 42;if ((z++ == 42) && (y = 1)) {z++; // z = 44}if ((x = 0) || (++z == 45)) {z++;  // z = 46}printf("z=%d", z);return 0;
}

答案:z=46

【华南理工大学2018研】设int a=3;,下列哪一个表达式的值等于0(  )。
A.a&&(a>0)
B.!a||a
C.a%=a
D.a>=a

【答案】C

【解析】A中a!=0且a>0所以表达式的值为1;B中||表示或,所以值也为1;D中表达式值也为1;答案选C。

【四川大学2017研】语句:printf(“%d”,(a=2) && (b=-2));的输出结果是(  )。
A.无输出
B.结果不确定
C.-1
D.1

【答案】D

【解析】a=2为真,b=-2也为真,所以输出1,答案选D。

1.5 位运算符

  • C 语言提供一些位运算符,用来操作二进制位(bit)。

  • 位运算符的运算过程都是基于二进制的补码运算。

运算符描述运算规则
<<二进制左移将一个数的各二进制位全部左移指定的位数,左边的二进制位丢弃,右边补0。
>>二进制右移将一个数的各二进制位全部右移指定的位数,正数左补0,负数左补1,右边丢弃。
&按位与两个二进制位都为 1,结果为1,否则为0。
|按位或两个二进制位只要有一个为1(包含两个都为 1 的情况),结果为1,否则为0。
^按位异或两个二进制位一个为0,一个为1,结果为1,否则为0。
~按位取反将每一个二进制位变成相反值,即 0 变成 1 , 1 变成 0 。
  • 结合赋值运算符的经验,这里有:<<= 、 >>= 、 &= 、 ^= 等

举例1:

(1)左移:<<

运算规则:在一定范围内,数据每向左移动一位,相当于原数据*2。(正数、负数都适用)

【注意】当左移的位数n超过该数据类型的总位数时,相当于左移(n-总位数)位

3<<4  类似于  3*24次幂 => 3*16 => 48

image-20240107124931208

-3<<4  类似于  -3*24次幂 => -3*16 => -48

image-20240107124933469

(2)右移:>>

运算规则:在一定范围内,数据每向右移动一位,相当于原数据/2。(正数、负数都适用)

【注意】

1、如果不能整除,向下取整

2、右移运算符最好只用于无符号整数,不要用于负数。因为不同系统对于右移后如何处理负数的符号位,有不同的做法,可能会得到不一样的结果。

69>>4  类似于  69/24次幂 = 69/16 =4

image-20240107124936308

-69>>4  类似于  -69/24次幂 = -69/16 = -5

image-20240107124939714

练习:高效的方式计算2 * 8的值(经典面试题)

答案:2 << 3 、  8  << 1

举例2:

(1)按位与:&

运算规则:对应位都是1才为1,否则为0。

  • 1 & 1 结果为1

  • 1 & 0 结果为0

  • 0 & 1 结果为0

  • 0 & 0 结果为0

9 & 7 = 1

image-20240107124943988

-9 & 7 = 7

image-20240107124946617

(2)按位或:|

运算规则:对应位只要有1即为1,否则为0。

  • 1 | 1 结果为1

  • 1 | 0 结果为1

  • 0 | 1 结果为1

  • 0 & 0 结果为0

9 | 7  //结果: 15

image-20240107124951293

-9 | 7 //结果: -9

image-20240107124955505

(3)按位异或:^

运算规则:对应位一个为1一个为0,才为1,否则为0。

  • 1 ^ 1 结果为0

  • 1 ^ 0 结果为1

  • 0 ^ 1 结果为1

  • 0 ^ 0 结果为0

9 ^ 7  //结果为14

image-20240107125004305

-9 ^ 7 //结果为-16

image-20240107125006563

(4)按位取反:~

运算规则:对应位为1,则结果为0;对应位为0,则结果为1。

  • ~0就是1

  • ~1就是0

~9  //结果:-10

image-20240107125010511

~-9  //结果:8

image-20240107125013249

练习1:

int i = 12,j = 5;printf("%d\n",i & j); //4
printf("%d\n",i | j); //13
printf("%d\n",i ^ j); //9

image-20240107125016188

练习2:特定位清零

技巧:待清零的位与0,其它位与1

示例:设字符型 x 的当前值为 53,将其最低两位清 0,其余位保持不变

分析:与二进制的0b11111100数值求&运算即可。

int main() {char x = 53; // 0b00110101x = x & 252; // 0b11111100printf("%d", x); //0b00110100return 0;
}

举例:判断特定位是否为零

技巧:待判定位与 1,其它位与 0;判与运算结果是否为 0

示例:设字符型 x 的当前值为 53,判定其最高位是否为 0

分析:与二进制的0b10000000求&运算,若结果为 0,则最高位为 0,否则为 1

int main() {char x = 53; // 0b00110101x = x & 128; // 0b10000000if(x == 0)printf("最高位为0");elseprintf("最高位不为0");return 0;}

举例:保留特定位

技巧:待保留位全部与 1,其余位与 0

示例:设字符型 x 的当前值为 53,保留其最低 4 位,其余位清零

分析:与二进制的0b00001111求&运算即可。

int main() {char x = 53; // 0b00110101x = x & 15;  // 0b00001111printf("%d\n",x); //0b00000101return 0;}

举例:待置 1 或 1,保持位或 0

示例:设字符型 x 的当前值为 53,将其最低两位置 1,其余位保持不变

分析:与二进制0b00000011求或运算即可

int main() {char x = 53; // 0b00110101x = x | 3;   // 0b00000011printf("%d\n",x); //0b00110111return 0;}

举例:特定位取反

待取反位异或 1,保持位异或 0

示例:设字符型 x 的当前值为 53,将其最低两位取反,其余位保持不变

分析:与二进制0b00000011求异或运算即可

int main() {char x = 53; // 0b00110101x = x ^ 3;   // 0b00000011printf("%d\n",x); //0b00110110return 0;}

1.6 条件运算符

  • 条件运算符格式:
(条件表达式)? 表达式1:表达式2
  • 说明:条件表达式是如果为 true (非0值),就执行表达式1,否则执行表达式2。

    image-20240107125020728

  • 如果运算后的结果赋给新的变量,要求表达式1和表达式2为同种或兼容的类型

**举例1:**获取两个数中的较大值

int main() {//获取两个数的较大值int m1 = 10;int m2 = 20;int max1 = (m1 > m2)? m1 : m2;printf("m1和m2中的较大值为%d\n",max1);return 0;}

**举例2:**获取三个数中的最大值

int main() {int n1 = 23;int n2 = 13;int n3 = 33;//写法1:int tempMax = (n1 > n2)? n1:n2;int finalMax = (tempMax > n3)? tempMax : n3;printf("三个数中最大值为%d\n",finalMax);//写法2:不推荐,可读性差int finalMax1 = (((n1 > n2)? n1:n2) > n3)? ((n1 > n2)? n1:n2) : n3;printf("三个数中最大值为%d\n",finalMax1);return 0;}

【华南理工大学2018研】输入一个字符,判别它是否为大写字母,如果是,将它变为小写字母;如果不是,不转换。然后输出最后得到的字符。请在下面空白处填上适当语句。

#include<stdio.h>
int main(){ char ch;  scanf("%c",);  ch=(ch>='A'&&)?(ch+32):;  printf(,ch);  return;
} 

【答案】①&ch②ch<=’Z’③ch④"%c"⑤0

【解析】程序进行输入时要加上地址符&;main函数中的第三行为一个三目运算符,当ch在A~Z之间时ch为真,此时ch+32变为小写字母,否则不变;程序进行输出时应用%加上数据类型进行输出,最后用return 0来结束程序。

1.7 sizeof 运算符

sizeof 运算符:sizeof(参数)

  • 参数可以是数据类型的关键字,也可以是变量名或某个具体的值
  • 返回某种数据类型或某个值占用的字节数量。

举例1:参数为数据类型

int x = sizeof(int);  //通常是 4 或 8

举例2:参数为变量

int i;
sizeof(i); //通常是 4 或 8// 参数为数值
sizeof(3.14); //浮点数的字面量一律存储为double类型,故返回 8

sizeof返回值的类型说明

sizeof 运算符的返回值,C 语言只规定是无符号整数,并没有规定具体的类型,留给系统自己去决定sizeof 到底返回什么类型。不同的系统中,返回值的类型有可能是 unsigned int ,也有可能是unsigned long ,甚至是 unsigned long long ,对应的 printf() 占位符分别是 %u 、 %lu和 %llu 。这样不利于程序的可移植性。

C 语言提供了一个解决方法,创造了一个类型别名 size_t ,用来统一表示 sizeof 的返回值类型。该别名定义在 stddef.h 头文件里面,对应当前系统的 sizeof 的返回值类型,可能是 unsigned int ,也可能是 unsigned long 。

printf() 有专门的占位符 %zd%zu ,用来处理 size_t 类型的值。

printf("%zd\n", sizeof(int));

上面代码中,不管 sizeof 返回值的类型是什么, %zd 占位符(或 %zu )都可以正确输出。

如果当前系统不支持 %zd 或 %zu ,可使用 %u (unsigned int)或 %lu (unsigned long int)代替。

1.8 运算符的优先级

运算符有不同的优先级,所谓优先级就是在表达式运算中的运算符顺序。

上一行中的运算符总是优先于下一行的。

image-20240107125024903

开发建议:

  1. 不要过多的依赖运算的优先级来控制表达式的执行顺序,这样可读性太差,尽量使用()来控制表达式的执行顺序。
  2. 不要把一个表达式写得过于复杂,如果一个表达式过于复杂,则把它分成几步来完成。例如:
    ​ (num1 + num2) * 2 > num3 && num2 > num3 ? num3 : num1 + num2;

2. 流程控制结构

  • 流程控制结构是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块。
  • 程序设计中规定的三种流程结构,即:
    • 顺序结构
      • 程序从上到下逐行地执行,中间没有任何判断和跳转。
    • 分支结构
      • 根据条件,选择性地执行某段代码。
      • if…elseswitch-case两种分支语句。
    • 循环结构
      • 根据循环条件,重复性的执行某段代码。
      • forwhiledo-while三种循环语句。

2.1 顺序结构

程序从上到下逐行地执行。表达式语句都是顺序执行的。并且上一行对某个变量的修改对下一行会产生影响。

image-20240107125032854

int main() {int x = 1;int y = 2;printf("x = %d\n", x);printf("y = %d\n", y);//对x、y的值进行修改x++;y = 2 * x + y;x = x * 10;printf("x = %d\n", x);printf("y = %d\n", y);return 0;}

c语言中定义变量时采用合法的前向引用。如:

int main() {int num1 = 12;int num2 = num1 + 2;return 0;
}

错误形式:

int main() {int num2 = num1 + 2; //use of undeclared identifier 'num1'int num1 = 12;return 0;
}

2.2 分支结构1:if-else

2.2.1 基本语法

结构1:单分支

if(条件表达式){语句块;

执行流程:条件表达式为真(值不为 0 )时,就执行语句块。

图示:

image-20240107125036032

举例:成年人心率的正常范围是每分钟60-100次。体检时,如果心率不在此范围内,则提示需要做进一步的检查。

int main(){int heartBeats = 89;if(heartBeats < 60 || heartBeats > 100){printf("你需要做进一步的检查");}printf("体检结束");return 0;
}

结构2:双分支

if(条件表达式) { 语句块1;
}else {语句块2;
}

执行流程:

  1. 首先判断条件表达式看其结果是为真(值不为 0 )还是假(值为0)
  2. 如果是真,就执行语句块1
  3. 如果是假,就执行语句块2

image-20240107125039142

举例:定义一个整数,判定是偶数还是奇数

int main() {int a = 10;if (a % 2 == 0) {printf("%d是偶数\n", a);} else {printf("%d是奇数\n", a);}return 0;
}

结构3:多重分支

if (条件表达式1) {语句块1;
} else if (条件表达式2) {语句块2;
}
...
}else if (条件表达式n) {语句块n;
} else {语句块n+1;
}

执行流程:

  1. 首先判断关系表达式1看其结果是真(值不为0)还是假(值为0)
  2. 如果是真,就执行语句块1,然后结束当前多分支
  3. 如果是假,就继续判断条件表达式2,看其结果是真还是假
  4. 如果是真,就执行语句块2,然后结束当前多分支
  5. 如果是假,就继续判断条件表达式…看其结果是真还是假

​ …

n. 如果没有任何关系表达式为真,就执行语句块n+1,然后结束当前多分支。

image-20240107125041916

举例:

岳小鹏参加C语言考试,他和父亲岳不群达成承诺:
如果:
成绩为100分时,奖励一辆跑车;
成绩为(80,99]时,奖励一辆山地自行车;
当成绩为[60,80]时,奖励环球影城一日游;
其它时,胖揍一顿。说明:默认成绩是在[0,100]范围内
int main() {int score = 67;//岳小鹏的期末成绩//写法一:默认成绩范围为[0,100]if (score == 100) {printf("奖励一辆跑车");} else if (score > 80 && score <= 99) {    //错误的写法:}else if(80 < score <= 99){printf("奖励一辆山地自行车");} else if (score >= 60 && score <= 80) {printf("奖励环球影城玩一日游");}//else{//	printf("胖揍一顿");//}//写法二:// 默认成绩范围为[0,100]if (score == 100) {printf("奖励一辆跑车");} else if (score > 80) {printf("奖励一辆山地自行车");} else if (score >= 60) {printf("奖励环球影城玩一日游");} else {printf("胖揍一顿");}return 0;
}

当条件表达式之间是“互斥”关系时(即彼此没有交集),条件判断语句及执行语句间顺序无所谓。

当条件表达式之间是“包含”关系时,“小上大下 / 子上父下”,否则范围小的条件表达式将不可能被执行。

当if-else结构是“多选一”时,最后的else是可选的,根据需要可以省略

语句块只有一条执行语句时,一对{}可以省略,但建议保留

练习:判断输出结果

int main() {int number = 20;if (number > 6)if (number < 12)printf("The number >= 6,且 <= 12.\n");elseprintf("判断不成功.\n");return 0;
}

说明:

如果有多个 if 和 else ,没有{}的情况下, else 总是跟最接近的 if 匹配。

为了提供代码的可读性,建议使用大括号,明确 else 匹配哪一个 if 。

如果希望else与外层的if匹配,改写为如下:

int main() {int number = 20;if (number > 6) {if (number < 12) {printf("The number >= 6,且 <= 12.\n");}} else {printf("判断不成功.\n");}return 0;
}
2.2.2 举例

举例1:

#include <stdio.h>int main() {int age = 0;scanf("%d", &age);if (age < 18) {printf("未成年\n");} else {printf("成年\n");}return 0;
}

举例2:

编写一个程序,判定某个年份是否为闰年。年份满足如下条件之一,即是闰年:

⑴ year 是 400 的整倍数: year%400==0

(2) 能被4整除,但不能被100整除:year % 4 == 0 && year % 100 != 0

#include<stdio.h>int main() {int year;printf("输入年份: ");scanf("%d", &year);if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))printf("%d 是闰年\n", year);elseprintf("%d 不是闰年\n", year);return 0;
}

举例3:解方程

设计求解一元二次方程 a x 2 + b x + c = 0 ax^2+bx+c=0 ax2+bx+c=0 (a≠0)的程序

#include<stdio.h>
#include <math.h>int main() {float a, b, c;float x1, x2, d;printf("输入方程中的系数与常量 a,b,c: ");scanf("%f%f%f", &a, &b, &c);d = b * b - 4 * a * c;if (d >= 0) {x1 = (-b + sqrt(d)) / (2 * a);x2 = (-b - sqrt(d)) / (2 * a);printf("x1=%f,x2=%f\n", x1, x2);} elseprintf("方程没有根\n");return 0;
}

举例4:判断水的温度

如果大于95℃,则打印“开水”;如果大于70℃且小于等于95℃,则打印“热水”;如果大于40℃且小于等于70℃,则打印“温水”;如果小于等于40℃,则打印“凉水”。
int main() {int waterTemperature = 85;if (waterTemperature > 95) {printf("开水");} else if (waterTemperature > 70 && waterTemperature <= 95) {printf("热水");} else if (waterTemperature > 40 && waterTemperature <= 70) {printf("温水");} else {printf("凉水");}return 0;
}

举例5:if-else的嵌套

出票系统:根据淡旺季的月份和年龄,打印票价。要求,月份和年龄从键盘获取输入。

4_10 旺季:
成人(18-60):60
儿童(< 18) : 半价
老人(> 60) : 1/3
淡季:
成人 : 40
其他 : 20

int main() {int month, age;double price = 60.0;printf("请输入月份(1-12):");scanf("%d", &month);printf("请输入年龄:");scanf("%d", &age);if (month >= 4 && month <= 10) {  // 旺季if (age < 18) {price = price / 2;  // 半价} else if (age > 60) {price = price / 3;  // 1/3价格}} else {  // 淡季if (age >= 18) {price = 40.0;} else {price = 20.0;}}printf("您的票价是:¥%.2f\n", price);return 0;}

【武汉科技大学2019研】对下述程序段的描述正确的是(  )。

scanf("%d,%d",&a,&b);
if(a>b)  
a=b;b=a;
else  
a++;b++;
printf("a=%d,b=%d",a,b); 

A.若输入4,5则输出a=5,b=6
B.若输入5,4则输出a=4,b=5
C.若输入5,4则输出a=5,b=5
D.有语法错误,不能通过编译

【答案】D

【解析】if(表达式)后面如果没有用花括号括起来,那么if的子语句只包括第一条语句,即在程序中只有a=b是属于if语句块的,if和else中间隔了一条语句b=a,编译无法通过。

【华南理工大学2018研】两次运行下面的程序,如果从键盘上分别输入6和4,则输出的结果是(  )

void main(void){int x;scanf("%d",&x);if(x++>5)printf("%d\n",x);elseprintf("%d\n",x--);return 0;
} 

A.7和5
B.6和3
C.7和4
D.6和4

【答案】A

【解析】当输入6时,判断 x++>5为真,进入if语句块,此时x=7,输出7;当输入4时,进入else语句块,此时x=5,然后因为–是先运算后自减,所以先输出5,后x的值为4,答案选A。

2.3 分支结构2:switch-case

2.3.1 基本语法

switch 语句用于判断条件有多个常量结果的情况。它把多重的 else if 改成更易用、可读性更好的形式。

switch(表达式){case 常量值1: 语句块1;//break;case 常量值2: 语句块2;//break;┇ ┇case 常量值n: 语句块n; //break;[default: 语句块n+1;]
}

执行流程图:

image-20240107125051216

执行过程:

第1步:根据switch中表达式的值,依次匹配各个case。如果表达式的值等于某个case中的常量值,则执行对应case中的执行语句。

第2步:执行完此case的执行语句以后,
​ 情况1:如果遇到break,则执行break并跳出当前的switch-case结构
​ 情况2:如果没有遇到break,则会继续执行当前case之后的其它case中的执行语句。—>case穿透
​ …
​ 直到遇到break关键字或执行完所有的case及default的执行语句,跳出当前的switch-case结构

使用注意点:

  • switch后面的表达式只能是整型和字符型。

  • case子句中的值必须是常量,不能是变量名或不确定的表达式值或范围。

  • 同一个switch语句,所有case子句中的常量值互不相同。

  • 如果没有break,程序会顺序执行到switch结尾;从使用频率说,一般switch-case结构中,都需要编写break。

  • default子句是可选的。同时,位置也是灵活的。当没有匹配的case时,执行default语句。

2.3.2 举例

举例1:

int main() {int grade = 1;switch (grade) {case 0:printf("zero\n");break;case 1:printf("one\n");break;case 2:printf("two\n");break;case 3:printf("three\n");break;default:printf("other\n");}return 0;
}

与如下代码对比:

int main() {int grade = 1;switch (grade) {case 0:printf("zero\n");//break;case 1:printf("one\n");//break;case 2:printf("two\n");//break;case 3:printf("three\n");//break;default:printf("other\n");}return 0;
}

举例2:使用switch-case实现:对学生成绩大于60分的,输出“合格”。低于60分的,输出“不合格”。

int main() {int score = 83;//方式1:switch(score / 10){case 0:printf("不及格");break;case 1:printf("不及格");break;case 2:printf("不及格");break;case 3:printf("不及格");break;case 4:printf("不及格");break;case 5:printf("不及格");break;case 6:printf("及格");break;case 7:printf("及格");break;case 8:printf("及格");break;case 9:printf("及格");break;case 10:printf("及格");break;default:printf("成绩输入有误");break;}return 0;
}

如果多个 case 分支对应同样的语句体,可以改写如下:

int main() {int score = 83;//方式2:体会case穿透switch(score / 10){case 0:case 1:case 2:case 3:case 4:case 5:printf("不及格");break;case 6:case 7:case 8:case 9:case 10:printf("及格");break;default:printf("成绩输入有误");break;}return 0;
}

从算法层面,还可以优化下代码,改为如下:

int main() {int score = 83;//方式3:算法层面优化switch(score / 60){case 0:printf("不及格");break;case 1:printf("及格");break;default:printf("成绩输入有误");break;}return 0;
}

错误举例:

int main() {int key = 10;switch (key) {case key > 0 :  //提示:Expression is not an integer constant expressionprintf("正数");break;case key < 0:printf("负数");break;default:printf("零");break;}return 0;
}

【武汉科技大学2019研】若有定义:int a=1,b=2; float x=3,w; 则合法的switch语句是( )。

A.

switch (a) {
case 1:w = a / b;break;
case 2:w = a % b;break;
}

B.

switch (b) {
case 1:z = a % b;
case 2:z = a / b;break;
}

C.

switch (x) {
case 2:w = a % b;break;
case 1:w = a / b;break;
}

D.

switch (a + b);{
case 3:
case 2:
w = a % b;
break;
}

【答案】A

【解析】B中,变量z未定义;C中x为浮点型,switch后面的表达式不能是浮点型,只能是整型和字符型;D中swith表达式后面不能加分号,答案选A。

【北京航空航天大学2018研】对于下列代码:

switch(option){
case 'H':printf("Hello ");
case 'W':printf("Welcome ");
case 'B':printf("Bye");break;
}

若option的取值为’W’,则该代码段的输出结果是(  )。
A.Welcome
B.Welcome Bye
C.Hello Welcome Bye
D.以上结果都不对

【答案】B

【解析】由于option为’W’,所以首先应该输出Welcome,但是由于该语句后面没有break语句来终止选择语句switch,因此会继续执行下面的语句,直到遇上break,所以最后输出Welcome Bye,答案为B。

2.3.3 if-else与switch-case比较
  • 结论:凡是使用switch-case的结构都可以转换为if-else结构。反之,不成立。

  • 开发经验:如果既可以使用switch-case,又可以使用if-else,建议使用switch-case。因为效率稍高。

  • 细节对比:

    • if-else语句优势
      • if语句的条件可以用于范围的判断,也可以用于等值的判断,使用范围更广
      • switch语句的条件是一个常量值,只能判断某个变量或表达式的结果是否等于某个常量值,使用场景较狭窄
    • switch语句优势
      • 当条件是判断某个变量或表达式是否等于某个固定的常量值时,使用if和switch都可以,习惯上使用switch更多。因为效率稍高。当条件是区间范围的判断时,只能使用if语句。
      • 使用switch可以利用穿透性,同时执行多个分支,而if…else没有穿透性。

2.4 循环结构之1:for循环

  • 循环结构的理解:循环语句具有在某些条件满足的情况下,反复执行特定代码的功能。

  • 循环结构分类:

    • for 循环
    • while 循环
    • do-while 循环
  • 循环结构四要素

    • 初始化部分
    • 循环条件部分
    • 循环体部分
    • 迭代部分
2.4.1 基本语法

语法格式:

for (①初始化部分; ②循环条件部分; ④迭代部分){③循环体部分;

**执行过程:**①-②-③-④-②-③-④-②-③-④-…-②

图示:

image-20240107125059745

说明:

  • for(;;)中的两个;不能多也不能少
  • ①初始化部分,用于初始化循环变量,只执行一次。可以声明多个变量,但必须是同一个类型,用逗号分隔
  • ②循环条件部分,只要为 true ,就会不断执行循环体;当值为false时,退出循环
  • ④迭代部分,每轮循环结束后执行,使得循环变量发生变化。可以有多个变量更新,用逗号分隔
2.4.2 举例

案例1:使用for循环重复执行某些语句

题目:输出5行HelloWorld

int main() {//写法1:
//    printf("Hello World!\n");
//    printf("Hello World!\n");
//    printf("Hello World!\n");
//    printf("Hello World!\n");
//    printf("Hello World!\n");//写法2:for (int i = 1; i <= 5; i++) {printf("Hello World!\n");}return 0;
}

案例2:格式的多样性

题目:写出输出的结果

int main() {int num = 1;for(printf("a");num < 3;printf("c"),num++){printf("b");}return 0;
}
int main() {int i, j;for (i = 0, j = 999; i < 10; i++, j--) {printf("%d, %d\n", i, j);}return 0;
}

案例3:累加的思想

题目:遍历1-100以内的偶数,并获取偶数的个数,获取所有的偶数的和

int main() {int count = 0;//记录偶数的个数int sum = 0;//记录偶数的和for (int i = 1; i <= 100; i++) {if (i % 2 == 0) {printf("%d\n", i);count++;sum += i;}//printf("偶数的个数为:" + count);}printf("偶数的个数为:%d\n", count);printf("偶数的总和为:%d\n", sum);return 0;
}

案例4:结合分支结构使用

题目:输出所有的水仙花数,所谓水仙花数是指一个3位数,其各个位上数字立方和等于其本身。例如: 153 = 1*1*1 + 3*3*3 + 5*5*5

int main() {//定义统计变量,初始化值是0int count = 0;//获取三位数,用for循环实现for (int x = 100; x < 1000; x++) {//获取三位数的个位,十位,百位int ge = x % 10;int shi = x / 10 % 10;int bai = x / 100;//判断这个三位数是否是水仙花数,如果是,统计变量++if ((ge * ge * ge + shi * shi * shi + bai * bai * bai) == x) {printf("水仙花数:%d\n", x);count++;}}//输出统计结果就可以了printf("水仙花数共有%d个", count);return 0;
}

拓展:

打印出四位数字中“个位+百位”等于“十位+千位”并且个位数为偶数,千位数为奇数的数字,并打印符合条件的数字的个数。

案例5:结合break的使用

说明:输入两个正整数m和n,求其最大公约数和最小公倍数。

比如:12和20的最大公约数是4,最小公倍数是60。

int main() {//需求1:最大公约数int m = 12, n = 20;//取出两个数中的较小值int min = (m < n) ? m : n;for (int i = min; i >= 1; i--) {//for(int i = 1;i <= min;i++){if (m % i == 0 && n % i == 0) {printf("最大公约数是:%d\n", i); //公约数break; //跳出当前循环结构}}//需求2:最小公倍数//取出两个数中的较大值int max = (m > n) ? m : n;for (int i = max; i <= m * n; i++) {if (i % m == 0 && i % n == 0) {printf("最小公倍数是:%d\n", i);//公倍数break;}}return 0;
}

说明:

1、我们可以在循环中使用break。一旦执行break,就跳出当前循环结构。

2、小结:如何结束一个循环结构?

​ 结束情况1:循环结构中的循环条件部分返回false

​ 结束情况2:循环结构中执行了break。

3、如果一个循环结构不能结束,那就是一个死循环!我们开发中要避免出现死循环。

【华南理工大学2018研】有一个分数序列 2 / 1 , 3 / 2 , 5 / 3 , 8 / 5 , 13 / 8 , 21 / 13 , . . . 2/1,3/2,5/3,8/5,13/8,21/13,... 2/1,3/2,5/3,8/5,13/8,21/13,...,求这个数列的前20项之和。请在下面空白处填上适当语句。

int main(){  int i,n=20;  double a=2,b=1,s=0,t;  for(i=1;;i++){    s=;;   a=a+b;;  }  printf("sum=%16.10f\n",);  return 0;
} 

【答案】①i<=n②s+a/b③t=a④b=t⑤s

【解析】此程序循环是从=1开始,所以要计算数列前20项,则循环条件应为i<=n;s用来累加求和,所以每次进行累加操作,即s=s+a/b;通过分析数列可知,数列中分子是上一项的分子分母之和,而分母是上一项的分子,依照此关系可以通过中间变量t进行换算,最后输出所求结果s。

【华南理工大学2018研】从键盘输入10个整数,编程求其中大于3且小于100的数的平均值并输出结果。

【答案】
此题可以先利用循环从屏幕读取10个数,然后依次判断数值是否大于3且小于100的数,最后取平均值进行输出,程序如下:

#include<stdio.h>
int main() {int n = 10;int num; //输入的整数int sum=0; //记录总和int count=0;//记录个数for(int i = 1;i <= n;i++){scanf("%d",&num);if(num > 3 && num < 100){sum += num;count++;}}
//    printf("%d\n",sum);
//    printf("%d\n",count);printf("%d\n",sum / count);return 0;
}

2.5 循环结构之2:while循环

2.5.1 基本语法

语法格式:

①初始化部分
while(②循环条件部分){③循环体部分;④迭代部分;
}

**执行过程:**①-②-③-④-②-③-④-②-③-④-…-②

图示:

image-20240107125105170

说明:

  • while(循环条件部分)中循环条件为非零值,表示真;为零值,表示伪。
  • 注意不要忘记声明④迭代部分。否则,循环将不能结束,变成死循环。
  • for循环和while循环可以相互转换。二者没有性能上的差别。实际开发中,根据具体结构的情况,选择哪个格式更合适、美观。
  • for循环与while循环的区别:初始化条件部分的作用域不同
2.5.2 举例

**案例1:**输出5行HelloWorld!

int main() {int i = 1;while (i <= 5) {printf("Hello World!\n");i++;}return 0;
}

**案例2:**遍历1-100的偶数,并计算所有偶数的和、偶数的个数(累加的思想)

int main() {//遍历1-100的偶数,并计算所有偶数的和、偶数的个数(累加的思想)int num = 1;int sum = 0;//记录1-100所有的偶数的和int count = 0;//记录1-100之间偶数的个数while (num <= 100) {if (num % 2 == 0) {printf("%d\n", num);sum += num;count++;}//迭代条件num++;}printf("偶数的总和为:%d\n", sum);printf("偶数的个数为:%d\n", count);return 0;
}

案例3:折纸珠穆朗玛峰

世界最高山峰是珠穆朗玛峰,它的高度是8848.86米,假如我有一张足够大的纸,它的厚度是0.1毫米。
请问,我折叠多少次,可以折成珠穆朗玛峰的高度?
int main() {//定义一个计数器,初始值为0int count = 0;//定义珠穆朗玛峰的高度int zf = 8848860;//单位:毫米double paper = 0.1;//单位:毫米while (paper < zf) {//在循环中执行累加,对应折叠了多少次count++;paper *= 2;//循环的执行过程中每次纸张折叠,纸张的厚度要加倍}//打印计数器的值printf("需要折叠:%d次\n", count);printf("折纸的高度为%f米,超过了珠峰的高度", paper / 1000);return 0;
}

【武汉科技大学2019研】如果有定义:int x=0,s=0; 则下面程序段的执行结果是(  )。

while(!x!= 0)  s+=x++;
printf("%d",s);

A.1
B.0
C.无限循环
D.控制表达式非法,无法编译

【答案】B

【解析】while后面的表达式中,首先执行!运算符,然后再执行!=运算符,第一次判断中,x=0则!x!=0满足条件,进入循环中,执行s += x++,x++是先运算,再自加,执行完后s=0,x=1,再回到while的判断条件,判断为false,跳出循环,输出s的值为0,答案选B。

2.6 循环结构之3:do-while循环

do-while 结构是 while 的变体,它会先执行一次循环体,然后再判断是否满足条件。如果满足的话,就继续执行循环体,否则跳出循环。

2.6.1 基本语法

语法格式:

①初始化部分;
do{③循环体部分④迭代部分
}while(②循环条件部分); 

**执行过程:**①-③-④-②-③-④-②-③-④-…-②

图示:

image-20240107125108895

说明:

  • do{}while();最后有一个分号
  • do-while结构的循环体语句是至少会执行一次,这个和for和while是不一样的
  • 循环的三个结构for、while、do-while三者是可以相互转换的。
2.6.2 举例

**案例1:**遍历1-100的偶数,并计算所有偶数的和、偶数的个数(累加的思想)

int main() {//遍历1-100的偶数,并计算所有偶数的和、偶数的个数(累加的思想)//初始化部分int num = 1;int sum = 0;//记录1-100所有的偶数的和int count = 0;//记录1-100之间偶数的个数do {//循环体部分if (num % 2 == 0) {printf("%d\n", num);sum += num;count++;}num++;//迭代部分} while (num <= 100); //循环条件部分printf("偶数的总和为:%d\n", sum);printf("偶数的个数为:%d\n", count);return 0;
}

**案例2:**体会do-while至少会执行一次循环体

int main() {//while循环:int num1 = 10;while (num1 > 10) {printf("hello:while\n");num1--;}//do-while循环:int num2 = 10;do {printf("hello:do-while\n");num2--;} while (num2 > 10);return 0;
}

案例3:ATM取款

声明变量balance并初始化为0,用以表示银行账户的余额,下面通过ATM机程序实现存款,取款等功能。=========ATM========1、存款2、取款3、显示余额4、退出
请选择(1-4):
int main() {//初始化条件double balance = 0.0;//表示银行账户的余额int selection; //记录客户的选择double addMoney, minusMoney; //分别记录存钱、取钱的额度int isFlag = 1;//用于控制循环的结束do {printf("=========ATM========\n");printf("\t1、存款\n");printf("\t2、取款\n");printf("\t3、显示余额\n");printf("\t4、退出\n");printf("请选择(1-4):");scanf("%d", &selection);switch (selection) {case 1:printf("要存款的额度为:");scanf("%lf", &addMoney);if (addMoney > 0) {balance += addMoney;}break;case 2:printf("要取款的额度为:");scanf("%lf", &minusMoney);if (minusMoney > 0 && balance >= minusMoney) {balance -= minusMoney;} else {printf("您输入的数据非法或余额不足\n");}break;case 3:printf("当前的余额为:%lf\n", balance);break;case 4:printf("欢迎下次进入此系统。^_^\n");isFlag = 0;break;default:printf("请重新选择!\n");break;}} while (isFlag);return 0;
}
2.6.3 小结:三种循环结构
  • 三种循环结构都具有四个要素:
    • 循环变量的初始化条件
    • 循环条件
    • 循环体语句块
    • 循环变量的修改的迭代表达式
  • 从循环次数角度分析
    • do-while循环至少执行一次循环体语句。
    • for和while循环先判断循环条件语句是否成立,然后决定是否执行循环体。
  • 如何选择
    • 遍历有明显的循环次数(范围)的需求,选择for循环
    • 遍历没有明显的循环次数(范围)的需求,选择while循环
    • 如果循环体语句块至少执行一次,可以考虑使用do-while循环
    • 本质上:三种循环之间完全可以互相转换,都能实现循环的功能

2.7 "无限"循环

image-20240107125113191

2.7.1 基本语法

语法格式:

  • 最简单"无限"循环格式:while(1) , for(;;)

适用场景:

  • 开发中,有时并不确定需要循环多少次,需要根据循环体内部某些条件,来控制循环的结束(使用break)。
  • 如果此循环结构不能终止,则构成了死循环!开发中要避免出现死循环。
2.7.2 举例

**案例1:**实现爱你到永远…

int main() {for (;;) {printf("我爱你!\n");}//printf("end\n");//永远无法到达的语句return 0;
}
int main() {for (int i = 1; i <= 10; ){ //循环变量没有修改,条件永远成立,死循环printf("我爱你!\n");}return 0;
}

思考:如下代码执行效果

int main() {for (int i = 1; i >= 10;) { //一次都不执行printf("我爱你!");}return 0;
}

**案例2:**从键盘读入个数不确定的整数,并判断读入的正数和负数的个数,输入为0时结束程序。

int main() {int positiveNumber = 0;//统计正数的个数int negativeNumber = 0;//统计负数的个数int num;  //记录输入的整数while(1){   //for (;;){printf("请输入一个整数(输入为0时结束程序):");scanf("%d", &num);if (num > 0) {positiveNumber++;} else if (num < 0) {negativeNumber++;} else {printf("程序结束\n");break;}}printf("正数的个数为:%d\n", positiveNumber);printf("负数的个数为:%d\n", negativeNumber);return 0;
}

2.8 嵌套循环(或多重循环)

2.8.1 使用说明
  • 所谓嵌套循环,是指一个循环结构A的循环体是另一个循环结构B。比如,for循环里面还有一个for循环,就是嵌套循环。其中,for ,while ,do-while均可以作为外层循环或内层循环。
    • 外层循环:循环结构A
    • 内层循环:循环结构B

image-20240107125116890

  • 实质上,嵌套循环就是把内层循环当成外层循环的循环体。只有当内层循环的循环条件为false(值为0)时,才会完全跳出内层循环,才可结束外层的当次循环,开始下一次的外层循环。
  • 设外层循环次数为m次,内层为n次,则内层循环体实际上需要执行m*n次。
  • **技巧:**从二维图形的角度看,外层循环控制行数,内层循环控制列数
  • **开发经验:**实际开发中,我们最多见到的嵌套循环是两层。一般不会出现超过三层的嵌套循环。如果将要出现,一定要停下来重新梳理业务逻辑,重新思考算法的实现,控制在三层以内。否则,可读性会很差。

例如:两个for嵌套循环格式

for(初始化语句①; 循环条件语句②; 迭代语句⑦) {for(初始化语句③; 循环条件语句④; 迭代语句⑥) {循环体语句⑤;}
}//执行过程:① - ② - ③ - ④ - ⑤ - ⑥ - ④ - ⑤ - ⑥ - ... - ④ - ⑦ - ② - ③ - ④ - ⑤ - ⑥ - ④..

**执行特点:**外层循环执行一次,内层循环执行一轮。

2.8.2 举例

**案例1:*打印5行6个

int main() {/********************************/for (int j = 1; j <= 5; j++) {for (int i = 1; i <= 6; i++) {printf("*");}printf("\n");}return 0;
}

**案例2:**打印5行直角三角形

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

**案例3:**打印5行倒直角三角形

		i	j(*的上限)   i + j = 6  --> j = 6 - i
*****   1	5
****	2	4
***		3	3
**		4	2
*		5	1
int main() {for (int i = 1; i <= 5; i++) {for (int j = 1; j <= 6 - i; j++) {printf("*");}printf("\n");}return 0;
}

案例4:九九乘法表

int main() {for (int i = 1; i <= 9; i++) {for (int j = 1; j <= i; j++) {printf("%d*%d=%d\t", i, j, i * j);}printf("\n");}return 0;
}

【北京航空航天大学2018研】对于下列for循环语句,请将其改写为功能完全相同的while循环语句。

int i,j,count=0;
for(i=0;i<100;i++){  
for(j=100;j>=i;j-=2)  {    
count+=j-i;  
}
} 

【答案】
此题可以在定义时先令i=0,j=100,在第一层while循环时只需判断i<100即可,在第二层while循环时只需判断j>=i即可,j-=2放在内层循环体中即可,具体程序如下:

int i=0, j=100, count=0;
while(i<100){  
while(j>=i)  {    
count+=j-i;    
j-=2;  
}  
i++;
} 

2.9 break和continue关键字

2.9.1 使用说明
关键字适用范围循环结构中的作用相同点
breakswitch-case--
break循环结构一旦执行,就结束(或跳出)当前循环结构此关键字的后面,不能声明语句
continue循环结构一旦执行,就结束(或跳出)当次循环结构此关键字的后面,不能声明语句

代码验证:

int main() {for (int i = 1; i <= 10; i++) {if (i % 4 == 0) {break;//123//continue;//123567910//如下的语句不可能被执行!//printf("今晚迪丽热巴要约我吃饭");}printf("%d", i);}printf("\n####\n");//嵌套循环中的使用for (int i = 1; i <= 4; i++) {for (int j = 1; j <= 10; j++) {if (j % 4 == 0) {break; //结束的是包裹break关键字的最近的一层循环!//continue;//结束的是包裹break关键字的最近的一层循环的当次!}printf("%d", j);}printf("\n");}return 0;
}
2.9.2 举例

举例1:在全系1000名学生中举行慈善募捐,当总数达到10万元时就结束,统计此时捐款的人数以及平均每人捐款的数目。

#include <stdio.h>#define SUM 100000 //指定符号常量SUM代表10万//在全系1000名学生中举行慈善募捐,当总数达到10万元时就结束,统计此时捐款的人数以及平均每人捐款的数目。
int main() {double amount, total = 0;//分别代表着每人捐款的数额,总捐款额int count = 0; //捐款人数for (int i = 1; i <= 1000; i++) {printf("请输入你的捐款额:");scanf("%lf", &amount);total = total + amount;count++;if (total >= SUM)break;}double aver = total / count; //人均捐款额度printf("捐款总人数是:%d\n人均捐款额为:%10.2f\n", count, aver);return 0;
}

举例2:要求输出100~200之间的不能被3整除的数。

int main() {int n;for (n = 100; n <= 200; n++) {if (n % 3 == 0)continue;printf("%d ", n);}printf("\n");return 0;
}

【华南理工大学2018研】编程求100~200间的全部素数。

【答案】
素数意思是只能被1和本身整除,因此将1到本身之间的数做除数,进行求余,如果余数为0,则不是素数,否则是素数。根据经验,假设所要判断的数为n,则一般只需要判断1到根号n之间的数即可,具体程序如下:

#include <stdio.h>
#include<math.h>int main() {int count = 0; //记录是否有约数for (int i = 100; i <= 200; i++) {for (int j = 2; j <= sqrt(i); j++) {if (i % j == 0){count++;break;}}if (count == 0)printf("%d\n", i);count = 0;}
}

【武汉科技大学2019研】以下正确的描述是(  )。
A.从多层循环嵌套中退出时,只能使用break语句
B.在循环体内使用continue和break语句,作用相同
C.只能在循环体内和switch体内使用break语句
D.continue语句的作用是结束整个循环的执行

【答案】C

【解析】从多层嵌套中退出不是只能使用break语句,也可以使用return或者程序自己执行完,A错误;在循环体内continue代表不执行该次循环中的剩余未执行语句,break代表直接跳出本层循环,BD错误,答案选C。

【北京航空航天大学2018研】以下关于循环语句的叙述中,正确的是(  )。
A.for循环语句的三个部分必须都要有表达式
B.while循环语句的循环体内至少要有一条语句
C.do…while循环语句的循环体至少会被执行一次
D.continue语句可以退出包含它的整个循环体

【答案】C

【解析】for循环的三个表达式都可以省略,但是之间的分号不能省略,同时要有退出循环的机制,因此A项错误;while循环语句的循环体内可以为空,并不违反相应语法,只不过循环什么也不执行,因此B项错误;continue语句只是不执行本次循环的剩余语句,而并非退出整个循环,因此D项错误,答案选C。

2.10 goto关键字

使用goto,可以实现无条件的语句的转移。

一般格式:

goto 标号;

其中,标号,属于标识符,以“:”为标记,位于某语句前面。

执行 goto 语句后,程序将跳转到指定标号处执行。这样可以随意将控制转移到程序中的任意一条语句上,然后执行它。

举例1:

int main() {loop_label:printf("Hello, world!\n");goto loop_label;return 0;
}

loop_label是一个标签名,可以放在正常语句的前面。程序执行到 goto 语句,就会跳转到它指定的标签名位置继续执行。因此,上面的代码会产生无限循环。

实际使用中,goto语句通常与条件语句配合。可用来实现条件转移,跳出循环体等功能。

**举例2:**录入学生成绩,并计算学生的平均分。当输入-1时程序结束。

int main() {int score, i = 0, sum = 0;next:printf("请输入第 %d 个学生成绩(输入-1结束):", i+1);scanf("%d", &score);if (score != -1) {sum += score;i++;goto next;}if (i != 0)printf("%d个学生的平均分是 %d\n",i, sum / i);return 0;
}

注意:goto 只能在同一个函数之中跳转,并不能跳转到其他函数。

**举例3:**goto 的一个主要用法是跳出多层循环

for(...) {for (...) {while (...) {do {if (some_error_condition)goto bail;    } while(...);}}
}bail:
// ... ...

上面代码有很复杂的嵌套循环,不使用 goto 的话,想要完全跳出所有循环,写起来很麻烦。

**举例4:**goto 的另一个用途是提早结束多重判断

if (do_something() == ERR)goto error;
if (do_something2() == ERR)goto error;
if (do_something3() == ERR)goto error;
if (do_something4() == ERR)goto error;

上面示例有四个判断,只要有一个发现错误,就使用 goto 跳过后面的判断。

小结:

从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。使用goto反而容易造成程序流程的混乱,致使程序容易出错。故建议不要轻易使用。

这里只是为了语法的完整,介绍一下它的用法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/604433.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSS基础笔记-04cascade-specificity-inheritance

CSS基础笔记系列 《CSS基础笔记-01CSS概述》《CSS基础笔记-02动画》CSS基础笔记-03选择器 前言 Cascading Style Sheets&#xff0c;关键就在于这个cascading&#xff0c;对于这个术语理解&#xff0c;感觉对于我这种CSS新手有点儿不太friendly。本文记录下我对这个术语的理…

互联网分布式应用之SpringCloud

SpringCloud Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. 微服务项目介绍 2. Eure…

kafka-zookeeper集群架构可视化监控,Kafka-Eagle安装部署

1、简介 在 kafka-zookeeper 集群架构下&#xff0c;zookeeper 管理 kafka 的元数据信息&#xff0c;如何监控这些信息&#xff0c;并且能够直观查看和管理 kafka 一些具体 主题、分区等参数信息&#xff0c;是非常便于开发的&#xff0c;因此 Kafka-Eagle 是一个为监控 kafka …

基于机器视觉的车牌检测-边缘检测因子的选择

车牌检测概述 车牌识别在检测报警、汽车出入登记、交通违法违章以及移动电子警察方面应用广泛。车牌识别过程为&#xff1a;首先通过摄像头获取包含车牌的彩色图像&#xff1b;然后进行车牌边缘检测&#xff0c;先粗略定位到车牌位置&#xff0c;再精细定位&#xff1b;最后根…

[AutoSar]基础部分 RTE 05 Port的实例化和初始化

目录 关键词平台说明一、端口类型二、端口的实例化2.1 创建application port2.2 实例化 三、初始化 关键词 嵌入式、C语言、autosar、Rte 平台说明 项目ValueOSautosar OSautosar厂商vector芯片厂商TI编程语言C&#xff0c;C编译器HighTec (GCC) 一、端口类型 如下图所示&am…

MvvmToolkit的使用

背景&#xff1a;MvvmLight不更新了&#xff0c;用Toolkit代替 1、首先下载好社区版本的NuGet包 2、ViewModel中需要继承ObservableObject&#xff0c;查看ObservableObject可以看到里面有实现好InotifyPropertyChanged。 3、对于属性的set&#xff0c;可以简写成一行&#xff…

鸿蒙应用开发 闹钟实现

后台代理提醒简介 随着生活节奏的加快&#xff0c;我们有时会忘记一些重要的事情或日子&#xff0c;所以提醒功能必不可少。应用可能需要在指定的时刻&#xff0c;向用户发送一些业务提醒通知。例如购物类应用&#xff0c;希望在指定时间点提醒用户有优惠活动。为满足此类业务…

PTA——L2-041 插松枝(25分、模拟题)

文章目录 一、题目二、题解1.基本思路&#xff1a; 一、题目 人造松枝加工场的工人需要将各种尺寸的塑料松针插到松枝干上&#xff0c;做成大大小小的松枝。他们的工作流程&#xff08;并不&#xff09;是这样的&#xff1a; 每人手边有一只小盒子&#xff0c;初始状态为空。…

C++与数据库MySQL锁——模拟订票(事务)

假设订票的时候&#xff0c;好几个人同时进入&#xff0c;查看这张票是否售出&#xff0c;假如同时购买了这张票&#xff0c;那对于售票行业来说&#xff0c;可能就会发生低级错误。那么如何避免这类事情发生呢&#xff1f; 解决办法&#xff1a; 在一个人访问的时候&#xf…

HCIA-Datacom题库(自己整理分类的)_11_其他网络协议单选【9道题】

1.DNS协议的主要作用是&#xff1f; 文件传输 远程接入 域名解析 邮件传输 2.下列属于链路状态协议的是? Direct static FTP OSPF 解析&#xff1a; FTP&#xff1a;文件传输协议 OSPF&#xff1a;链路状态路由协议 3.如下图所示的网络主机A通过Telnet登录到路由…

Hystrix熔断/断路器

简介 Hystrix是一个用于处理分布式系统的延迟和容错的开源库&#xff0c;在分布式系统里&#xff0c;许多依赖不可避免的会调用失败&#xff0c;比如超时、异常等&#xff0c;Hystrix能够保证在一个依赖出问题的情况下&#xff0c;不会导致整体服务失败&#xff0c;避免级联故…

MyBatisPlus学习一:快速入门

前言 前面快速学习了Mybatis&#xff0c;现在开始快速学习MyBatisPlus 学习教程&#xff1a; 黑马mybatis教程全套视频教程&#xff0c;2天Mybatis框架从入门到精通 黑马程序员最新MybatisPlus全套视频教程&#xff0c;4小时快速精通mybatis-plus框架 简介 MyBatisPlus 是…

提升软件质量与效率:UI自动化测试的重要性

在软件开发领域&#xff0c;UI自动化测试工具被广泛应用&#xff0c;其意义不仅仅体现在节省时间和资源上&#xff0c;更关系到软件质量的提升、团队效率的增加&#xff0c;以及用户体验的改善。本文将探讨使用UI自动化测试工具的重要性&#xff0c;以及它在软件开发生命周期中…

【基础工具篇使用】VScode 远程 Ubuntu 系统 进行使用

文章目录 准备条件使用步骤step1&#xff1a; 打开远程窗口step2&#xff1a;选择中的红色框“Connect to Host”功能Step3: 根据图中的红色框提示信息输入远程电脑的用户名和 IP 地址&#xff0c;输入如下命令即可连接&#xff1a; 显示效果 准备条件 我们可以使用 vscode 的…

【idea】解决sprintboot项目创建遇到的问题2

本篇是继【idea】解决sprintboot项目创建遇到的问题_java.lang.illegalargumentexception: unable to inst-CSDN博客 目录 一、Dependency com.mysql:mysql-connector-j: not found 二、Could not find artifact org.springframework.boot:spring-boot-maven-plugin:pom:4.0…

LCD—液晶显示

本节主要介绍以下内容 显示器简介 液晶控制原理 秉火3.2寸液晶屏简介 使用FSMC模拟8080时序 NOR FLASH时序结构体 FSMC初始化结构体 一、显示器简介 显示器属于计算机的I/O设备&#xff0c;即输入输出设备。它是一种将特定电子信息输出到屏幕上再反射到人眼的显示工具。…

linux创建pyspark虚拟环境

一、创建虚拟环境 conda create -n test python3.6.6 二、注意添加镜像 vi /root/.condarc channels:- http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/- http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/- http://mirrors.ustc.edu.cn/anaconda/pkgs/ma…

【AI视野·今日NLP 自然语言处理论文速览 第六十九期】Wed, 3 Jan 2024

AI视野今日CS.NLP 自然语言处理论文速览 Wed, 3 Jan 2024 Totally 24 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers An Autoregressive Text-to-Graph Framework for Joint Entity and Relation Extraction Authors Zaratiana Ur…

STM32_HAL Freertos按键控制LED

设置GPIO引脚 根据电路图&#xff0c;K0为用户按键&#xff0c;连接在PA0引脚&#xff0c;当K0按下时接地&#xff0c;引脚电平低电平。在CubeMX中设置PA0&#xff0c;将IO设置为输入&#xff0c;上拉&#xff08;上拉外部悬空时&#xff0c;引脚为高电平&#xff09;。 添…

大学物理实验重点——交直流电桥

直流电桥 惠斯通电桥 平衡条件&#xff1a; 非平衡电桥 为了测量的准确性&#xff0c;在测量的起始点&#xff0c;电桥必须调至平衡&#xff08;&#xff09;&#xff0c;称为预调平衡。这样可使输出只与某一臂电阻变化有关。 平衡时 若 R1、 R2 、 R3 固定&#xff0c; R4 为…