控制语句就是用来实现对流程的选择、循环、转向和返回等控制行为。
分支语句
if语句
基本结构
if(表达式)
{
语句块1;
}
else
{
语句块2;
}
执行顺序:
如果表达式判断成立(即表达式为真),则执行语句块1;如果表达式判断不成立(即表达式为假),则执行语句块2。
例如:
如果下雨就打印 “with umbrella” ,如果不下雨就打印 “no umbrella” 。
#include <stdio.h> #include <stdlib.h> #define RAIN 0 int main(int argc,char const * argv[]) { if(RAIN) printf("with umbrella\n"); else printf("no nmbrella\n"); return 0; }
输入a和b两个整数,实现用较大的数减较小的数。
int a,b; scanf("%d%d",&a,&b); if(a>b) printf("%d\n",a-b); else printf("%d\n",b-a);
以下程序的运行结果是(B)
int main() { unsigned int a; int b=-1; a=b; printf("%u",a); return 0; }
A. -1 B. 65535 C. 32767 D. -32768
解析:
有符号数转换为无符号数就是该数的补码,即有符号数为正数时,转换为无符号数就是他本身;为负数时,转换为无符号数就是他的补码。
拓展:
同样字长的无符号数和有符号数之间相互转换的一般规则是:数值可能会变,但是位模式不变,如果转换的无符号数太大以至于超过了补码能够表示的范围,可能会得到该范围的最大值。
设有定义语句:
char c1=92,c2=92;
则以下表达式中值为零的是(A)
A. c1^c2 B. c1&c2 C. ~c2 D. c1|c2
如果a=1,b=2,则a | b的值为(D)
A. 0 B. 1 C. 2 D. 3
实现大小写字符转换
#include <stdio.h> #include <stdlib.h> int main(int argc,char const * argv[]) { char c=getchar(); if(c>'A'&&c<'Z') ch+=32; else if(c>'a'&&c<'z') ch-=32; else { printf("input error\n"); return ; } putchar(c); putchar(10); return 0; }
结合宏定义和三目运算实现求两个数的差
解析:在宏定义中定义了变量,在函数中不能出现同名变量
#include <stdio.h> #include <stdlib.h> /*三目运算结合宏*/ #define M 20 #define N 10 #define DIFF M>N?M-N:N-M /*三目运算结合宏函数*/ #define DIFF_FUN(a,b) a>b?a-b:b-a int main(int argc,char const *argv[]) { printf("%d\n",DIFF); printf("%d\n",DIFF_FUN(M,N)); //调用宏函数:M>N?M-N:N-M return 0; }
分层结构
if(表达式1)
{
语句块1;
}
else if(表达式2)
{
语句块2;
}
else
{
语句块3;
}
执行顺序:
先判断if后面的表达式1是否成立,如果成立(即结果为真)则执行语句块1,如果结果为假则继续判断else if里面的表达式2,如果表达式2成立则执行语句块2,如果结果为假,则执行else里面的语句块3。
例如:
判断两个数的大小关系。
#include <stdio.h> #include <stdlib.h> int main(int argc,char const * argv[]) { 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; }
从终端输入一个学生的成绩,来判断学生成绩的等级并打印出来,等级评判如下:
90-100为A;80-89为B;70-79为C;60-69为D;60分以下为不及格(打印sorry,you fail )
#include <stdio.h> #include <stdlib.h> int main(int argc,char const * argv[]) { int score; scanf("%d",&score); if(score<=100&&score>=90) printf("A\n"); else if(score>=80&&score<=89) printf("B\n"); else if(score>=70&&score<=79) printf("C\n"); else if(score>=60&&score<=69) printf("D\n"); else if(score<=59) printf("sorry,you fail\n"); else printf("input error\n"); return 0; }
嵌套结构
if(表达式1)
{
if(表达式2)
{
语句块1;
}
else
{
语句块2;
}
}
else
{
语句块3;
}
执行顺序:
先判断if后面的表达式1,如果结果为真则判断嵌套的if后面的表达式2,如果表达式2结果为真 则执行语句块1,如果结果为假则执行语句块2,如果表达式1结果为假则执行语句块3。
从终端输入一个学生的成绩,来判断学生成绩的等级并打印出来,如果输入的不是int型数据则打印 “input error” ,等级评判如下:
90-100为A;80-89为B;70-79为C;60-69为D;60分以下为不及格(打印sorry,you fail )
#include <stdio.h> #include <stdlib.h> int main(int argc,char const * argv[]) { int score; scanf("%d",&score); if(score>=0&&score<=100) { if(score<=100&&score>=90) printf("A\n"); else if(score>=80&&score<=89) printf("B\n"); else if(score>=70&&score<=79) printf("C\n"); else if(score>=60&&score<=69) printf("D\n"); else if(score<=59) printf("sorry,you fail\n"); } else printf("input error\n"); return 0; }
输入一个int类型的数据,如果大于0则打印大于0,并且再判断是否大于等于10,如果大于等于10则打印大于等于10,小于10则打印小于10,如果数据小于0则不打印任何东西。
#include <stdio.h> #include <stdlib.h> int main(int argc,char const * argv[]) { int num=0; scanf("%d",&num); if(num>=0) { printf("num>=0\n"); if(num>=10) { printf("num>=10"); } else printf("num<10\n"); } return 0; }
总结:
- 首先需要判断表达式是否成立 ,如果成立就执行if里面的语句块,否则执行else里面的语句块;
- if后面可以没有else,但是else前面必须有if,并且else必须紧跟着if后面,中间不能加任何语句;
- if和else下面语句块中如果只有一行语句则可以省略花括号。
switch…case语句
基本结构
switch(变量或表达式)
{
case 常量1:
语句块1;
break;
case 常量2:
语句块2;
break;
……
default:
语句块n+1;
}
执行顺序:
当switch后面括号中的变量或表达式与下面其中一个case后面的常量相符时,就执行相应case语句后面的语句块,并依次执行后面的case,直到遇到break语句跳出switch语句。如果变量或表达式与所有的case后面的常量都不相等,则执行default后面的语句块。
注意:
- switch后面的表达式不能是浮点型数据或字符串;
- case后面的break可以省略,但是省略后会从相符的case开始顺序执行,直到遇到break结束。
从终端输入一个学生的成绩,然后打印出来对应成绩的等级,要求用到switch…case结构编写,等级评判如下:
90-100为A;80-89为B;70-79为C;60-69为D;60分以下为不及格(打印sorry,you fail )
#include <stdio.h> #include <stdlib.h> int main(int argc,char char const * argv[]) { int score; scanf("%d",&score); switch(score/10) { case 10: case 9: printf("A\n");break; case 8: printf("B\n");break; case 7: printf("C\n");break; case 6: printf("A\n");break; default: printf("sorry,you fail\n");break; } return 0; }
从终端输入一个日期(年、月、日),判断这是这一年的第几天。
解析:
首先要先判断是闰年还是平年,闰年的二月份比平年的二月份多一天。普通年份除以4,有余数的是平年,没有余数的是闰年,对于整百的年份,要除以400,有余数的是平年,没有余数的是闰年。
方法一:
#include <stdio.h> #include <stdlib.h> int main(int argc, char const *argv[]) { int year, month, day, days = 0, leap = 0; scanf("%d %d %d", &year, &month, &day); if (year % 100 == 0) { if (year % 400 == 0) leap = 1; else leap = 0; } else { if (year % 4 == 0) leap = 1; else leap = 0; } switch (month) { case 1: days = day; break; case 2: days = 31 + day; break; case 3: days = 31 + 28 + leap + day; break; case 4: days = 31 + 28 + leap + 31 + day; break; case 5: days = 31 + 28 + leap + 31 + 30 + day; break; case 6: days = 31 + 28 + leap + 31 + 30 + 31 + day; break; case 7: days = 31 + 28 + leap + 31 + 30 + 31 + 30 + day; break; case 8: days = 31 + 28 + leap + 31 + 30 + 31 + 30 + 31 + day; break; case 9: days = 31 + 28 + leap + 31 + 30 + 31 + 30 + 31 + 31 + day; break; case 10: days = 31 + 28 + leap + 31 + 30 + 31 + 30 + 31 + 31 + 30 + day; break; case 11: days = 31 + 28 + leap + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + day; break; case 12: days = 31 + 28 + leap + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + day; break; default: printf("month err\n"); break; } printf("%d\n",days); return 0; }
方法二:
#include <stdio.h> #include <stdlib.h> int main() { int year = 0, month = 0, day = 0, days = 0, leap = 1; scanf("%d %d %d", &year, &month, &day); leap = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0); switch (month) { case 12: days += 30; case 11: days += 31; case 10: days += 30; case 9: days += 31; case 8: days += 31; case 7: days += 30; case 6: days += 31; case 5: days += 30; case 4: days += 31; case 3: days += 28 + leap; case 2: days += 31; case 1: days += day; break; default: printf("error!\n"); break; } printf("%04d-%02d-%02d:这一年的第%d天\n", year, month, day, days); return 0; }
总结:
- 执行顺序:先判断switch()括号中的条件是否满足switch语句块里的case,如果满足哪个case则执行那个case里面的语句块,如果不满足则执行default中的默认语句块,并且如果case后面没有break会依次向下执行,直到遇到break后结束。
- 如果case后面的语句块和上一个case中的语句块相同,那么可以省略,形式如下:
case 常量1:
case 常量2:
语句块1;
break;
switch…case语句要遵循的规则:
- 只能针对基本数据类型的整型数据或字符型数据,如果要判断的条件是其他类型必须用if;
- case后面的标签必须是常量;
- case后面的标签必须是唯一表达式,不能有两个重复的case。
循环语句
for循环
基本结构
for(表达式1;表达式2;表达式3)
{
语句块;
}
说明:
表达式1:赋初值
表达式2:循环判断条件
表达式3:增值或减值
执行顺序:
首先执行表达式1进行赋初值,然后判断表达式2是否成立,如果成立就进入循环执行语句块,最后执行表达式3进行增值或者减值,再判断表达式2是否成立,如果成立就再次进入循环,直到判断表达式2不成立的时候退出循环。
例如:
求5的阶乘(5!)
int sum=1; for(int i=1;i<=5;i++) sum*=i; printf("%d\n",sum);
嵌套结构
for(表达式1;表达式2;表达式3)
{
for(表达式4;表达式5;表达式6)
{
语句块;
}
}
例如:
用for循环打印99乘法表
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
#include <stdio.h> #include <stdlib.h> int main(int argc,char const * argv[]) { for(int i=1;i<10;i++) { for(int j=1;j<=i;j++) printf("%d*%d=%d ",j,i,i*j); printf("\n"); } return 0; }
for循环变形
变形一
表达式1;
for(;表达式2;表达式3)
{
语句块;
}
变形二
表达式1;
for(;表达式2;)
{
语句块;
表达式3;
}
变形三
表达式1;
for(;;)
{
if(表达式2)
{
语句块;
表达式3;
}
else
{
break;
}
}
例题:
打印所有的水仙花数
水仙花数:三位数的百位立方+十位立方+个位立方=原数
#include <stdio.h> #include <stdlib.h> int main(int argc,char const argv[]) { int g,s,b,num; for(int i=100;i<1000;i++) { g=i%10; s=i/10%10; b=i/100; num=g*g*g+s*s*s+b*b*b; if(num==i) printf("%d\n",i); } return 0; }
从终端输入行数,例如输入5,打印类似于下图的图形。
分析:
下半部分的行数和空格数关系表:
行数 i 空格数 = i-1 星星数 = 5 - i + 1 1 0 5 = 5 - 1 + 1 2 1 4 = 5 - 2 + 1 3 2 3 = 5 - 3 + 1 4 3 2 = 5 - 4 + 1 5 4 1 = 5 - 5 + 1 #include <stdio.h> #include <stdlib.h> int main(int argv,char const * argc[]) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { for(int j=1;j<=i;j++) printf("*"); printf("\n"); } for(int i=1;i<=n;i++) { for(int j=1;j<i;j++) printf(" "); for(int k=1;k<=n-1+1;k++) printf("*"); printf("\n"); } return 0; }
while循环
基本结构
定义循环变量并赋初值;
while(判断条件)
{
语句块;
增值或减值语句;
}
执行顺序:
首先定义循环变量并赋初值,然后判断条件是否满足,如果满足则进入循环体系并进行增值或减值语句,然后再进行判断,如果满足则再次进入循环体系直到不满足条件就退出循环,类似于for循环的第二种变形。
例如:
用while循环求1到100的和
#include <stdio.h> #include <stdlib.h> int main(int argc,char const * argv[]) { int i=1,sum=0; while(i<=100) { sum+=i; i++; } printf("%d\n",sum); return 0; }
do…while循环
基本结构
do
{
语句块;
增值或减值语句;
}while(判断条件);
执行顺序:
先执行再判断。
用do…while循环求1到100的和
#include <stdio.h> #include <stdlib.h> int main(int argc,char const * argv[]) { int i=1,sum=0; do { sum+=i; i++; }while(i<=100); printf("%d\n",sum); return 0; }
上图中左边是do…while循环,右边是while循环
do…while和while的区别:
- 执行顺序不同:do…while先执行后判断,while先判断后执行。
- 执行次数不同:do…while至少执行一次,但是如果一开始满足判断条件则两者执行次数相同。
死循环
for(;;){}
while(1){}
while(1);
循环控制语句
break
break:直接结束循环,如果是嵌套的话是结束一层循环。
continue
continue:结束本次循环,继续下一次循环。
goto
goto:强制跳转到标签位置,可以用于多层嵌套循环(尽量不要使用goto)。
练习:
打印100-200中所有能被三整除的数
#include <stdio.h> #include <stdlib.h> int main(int argc, char const *argv[]) { int n; for(n=100;n<=200;n++) { if(n%3!=0) continue; printf("%d ",n); } printf("\n"); return 0; }
练习:
从终端上循环输入一个字符并在终端上输出 这个字符,当输入的字符为 ' q ' 时,程序结束。
#include <stdio.h> #include <stdlib.h> int main() { char ch; while(1) { scanf("%c",&ch); //getchar(); if(ch=='\n') continue; if(ch=='q') break; printf("%c\n",ch); } return 0; }
死循环结束场景:
使用在循环语句中,为了结束循环在使用时需要加判断条件。
练习:
循环输入一个5位数,判断是不是回文数,当输入的数是0时循环结束,输入的数是回文数循环也结束。
解析:
12321是回文数,即个位与万位相同,十位与千位相同。
#include <stdio.h> #include <stdlib.h> { int n=0,g,s,b,q,w; while(1) { scanf("%d",&n); g=n%10; s=n/10%10; b=n/100%10; q=n/1000%10; w=n/10000; if((g==w&&w!=0)&&q==s||n==0) { printf("%d\n",n); break; } } return 0; }
输入任意两个数,输出两个数之间(包括这两个数)各偶数之和。
解析:
从输入的较小的数开始依次加1判断是否为偶数,直到加到较大的数为止,每次都判断当前数是否是偶数,是则累加到sum中。
#include <stdio.h> #include <stdlib.h> int main() { int a,b,c,sum=0; scanf("%d %d",&a,&b); if(a>b) { c=a; a=b; b=c } while(a<=b) { if(a%2==0) sum+=a; a++; } printf("sum=%d\n",sum); return 0; }