【有条件执行语句】
if esle 语句
if else 语句根据一个条件确定是否执行一段代码,执行条件是一个布尔值,布尔值为true则执行,为false则不执行,同时可以设置不符合条件时执行的语句。
if(执行条件)
{
符合条件时执行的代码;
}
else
{
不符合条件时执行的代码;
}
使用事项:
1.执行条件可以直接使用一个布尔数据,也可以是返回布尔值的运算式、函数,此时会首先执行一遍运算式或函数,之后使用其返回值当做执行条件。
2.若不需要在不符合条件时执行其它语句,可以省略else。
3.if和else内部代码可以有多个语句,若只有一个语句可以省略{}符号。
#include <stdio.h>
int main()
{
int a, b;
scanf("%d%d", &a, &b); //输入变量a、b的值
if(a < b)
{
printf("a小于b\n"); //输出判断结果
}
else
{
printf("a不小于b\n");
}
return 0;
}
if else 语句对应汇编代码如下:
401154: mov edx,DWORD PTR [rbp-0x4] ;变量a写入edx
401157: mov eax,DWORD PTR [rbp-0x8] ;变量b写入eax
40115a: cmp edx,eax ;比较a与b的关系
40115c: jge 40116a ;大于等于则跳转到else语句部分,小于则顺序执行if语句部分
40115e: mov edi,0x402009 ;if语句部分,将"a小于b\n"字符串地址写入edi传参
401163: call 401030 ;跳转到输出函数
401168: jmp 401174 ;if语句代码末尾,跳过else语句,执行之后的指令
40116a: mov edi,0x402012 ;else语句部分,将"a不小于b\n"字符串地址写入edi传参
40116f: call 401030 ;跳转到输出函数
401174: mov eax,0x0 ;return 0,设置main函数返回值
401179: leave ;还原栈空间
40117a: ret ;返回指令
某些情况下,编译器会进行以空间换时间的优化,此时if语句部分无需执行jmp指令跳过else语句部分,相当于转换为如下C代码:
#include <stdio.h>
int main()
{
int a, b;
scanf("%d%d", &a, &b);
if(a < b)
{
printf("a小于b\n");
return 0; //return用于终止函数
}
else
{
printf("a不小于b\n");
return 0;
}
}
嵌套 if else
if else 语句可以嵌套使用,从而进行多重条件判断,嵌套可以在if语句内、也可以在else语句内。
#include <stdio.h>
int main()
{
int a,b;
scanf("%d%d", &a, &b);
if(a<b)
{
printf("a小于b\n");
}
else
{
if(a>b)
{
printf("a大于b\n");
}
else
{
printf("a等于b\n");
}
}
return 0;
}
上述这种 if else 语句嵌套使用方式,可以使用如下简写形式:
#include <stdio.h>
int main()
{
int a,b;
scanf("%d%d", &a, &b);
if(a<b)
{
printf("a小于b\n");
}
else if(a>b)
{
printf("a大于b\n");
}
else
{
printf("a等于b\n");
}
return 0;
}
switch case 语句
switch case 语句用于在多组语句中选择一组符合条件的执行,找到符合条件的语句后不再判断其它条件,功能类似多个if语句嵌套并在每个if内使用goto语句跳出嵌套,但是使用 switch case 会让代码更简洁,并且编译器会对 switch case 进行一些优化,执行速度更快。
switch (整数变量)
{
case 整数常量:
执行代码段;
break;
case 整数常量:
执行代码段;
break;
case 整数常量:
执行代码段;
break;
default:
执行代码段;
break;
}
switch关键词之后设置一个变量,之后定义多个case语句,每个case语句设置一个常量,switch设置的变量会与case设置的常量进行比较,与哪个case常量相同就执行哪个case语句内代码段,若没有符合条件的case语句,则执行default语句内代码段,若不需要在不满足条件时执行另一段代码,default也可以省略。
注:case和default语句内代码段以break结尾,用于跳出switch语句,若没有设置break则会顺序执行此语句之后的代码,这将会导致逻辑混乱。
#include <stdio.h>
int main()
{
unsigned int a;
scanf("%u",&a); //输入a的值
switch(a)
{
case 0:
printf("输入值为0\n");
break;
case 1:
printf("输入值为1\n");
break;
case 2:
printf("输入值为2\n");
break;
case 3:
printf("输入值为3\n");
break;
default:
printf("输入值大于3\n");
break;
}
return 0;
}
以上switch语句对应的汇编代码如下:
401150: mov eax,DWORD PTR [rbp-0x4] ;变量a写入eax
401153: cmp eax,0x1 ;a与1比较
401156: je 401174 ;a等于1则跳转到case 1
401158: test eax,eax ;a与0比较
40115a: je 401168 ;a等于0则跳转到case 0
40115c: cmp eax,0x2 ;a与2比较
40115f: je 401180 ;a等于2则跳转到case 2
401161: cmp eax,0x3 ;a与3比较
401164: je 40118c ;a等于3则跳转到case 3
401166: jmp 401198 ;若没有满足条件的case语句,跳转到default
401168: mov edi,0x402007 ;case 0 语句
40116d: call 401030 ;终端输出函数
401172: jmp 4011a3 ;跳转到switch case语句之后的代码,此处为跳转到return 0
401174: mov edi,0x402015 ;case 1 语句
401179: call 401030
40117e: jmp 4011a3
401180: mov edi,0x402023 ;case 2 语句
401185: call 401030
40118a: jmp 4011a3
40118c: mov edi,0x402031 ;case 3 语句
401191: call 401030
401196: jmp 4011a3
401198: mov edi,0x40203f ;default 语句
40119d: call 401030
4011a3: mov eax,0x0 ;return 0
4011a8: leave
4011a9: ret
编译器使用了多个跳转指令,分别跳转到对应的case语句,当case语句过多时编译器会进行优化,将所有的case语句地址放在一个数组内(称为case地址表),之后使用switch设置的变量当做数组下标调用case地址表中的元素,从而减少跳转指令的使用量,具体细节这里不详细介绍,本文的重点是介绍C语言编程,而非C语言编译器。
条件运算式
条件运算式类似 if else 语句,但是条件运算式只能根据判断条件返回两个数据之一,此功能编译器可以进行一些优化,比使用 if else 语句执行速度更快。
条件 ? 数据1 : 数据2;
条件是一个布尔值,若为true则返回数据1,若为false则返回数据2。
#include <stdio.h>
int main()
{
int a,b;
printf("输入两个整数,判断最大值\n");
scanf("%d%d", &a, &b);
a = a>b ? a : b; //若a>b则返回a,否则返回b
printf("最大值为%d\n", a);
return 0;
}
条件运算式对应汇编代码:
40116e: mov edx,DWORD PTR [rbp-0x8] ;变量b写入edx
401171: mov eax,DWORD PTR [rbp-0x4] ;变量a写入eax
401174: cmp edx,eax ;比较b与a
401176: cmovge eax,edx ;若b>=a则将b写入eax,否则eax存储a
401179: mov DWORD PTR [rbp-0x4],eax ;eax写入变量a
【循环语句】
循环语句用于循环执行一段代码,循环条件是一个布尔值,若为true则循环一遍,为false则退出循环。
while 循环
while循环首先判断循环条件,之后确定是否执行循环。
while(循环条件)
{
循环代码段;
}
#include <stdio.h>
int main()
{
int a[] = {1,2,3,4,5};
int b = 0;
/* 遍历数组a */
while(b < 5)
{
printf("%d\n", a[b]);
b++;
}
return 0;
}
上述循环语句对应汇编代码如下:
40112a: mov DWORD PTR [rbp-0x20],0x1 ;数组a入栈存储
401131: mov DWORD PTR [rbp-0x1c],0x2
401138: mov DWORD PTR [rbp-0x18],0x3
40113f: mov DWORD PTR [rbp-0x14],0x4
401146: mov DWORD PTR [rbp-0x10],0x5
40114d: mov DWORD PTR [rbp-0x4],0x0 ;变量b赋值
401154: jmp 401177 ;跳转到循环条件判断语句
401156: mov eax,DWORD PTR [rbp-0x4] ;循环语句内部代码
401159: cdqe
40115b: mov edx,DWORD PTR [rbp+rax*4-0x20]
40115f: mov eax,DWORD PTR [rbp-0x4]
401162: mov esi,eax
401164: mov edi,0x402004
401169: mov eax,0x0
40116e: call 401030 ;输出函数
401173: add DWORD PTR [rbp-0x4],0x1 ;b++
401177: cmp DWORD PTR [rbp-0x4],0x4 ;循环条件判断语句
40117b: jle 401156 ;b小于等于4(等同于小于5)则向前跳转,实现循环
编译器进行了一个优化,将循环条件判断代码放在了末尾,这样可以少使用一个跳转指令,降低CPU分支预测失败率,等于转换成了 do while 循环。
嵌套 while
循环语句可以嵌套定义,比如遍历二维数组时就需要使用嵌套循环语句。
#include <stdio.h>
int main()
{
int a[3][5] =
{
{1,2,3,4,5},
{11,12,13,14,15},
{21,22,23,24,25}
};
int b = 0, c;
while(b < 3)
{
c = 0;
while(c < 5)
{
printf("%d,", a[b][c]);
c++;
}
printf("\n");
b++;
}
return 0;
}
有条件执行语句和循环语句也可以互相嵌套,在有条件执行语句内定义循环语句,或在循环语句内定义有条件执行语句。
无限循环
很多程序的工作就是无限循环,比如服务器端程序,不断的接收用户发送的网络数据,之后进行处理。
对于一些循环条件很复杂的有限循环,也可以使用无限循环代替,将循环条件放在循环语句内部,若满足条件则循环,否则执行break语句终止循环。
但是对于循环语句的某些终止条件由外界提供的情况,应该慎用无限循环,若出现意外情况可能会导致循环语句永远不会被终止,为了避免这种情况可以使用一个循环次数很大的有限循环代替无限循环,正常情况下不会执行如此多次的循环,即使循环语句最终没有使用break终止,也会因为循环次数达到上限而终止。
#include <stdio.h>
int main()
{
int a[] = {1,2,3,4,5};
int b = 0;
while(1) //循环条件固定为1
{
if(b > 4) break; //b>4则执行break语句终止循环
printf("%d\n", a[b]);
b++;
}
return 0;
}
for 循环
for循环是while循环的另一种使用方式,for将循环条件变量的定义、判断、修改放在一起,方便查看代码,所有的for循环都可以使用while循环代替。
for(循环条件变量; 循环条件判断; 循环条件修改)
{
循环代码段;
}
for循环使用说明:
1.循环条件变量,定义循环条件所用的变量,只会执行一次,相当于在for外部定义的一个变量,但是只能在for内部使用。
2.循环条件判断,循环条件变量参与的运算式,返回布尔值,若为true则执行一次循环,若为false则退出循环。
3.循环条件修改,修改循环条件变量的值。
#include <stdio.h>
int main()
{
int a[] = {1,2,3,4,5};
/* 变量i只定义一次,每次循环前首先判断i<5,每次循环后执行i++ */
for(int i = 0; i < 5; i++)
{
printf("%d\n", a[i]);
}
return 0;
}
有些古老的编译器不支持上述用法,需要使用如下形式:
#include <stdio.h>
int main()
{
int a[] = {1,2,3,4,5};
int i;
for(i = 0; i < 5; i++)
{
printf("%d\n", a[i]);
}
return 0;
}
for的无限循环形式:for(;;) { }
do while 循环
do while 循环语句将循环条件放在循环代码段之后,首先执行一遍循环代码,然后判断循环条件,若满足条件则继续循环,循环语句至少执行一次。
do
{
循环代码段;
}while(循环条件);
#include <stdio.h>
int main()
{
int a[] = {1,2,3,4,5};
int b = 0;
/* while定义在循环语句末尾,首先执行一次循环,之后判断循环条件 */
do
{
printf("%d\n", a[b]);
b++;
}while(b < 5);
return 0;
}
while 与 do while 的执行流程区别如下。
while循环语句执行顺序:
1.进入 while =》 满足条件 =》 不执行跳转,顺序执行一遍循环代码 =》 执行跳转,跳转到 while 起始地址
2.进入 while =》 不满足条件 =》 执行跳转,跳过 while
do while循环语句执行顺序:
1.进入 do while 直接执行循环代码 =》 满足条件 =》 执行跳转,跳转到 do while 起始地址
2.进入 do while 直接执行循环代码 =》 不满足条件 =》 不执行跳转,顺序执行 do while 之后的代码
在不满足循环条件时 while 会比 do while 多执行一个跳转指令,为了减少执行跳转指令,编译器会将 while 和 for 转换为 do while。
实际上之前介绍的 while 语句汇编代码已经转换为 do while,因为循环条件在编译期间即可确定成立,编译器判断循环语句至少会执行一次,若循环条件不能在编译期间确定是否为true,编译器也会将 while 转换为 do while,比如下面的代码。
#include <stdio.h>
int main()
{
unsigned int a;
scanf("%u", &a); //程序执行期间输入a的值
/* 变量a递减,直到a为0 */
while(a != 0)
{
printf("%d\n", a);
a--;
}
return 0;
}
编译器转换为如下代码:
#include <stdio.h>
int main()
{
unsigned int a;
scanf("%u", &a);
if(a != 0)
{
do
{
printf("%d\n", a);
a--;
}while(a != 0);
}
return 0;
}
【跳转语句】
break 跳转
break语句有两个作用:
1.终止循环语句,执行循环语句之后的代码,对于嵌套使用的循环,break只终止所在的这层循环。
2.跳过switch case语句,执行switch case之后的代码。
猜数字游戏代码:
#include <stdio.h>
int main()
{
int a=17, b=0; //a为用户要猜测的数据,b存储用户输入的数据
char x=0; //清空标准输入文件使用
printf("猜数字游戏,数据范围 0 - 100,请输入你认为的数据\n");
/* 无限循环 */
while(1)
{
scanf("%d", &b); //输入b的值
/* 清空标准输入文件,原因在C语言标准函数库一节中介绍 */
while(x != 10)
{
x = getchar();
}
x = 0;
if(b < a)
{
printf("太小了,请重新输入\n");
}
else if(b > a)
{
printf("太大了,请重新输入\n");
}
else
{
printf("猜对了,正确值是%d\n", a);
break; //用户输入正确数据后终止循环
}
}
return 0;
}
continue 跳转
continue语句用于终止循环语句的本次循环,执行下一次循环,一般与if语句配合使用,在满足条件时放弃本次循环。
#include <stdio.h>
int main()
{
int a[] = {1,2,3,4,5};
for(int i = 0; i < 5; i++)
{
if(i == 3)
{
continue; //i为3则放弃本次循环
}
printf("a[%d]=%d\n", i, a[i]);
}
return 0;
}
goto 跳转
goto语句用于无条件跳转到任意代码处执行,可以向前跳转也可以向后跳转,一般与if语句配合使用,实现有条件任意跳转,常用于复杂逻辑判断中,比如多个if语句和循环语句互相嵌套的情况,若没有goto语句则实现某些功能的代码会非常复杂。
#include <stdio.h>
int main()
{
int a;
scanf("%d", &a); //输入a的值
if(a == 0) goto x; //x为自定义的地址名称,若a等于0,则跳过功能一代码,执行功能二代码,否则两段代码都执行
//功能一代码 ......
printf("功能一执行完毕\n");
x:
//功能二代码 ......
printf("功能二执行完毕\n");
return 0;
}
标签:语句,case,07,int,C语言,while,循环,跳转,程序执行 From: https://www.cnblogs.com/alixyy/p/18175599