流程控制
什么是流程控制
程序代码执行的顺序
流程控制的分类
顺序
选择
定义
某些代码可能执行,也可能不执行,有选择的执行某些代码
分类
if
if最简单的用法
语法:
if(表达式)
语句;
功能:
如果表达式为真,执行语句
如果表达式为假,语句不执行
1 # include <stdio.h> 2 3 int main() 4 { 5 if (3>2) 6 printf("aaaa\n");//输出结果为aaaa 7 8 if (0) 9 printf("bbbb\n");//不会输出结果,因为if表达式内的结果为假 10 11 if (0 == 0) 12 printf("cccc\n"); //输出结果为bbbb 13 return 0; 14 }
if的范围问题
-
if(表达式)
语句A;
语句B;
解释:
if默认只能控制语句A的执行或不执行 if无法控制语句B的执行或不执行
或者讲:语句B一定会执行
-
if(表达式)
{
语句A;
语句B;
}
此时if可以控制语句A和语句B
由此可见:if默认只能控制一个语句的执行或者不执行
如果想控制多个语句的执行或者不执行,就必须把这些语句使用{}括起来
1 # include <stdio.h> 2 3 int main() 4 { 5 if(1>2) 6 printf("AAAA\n"); 7 printf("BBBB\n"); 8 printf("CCCC\n"); 9 10 return 0; 11 } 12 /* 13 在Dev-C++ 5.11中的输出结果是: 14 ------------------------------ 15 BBBB 16 CCCC 17 ------------------------------ 18 总结: 19 if默认只能控制语句A的执行或不执行 20 if无法控制语句B的执行或不执行 21 */
if...else...的用法
if...else if...else...的用法
语法:
if(1)
A;
else if (2)
B;
else if (3)
C;
else
D;
解释:如果1不满足,那么编译器就会到下一步判断2是否满足,如果不满足,继续向下判断,直至输出为止;
如果输出语句为D,表示1,2,3的表达式都为0
1 # include <stdio.h> 2 3 int main() 4 { 5 double delta = 0;//第一条语句 6 7 if (delta>0) 8 printf("有两个解\n");//第二条语句 9 printf("haha\n");//第三条语句 编译会出错,因为从整体来看这是5个语句,如果上一条语句表达式为0,那么输出此条语句,编译器会发现下一条语句不符合语法,因为没有else开头的语法 10 else if(delta == 0) 11 printf("有一个唯一的解\n"); 12 else 13 printf("无解");//第四条语句 14 15 return 0;//第五条语句 16 }
C语言对真假的处理
非零是真 真用1表示
零就假 假用0表示
if举例--求分数的等级
1 # include <stdio.h> 2 3 int main() 4 { 5 float score; 6 7 printf("请输入您的考试成绩:"); 8 scanf("%f",&score); 9 10 if(score>100) 11 printf("你想的太美了!"); 12 else if(score>90 && score<=100) 13 printf("太厉害了"); 14 else if(score>80 && score<=90) 15 printf("优秀"); 16 else if(score>70 && score<=80) 17 printf("良好"); 18 else if(score>60 && score<=70) 19 printf("还行") ; 20 else if(score>=0 && score<=60) 21 printf("还需要努力"); 22 else 23 printf("成绩无效,请重新输入成绩"); 24 return 0; 25 }
数值互换
1 # include <stdio.h> 2 3 int main() 4 { 5 int i = 3; 6 int j = 4; 7 int k; //定义一个寄存器 8 9 k = i;//转换之前,先寄存,然后在互换 10 i = j; 11 j = k; 12 13 printf("i = %d j = %d",i, j); 14 15 return 0; 16 }
对任意三个数字进行排序
1 # include <stdio.h> 2 3 int main() 4 { 5 int a, b, c; 6 int d;//定义一个变量用来存储中间值 7 8 printf("请输入三个整数:"); 9 scanf("%d %d %d", &a, &b, &c); 10 11 if(a<b)//如果a的值最大就不需要比较,直接输出就行,第二种情况是如果a<b,就将a,b的值互换 12 { 13 d = a; 14 a = b; 15 b = d; 16 } 17 18 if(a<c)//第三种情况是a<c,将a,b的值互换,这样a的值就是最大的值了 19 { 20 d = a; 21 a = c; 22 c = d; 23 } 24 25 if(b<c)//a的值已经是最大值,然后看b的值,如果b>c,那么不要转换,直接输出就行,如果b<c,就将b,c的值互换,这样b的值就是第二大的值了,然后c就成了最小值,照常输出就行了 26 { 27 d = b; 28 b = c; 29 c = d; 30 } 31 32 printf("%d %d %d",a, b, c); 33 34 return 0; 35 }
if的常见问题解析
-
空语句的问题
if ( 3 > 2 );
等价于
if ( 3 > 2 )
;//这是一个空语句
-
if(表达式1)
A;
else
B;
是正确的
if (表达式1);//if添加分号,表明这是一个空语句,然后else没有对应的if,在编译过程中会报错
A;
else
B;
-
if(表达式1)
A;
else if(表达式2)
B;
else if(表达式3)
C;
else
D;
即便表达式1和2都成立,也只会执行A语句
-
if(表达式1)
A;
else if(表达式2)
B;
else if(表达式3)
C;
没有添加else,编译器不会报错,但逻辑上存在漏洞
-
if(表达式1)
A;
else if(表达式2)
B;
else if(表达式3)
C;
else(表达式4)
D;
这样写是不对的,编译器会报错,正确的写法是要么去掉表达式4,要么在else后面添加if
-
if(表达式1)
A;
else if(表达式2)
B;
else if(表达式3)
C;
else if(表达式4);
D;
这样写语法不会出错,但逻辑上是错误的,因为表达式4无实际意义
1 # include <stdio.h> 2 3 int main() 4 { 5 if(3>2) 6 printf("AAAA"); 7 else if(2>5) 8 printf("BBBB"); 9 else(4>2);//表达式无实际意义,不管是否成立,均不会输出 10 printf("CCCC"); 11 12 return 0; 13 }
switch
格式
switch (表达式)
{ case 常量表达式1: A; case 常量表达式2: B;
....
case 常量表达式3: C;
default: N; }
例子
1 # include <stdio.h> 2 3 int main() 4 { 5 int val; 6 7 printf("请您输入要进入的楼层:\n"); 8 scanf("%d", &val); 9 10 switch(val) 11 { 12 case 1: 13 printf("1层开!\n"); 14 break; 15 case 2: 16 printf("2层开!\n"); 17 break; 18 case 3: 19 printf("3层开!\n"); 20 break; 21 default://如果以上都不执行,则执行此语句 22 printf("还没有盖到这层!\n"); 23 break; 24 } 25 26 return 0; 27 } 28 /* 29 在没有break情况下: 30 可以将case 常量表达式比作入口,编译器会将switch中的val值进行对比,如果匹配,它就会从对应入口进入,然后从上往下一次执行,例如val==1,那么输出为1层开!2层开!3层开!还没有盖到这层!如果val==2,那么输出为2层开!3层开!还没有盖到这层! 31 有break情况下: 32 例如val==1,那么输出为1层开!因为程序执行到break,会跳出switch,不会再执行下面的语句 33 */
case穿透现象:
switch语句会根据表达式的值从相匹配的case标签处开始执行,一直执行到break语句处或者是switch语句的末尾。如果没有break语句那么就会从表达式的值相匹配的case标签处开始执行,一直执行到switch语句的末尾这种从其中一个case处开始,忽略后面的值的匹配,直接运行case的内容的现象就是穿透的现象。
功能
判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。
所有case后面的常量表达式为便于描述我们姑且称之为标签,这些标签都只能是:
-
枚举常量(有些书称之为枚举元素)
-
数值常量(也就是1, 2, 3, ....)
-
字符常量(例:A, B, C....)
-
常变量
-
宏名中的一种,注意普通变量,枚举变量是不能作为标签使用的
switch后面括号里的表达式可以任意类型
循环
定义
某些代码会被重复执行
分类
for
格式:
for(1; 2; 3)
语句A;
执行的流程【重点】
单个for循环的使用
1 # include <stdio.h> 2 3 int main() 4 { 5 int i; 6 int sum = 0;//给sum赋值进行初始化,防止有垃圾值 7 8 for(i = 1;i<=5; ++i) 9 sum = sum + i; 10 11 printf("sum = %d\n",sum); 12 13 return 0; 14 } 15 /* 16 for循环运行的流程步骤 : 17 假设i = 1;是第一步,i<=5;是第二步,++i是第三步, sum = sum + i; 是第四步, printf("sum = %d\n",sum);是第五步 18 1.当程序运行到for循环,执行第一步将1赋值到i(只执行一次),第二步满足 ,开始执行第四步,sum的初始为0加 上i值1,然后将结果赋值到sum中,开始执行第三步(意味的一次循环的结束) ,i的值自增后等于 2, 19 2.然后判断第二步(表达式满足,执行for的语句,否则退出循环),i<=5,执行for语句,也就是第四步,然后执行第 三步,以此类推,直至第二步不满足,退出循环。 20 3.然后将结果打印出来,执行第五步 21 */
多个for循环的使用
1 /* 2 for(1; 2; 3) 3 for(4; 5; 6) 4 A; 5 B; 6 执行的步骤是: 7 这一共是两个语句,第二个for循环包含语句A,然后把它当成一个整体,所以第一个语句为第一个for与它所控制的语句,也就是前面的那个整体,第二语句为B 8 首先,先执行1,然后执行2,如果2成立,执行4,执行5,如果5成立,执行A,然后执行6,在执行5,如果5成立,执行A,执行6,执行5,如果5不成立,退出内循环。 9 开始执行3,执行2,如果2成立,执行4,执行5,如果5成立,执行A,执行6,执行5,如果5不成立,退出内循环。 10 执行3,执行2,如果2不成立,退出外循环。 11 执行B 12 13 */
范围问题
for循环只能控制一个语句,如果想控制多个语句,需要用{}括起来
举例:
1 /*1到100之间能被3整除的数之和 */ 2 # include <stdio.h> 3 4 int main() 5 { 6 int i; 7 int sum = 0; 8 9 for(i=3;i<=10;i++) 10 { 11 if(i%3==0) 12 sum = sum + i;//需重点记忆的是:for与if一样只能控制一个语句 13 14 printf("sum = %d\n",sum); 15 } 16 17 return 0; 18 } 19 //输出结果为: 20 sum = 3 21 sum = 3 22 sum = 3 23 sum = 9 24 sum = 9 25 sum = 9 26 sum = 18 27 sum = 18
强制类型转化
格式:
(数据类型)(表达式)
功能:
把表达式的值强制转化为前面所执行的数据类型
例子:
(int)(4.5+2.2)最终值是6
(float)(5) 最终值是5.000000
试数详细步骤举例
原则:
-
编译器如何执行,自己就怎么写到纸上,不要问为什么(不需要知道语句什么功能,把自己当做计算机)
-
不要遗漏步骤
-
格式详细
1 # include <stdio.h> 2 3 int main() 4 { 5 int i; 6 float sum = 0; 7 8 for(i=1;i<101;i++) 9 sum = sum + 1/(float)(i); 10 //sum = sum + (float)(1/i);这样写是不对,因为 (1/i)值是整数,强制转换为浮点数还是相当于整数 11 //更简单的写法是sum = sum + 1.0/i; 12 13 printf("sum=%f",sum); 14 15 return 0; 16 } 17 /* 18 1-> i=1 1<=100成立 19 sum=0+1/1.0=1 ++i i=2 20 2-> i=2 2<=100成立 21 sum=1+1/2.0 ++i i=3 22 3-> i=3 3<=100成立 23 sum=1+1/2.0+1/3.0 ++i i=4 24 ....... 25 */
浮点数的存储所带来的问题
float和double都不能保证可以把所有的实数都准确的存储一个小数
举例:
有一个浮点型变量x,如何判断x的值是否是零
if(|x-0.000001|<0.000001)
是零
else
不是零
为什么循环中更新的变量不能定义为浮点型
因为浮点型数字存储会出现误差,造成在循环中出现不是理想中的状态
++ 自增 -- 自减
例:
int a = 3;
int b = a++;//后自增
int c = ++a;//前自增
a,b,c输出结果为3,3,5
上面的代码相当于
int a = 3;
int b = a++;执行完这行代码后,先给b赋值,再自增
//a++ a=a+1
//a++ a=a+1
int c = ++a;执行完这行代码前,先自增,再给c赋值
a,b,c输出结果为3,3,5
为什么会出现自增
-
代码更精炼
-
自增的速度更快
学习自增要明白的几个问题
-
我们编程时应该尽量屏蔽掉前自增和后自增的差别
-
自增表达式最好不要作为一个更大的表达式的一部分来使用或者说i++和++i单独成一个语句,不要把它作为一个完整复合语句的一部分来使用
例:
int m = i++ + ++i + i + i ++;//这样写不但是不规范的代码而且是不可移植的代码
printf("%d %d %d",i++, ++i, i)
三目运算符
A ? B : C
等价于
if(A)
B;
else
C;
逗号表达式
格式:
(A, B, C, D)
功能:
从左到右执行,最终表达式的值是最后一项的值
1 # include <stdio.h> 2 3 int main() 4 { 5 int i; 6 int j = 3; 7 8 i = (j++, ++j, j+2, j-3);//逗号是顺序点,执行顺序点之前前面的语句已经生效 9 printf("%d\n",i); 10 11 return 0; 12 }
while
执行顺序
格式:
while(表达式)
语句;
功能:while表达式成立执行语句,否则退出循环
与for的相互的比较
for与while可以相互转化
for(1;2; 3)
A;
等价于
1;
while(2)
{
A;
3;
}
while和for可以相互转化,但for的逻辑性更强,更不容易出错,推荐多使用for
举例
判断一个是否是回文数(输入一个数字将其从右往左组合成一个新的数字与输入的数字的值相等)
1 # include <stdio.h> 2 3 int main() 4 { 5 int m; 6 int val; 7 int sum = 0; 8 9 printf("请输入您要判断的数据:"); 10 scanf("%d",&val); 11 12 m = val; 13 while(m) 14 { 15 sum = sum * 10 + m%10; 16 m/=10; 17 } 18 19 if(sum == val) 20 printf("Yes%\n"); 21 else 22 printf("No%\n"); 23 24 return 0; 25 } 26 /* 27 假设输入一个数字为1234,那么它的运算流程如下: 28 1. m=1234 成立 29 sum=0*10+1234%10=4 30 m/=10 等价于 m=m/10=1234/10=123 31 2. m=123 成立 32 sum=4*10+123%10=43 33 m/=10=123/10=12 34 3. m=12 成立 35 sum=43*10+12%10=432 36 m=12/10=1 37 4. m=1 成立 38 sum=432*10+1/%10=4321 39 最终sum=4321 40 */
斐波那契数列
1 /*1 2 3 5 8 13 ....,从第3项开始,任意的一项的和都等于前两项之和*/ 2 # include <stdio.h> 3 4 int main() 5 { 6 int f1, f2, f3;//定义斐波那契数列的第一项和第二项及输出项的存储变量 7 int i;//定义循环初始值 8 int n;//定义输入项的变量 9 f1 = 1; 10 f2 = 2; 11 12 printf("请输入您想要的斐波那契数列的项数:"); 13 scanf("%d",&n); 14 15 if(n==1) 16 f3 = 1; 17 else if(n==2) 18 f3 = 2; 19 else 20 { 21 for(i=3; i<=n; ++i) 22 { 23 f3 = f1+f2; 24 f1 = f2; 25 f2 = f3; 26 } 27 28 } 29 printf("%d\n",f3); 30 31 return 0; 32 }
什么时候使用while,什么时候使用for
没法说,用多了自然而然就知道了
do...while
格式
do
{
....
}while(表达式);
do...while并不等价于for,当然也不等价于while
-
while先判断后执行,do...while是先执行后判断
-
do...while总是保证循环体会至少执行一次!这是他们的主要差别。
功能:
主要用于人机交互
例子:一元二次方程
1 # include <stdio.h> 2 # include <math.h> 3 int main() 4 { 5 double a, b, c;//定义3个系数 6 double delta;//定义求根公式 7 double x1, x2;//定义两个解的变量 8 char cha;// 9 10 do 11 { 12 printf("请您输入一元二次方程a,b,c三个系数的值:\n"); 13 14 printf("a = "); 15 scanf("%lf",&a); 16 17 printf("b = "); 18 scanf("%lf",&b); 19 20 printf("c = "); 21 scanf("%lf",&c); 22 23 delta = b*b - 4*a*c; 24 25 26 if(delta>0) 27 { 28 x1 = (-b + sqrt(delta)) / (2*a); 29 x2 = (-b - sqrt(delta)) / (2*a); 30 printf("有两个不同的解,x1=%lf x2=%lf\n",x1,x2); 31 } 32 else if(delta==0) //建议写成0==delta,防止少写一个等号,变成赋值 33 { 34 x1 = (-b) / (2*a); 35 x2 = x1; 36 printf("有一个解,并且相同,x1=%lf x2=%lf\n",x1,x2); 37 } 38 else 39 printf("无解\n"); 40 41 printf("您是否想继续运算,继续请输入Y,退出按任意键\n"); 42 scanf(" %c",&cha); //%c前面必须得加一个空格,原因是空白符的问题,具体得看C Primer Plus 43 44 } while('Y'==cha||'y'==cha); 45 46 return 0; 47 }