C语言之所以被称为结构化的程序设计语言,其原因就是因为C语言能够支持顺序结构,选择结构(分支结构),循环结构这三种结构,而日常生活中的几乎所有问题都是由这三种结构构成的,所以生活中遇到的几乎所有的问题,都可以通过C语言编写代码来解决,所以学会分支与循环语句就显得十分重要。
一 分支结构
分支结构,顾名思义,就是分出多条路线,然后选择一条路线去执行,就是分支结构,就比如你去公司上班,一共有A和B两条路可以走,你可以选择走A路线去上班,同时,B路线也就不走了,这就是分支结构。而在C语言中,分支结构可以通过if语句和switch语句来实现。
1 if语句
if语句是C语言中使用最多的一中分支语句,其语法是:
if (表达式)
语句
表达式为真,则执行下面的语句,如果为假,则不执行下面的语句,而在C语言中0也表示假,非0表示真,所以当表达式结果为0是语句也不执行,结果不是0时,语句则会执行。
例如:
//输入一个整数,判断是否为偶数
#include<stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
if (num % 2 == 0)
{
printf("%d是偶数\n",num);
}
return 0;
}
输入6,结果为“6是偶数”;输入5,则什么都没有输出。
2 else语句
if语句一般只包含一种情况,那么如果有多种情况的话,就需要if...else....语句了,其语法是:
if (表达式)
语句1
else
语句2
如果表达式为真,则执行语句1,否则,就执行语句2。
例如:
//输入一个数,判断一个数是奇数还是偶数
#include<stdio.h>
int main()
{
int num = 0;
scanf("%d",&num);
if (num % 2 == 0)
printf("%d是偶数\n",num);
else
printf("%d是奇数\n",num);
return 0;
}
输入5,输出“5是奇数”;输入6,输出“6是偶数”。
3 if语句或else语句中包含多条语句
如果是下面一段代码,会输出什么呢?
#include<stdio.h>
int main()
{
int num = 6;
if (num % 2 == 0)
printf("Hello World ");
printf("Hello C");
return 0;
}
实际上其输出的是“Hello World Hello C”,这是因为在C语言中if和else语句默认只控制一条语句,那么该如何控制多条语句呢?只需要把多条代码放到{ }中即可让if或者else语句控制多条语句了。
{ }叫做代码块,也叫做复合语句,使用{ }会使写的代码逻辑看起来更加清晰,可读性更强,所以在代码中要使用必要的一些{ }来增强代码的可读性。
4 if语句的嵌套
有时候呢,分支语句并不只有两种情况,可能会有多种情况,这时候就需要if语句嵌套使用来完成多种情况的实现。比如:
//大于0就输出正数,0就输出零,小于0就输出负数
int main()
{
int a = 0;
if (a == 0)
printf("零\n");
else
{
if (a > 0)
printf("正数\n");
else
printf("负数\n");
}
return 0;
}
其实,在if语句的嵌套结构中,else后面的大括号在语法上是支持省略的,比如:
//大于0就输出正数,0就输出零,小于0就输出负数
int main()
{
int a = 0;
if (a == 0)
printf("零\n");
else if (a > 0)
printf("正数\n");
else
printf("负数\n");
return 0;
}
所以平常所见的else if语句其实是if语句的嵌套结构。
5 悬空else
请看下面代码会输出什么
int main()
{
int a = 0;
int b = 1;
if (a)
if (b)
printf("Hello World!\n");
else
printf("Hello C!\n");
return 0;
}
看对齐方式应该是输出Hello C!,实际上呢,什么都没有输出,其原因就是else总是与它最近的if语句相匹配,所以示例代码中else是与它上一句的if语句相匹配的,故什么都没有输出。
6 switch 语句
C语言中还支持一种分支语句叫做switch语句,其中包含case语句,default语句与break语句,swtich语句是else...if语句的一种替代形式,是代码可读性更强,逻辑更加清晰。
其语法形式是:
switch(expression)
{
case value1:
statement
case value2:
statement
default:
statement
}
其中,expression是整形表达式,value1与value2是expression可能出现的各种值的情况,default是除了value1和value2之外的情况所执行的情况,值得注意的是,case后面的值必须是常量表达式,不能是变量,也不能是定义的整型变量,而且case与后面的常量表达式之间必须有空格
那下面这个代码的输出结果是啥呢?
#include<stdio.h>
int main()
{
int a = 3;
switch(a % 3)
{
case 0:
printf("余数是0 ");
case 1:
printf("余数是1 ");
case 2:
printf("余数是2 ");
}
return 0;
}
实际上,这个代码的输出结果是“余数是0 余数是1 余数是2 ”,那么为什么会输出这个呢?其实,case是相当于分支的入口,直到swich分支结构的最后一行,整个switch分支结构才结束,那么如果要提前结束switch分支结构要怎么办呢?这时候只要在每一个case语句后面加一个break语句,就可以提前结束switch分支结构了,如上面那个代码:
#include<stdio.h>
int main()
{
int a = 3;
switch(a % 3)
{
case 0:
printf("余数是0 ");
break;
case 1:
printf("余数是1 ");
break;
case 2:
printf("余数是2 ");
break;
}
return 0;
}
这样之后,就只会输出“余数是0 ”了。
所以一般为了保证switch分支结构的正确性,要在case语句后面加上break语句,但要注意的是,break语句是需要但不是必要,还要根据实际情况来选择是否加上break语句,而不是盲目的在每一个case语句后都加上break语句,这样可能会导致代码的冗余甚至是错误,如:
//输入一个值,如果是周一到周五输出工作日,如果是周六周日输出休息日
#include<stdio.h>
int main()
{
int a = 0;
scanf("%d",&a);
switch(a)
{
case 1:
printf("工作日\n");
break;
case 2:
printf("工作日\n");
break;
case 3:
printf("工作日\n");
break;
case 4:
printf("工作日\n");
break;
case 5:
printf("工作日\n");
break;
case 6:
printf("休息日\n");
break;
case 7:
printf("休息日\n");
break;
default:
printf("输入错误\n");
return 0;
}
可以看到,这样写有大量代码重复,造成了冗余,可以进行如下优化:
//输入一个值,如果是周一到周五输出工作日,如果是周六周日输出休息日
#include<stdio.h>
int main()
{
int a = 0;
scanf("%d",&a);
switch(a)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("工作日\n");
break;
case 6:
case 7:
printf("休息日\n");
break;
default:
printf("输入错误\n");
return 0;
}
还有一点需要注意的是,default语句并不是必须放在最后,放在前面也是可以的,所以switch分支结构中的语句是没有先后顺序的。
7 条件操作符
在C语言中,有一个唯一的三目操作符(需要三个操作数),那就是条件操作符,其基本形式是
表达式1 ? 表达式2 : 表达式3
表达式1表示判断的条件,如果为真,执行表达式2,为假执行表达式3,如:
//求出两个数中的较大值
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int max = a>b ? a : b;
printf("%d\n",max);
return 0;
}
二 循环结构
上面介绍了分支语句,那循环语句包括哪些呢?循环语句共有三种,分别是while语句,do while语句,以及for语句。
1 while循环
其语法是:
while (表达式)
{
语句1
语句2
...
}
while循环特点是,先判断表达式是否为真(或结果非0),若为真,则执行代码块中的语句,若为假(或结果为0),则不执行代码块中的语句 。
如:
//输出10-1 10个数字
#include<stdio.h>
int main()
{
int n = 10;
while(n)
{
printf("%d ",n);
n--;
}
return 0;
}
2 for循环
其语法是:
for (表达式1;表达式2;表达式3)
{
语句1;
语句2;
....
}
表达式1是循环变量的初始化,表达式2是循环的条件,表达式3是循环变量的调整部分,在语法上是支持三个表达式都省略的,但是一般不会省略,如果省略,可能会陷入死循环。
for循环的特点是表达式1只会在第一次循环时执行一次, 接下来的循环就是表达式2,循环语句,和表达式3之间的循环。
for循环举例:
//输出10-1 10个数字
#include<stdio.h>
int main()
{
int i = 0;
for(i = 10; i ;i--)
{
printf("%d ",i);
}
return 0;
}
3 do while循环
其语法是:
do
{
语句1
语句2
....
}while(表达式);
do while循环的特点是,不管表达式判断是否为真,其循环语句至少会被执行一次。
do while循环举例:
//输出10-1 10个数字
#include<stdio.h>
int main()
{
int i = 10;
do
{
printf("%d ",i);
i--;
}while(i);
return 0;
}
4 循环结构中的break语句以及continue语句
循环语句在使用时,有时需要提前结束循环或者跳过本次循环,那这时候就要使用break语句来跳出循环,或者使用continue语句来结束本次循环。
不管循环是否执行完,使用break语句都会跳出循环,接着执行循环下面的语句;而使用continue语句会跳过本次循环中continue后面的代码,进行下一次循环的判断。
break与continue语句举例:
//输出1 2 3 4 6 7
#include<stdio.h>
int main()
{
int i = 0;
for (i = 1;i <= 10;i++)
{
if (5 == i)
continue;
if (8 == i)
break;
printf("%d ",i);
}
return 0;
}
当 i 等于5的时候,加上continue语句会跳过本次循环后面的代码,所以不会输出5,当 i 等于8的时候,加上break语句会跳出循环,所以8 9 10就不会输出了。
5 循环语句使用时的注意事项
在使用循环语句时,有那么两个注意事项:
1 一般要为循环添加一个循环变量,而且要在循环中进行循环变量的调整,否则可能会陷入死循环。
2 在使用break和continue语句时,要仔细考虑使用时机,否则可能会陷入死循环。
如:
#include<stdio.h>
int main()
{
int i = 0;
while(i <= 10)
{
if (5 == i)
continue;
printf("%d ",i);
i++;
}
return 0;
}
这里当 i 自增到5的时候,由于执行了continue语句,所以后面的 i++ 语句会被跳过,也就跳过了循环变量的调整语句,所以 i 一直等于5,一直小于10,循环会一直进行下去,陷入了死循环。
6 循环嵌套--求素数
在循环结构的嵌套中,有一个经典代码,就是求出素数,其代码是:
//输出100-200之间的素数(只能被1和本身整除)
//1 用一个for循环来产生100-200之间的数,但是由于偶数是可以被2整除的,所以偶数都不是素数,那么i
//可以从101开始,每次加2
//2 由于如果一个正数存在其他因子,那么其中一个因子必然会小于等于i的平方根,所以再在第一个for循环
//里面再用一个for循环来产生2-i的平方根之间的数字来试除i,如果能整除,那么i就不是素数
#include<stdio.h>
#include<math.h>
int main()
{
int i = 0;
for (i = 101;i <= 199;i += 2)
{
int j = 0;
int flag = 1;//假设i是素数
for (j = 2;j <= sqrt(i);j++)
{
if (i % j == 0)
flag = 0;//i不是素数
break;
}
if (1 == flag)
printf("%d ",i);
}
return 0;
}
7 goto语句
C语言中还提供了一种语句,叫goto语句,可以实现代码之间的跳转,本来break只能跳出一个循环,而使用goto语句可以跳出多个循环,其基本形式是:
goto 标志
语句1
语句2
....
标志:
语句3
语句4
....
标志是你想要执行goto语句是你想要跳转到的标志,比如goto next; goto begin等,执行到goto语句时,就会跳过语句1,语句2的执行,而直接跳转到标志,执行标志下面的语句。
goto语句虽然可以实现代码的快速跳转,但是如果使用较多的话,会使得代码随意乱跳,打乱执行流程,所以建议尽量不使用goto语句。
三 逻辑操作符
在if分支结构,while、do while、for循环结构中,他们都会判断表达式的真假来决定循环语句是否执行,而在C语言中真好有那么三个逻辑操作符来实现多条件之间的判断,这三个逻辑操作符分别是&&(逻辑与操作符),||(逻辑或操作符),!(逻辑取反操作符)。
值得注意的一点是,逻辑操作符如果判断为假,则会返回0,如果判断为真,则会返回1。
1 &&--逻辑与操作符
&& 是并且的意思,其是一个双目操作符(操作符需要两个操作数),其判断逻辑是全真为真,有假则为假(有0为0,双非0为1)。
2 ||--逻辑或操作符
||是或者的意思,其也是一个双目操作符,其判断逻辑是有真则为真,全假则为假(有非0为1,全0为0)。
逻辑与,逻辑或操作符举例:
//输入一个月份,根据月份进行判断,输出月份相对应季节
#include<stdio.h>
int main()
{
int m = 0;
scanf("%d",&m);
if (m == 12 || (m >=1 && m <= 2))
printf("冬季\n");
else if (m <= 5)
printf("春季\n");
else if (m <= 8)
printf("夏季\n");
else
printf("秋季\n");
return 0;
}
3 !--逻辑取反操作符
! 是取反的意思,即把假变为真,把真变为假(非0为0,0为1)。
4 短路现象
C语言中逻辑运算符有一个特点,就是逻辑运算符总是从左往右开始计算表达式,如果左边的表达式能够得出整个逻辑运算的结果,那就不再对右边的表达式进行运算,这就称为‘‘短路’’。
即:由于&&操作符如果表达式中其中一个是假(或者结果为0),那么逻辑运算的结果就为假(或为0),所以当从左边开始运算,碰到结果为假(或为0)的表达式,那么右边的表达式是便不再计算;同样地,当 || 操作符从左往右开始计算,当碰到结果为真(或为非0)的表达式,那么右边的表达式便不再计算。
例如:
#include<stdio.h>
int main()
{
int i = 0;
int a = 0;
int b = 0;
int c = 0;
int d = 0;
i = ++a && b++ || ++c || d++;
printf("a=%d b=%d c=%d i=%d d=%d", a, b, c, i, d);
return 0;
}
输出结果为:1 1 1 1 0
请思考:如果把++a换成a++呢?