逻辑操作符
逻辑操作符包括逻辑与||
,逻辑或&&
以及逻辑取反!
。这里与数学上的逻辑运算相同,不再额外赘述。需要指出的是短路现象。C语言逻辑运算符会先对左边表达式求值,再对右边表达式求值。如果左边的表达式满足逻辑运算符的条件,则不会对右边求值。这种现象就是短路。看一下代码:
if(mon >= 3 || mon <=5);
左边是mon >= 3
,右边是mon <=5
。如果mon == 6
,按照短路的原则,6>=3,因此表达式的值是真,也就会执行if之后的语句。
switch语句
switch
是另一种if..else
,常用于判断条件有多个的情况。switch
语句在使用时,需要注意:
switch
之后的表达式必须是整型表达式;case
之后的值必须是整型常量。
switch语句中的break
看一段代码:
int main()
{
int n = 0;
scanf("%d", &n);
switch(n%3)
{
case 0:
printf("整除,余数为0\n");
case 1:
printf("余数是1\n");
case 2:
printf("余数是2\n");
}
return 0;
}
当输入为3
的时候,会依次打印从case 0
开始的所有结果。这是因为case
仅仅决定分支的入口,如果不配合书写break
,程序会从case
确定的入口开始依次执行。
switch语句中的default
default
是处理所有的case
无法匹配的情况。default
可以再switch
语句中的任意位置,但通常是放在最后。举个例子:
int main()
{
int day = 0;
scanf("%d", &day);
switch(day)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("工作日\n");
break;
case 6:
case 7:
printf("休息日\n");
break;
default:
printf("输入错误\n");
break;
}
return 0;
}
上述代码输入8的时候就会从default
处进入。
循环语句
循环语句一共有 while
、do...while
、for
三种,接下来依次介绍。
while
while
的语法结构是:
while(exp)
statement;
while
会判断exp
的值,依据真假决定是否执行statement
。为真则执行,为假就不执行。看一下代码:
int main()
{
int i = 1;
while(i<=10)
{
printf("%d ", i);
i = i+1;
}
return 0;
}
上述代码打印1~10。初始状态下,i = 1,while先判断,由于1 <=10 因此执行循环体内的打印和i=i+1。然后再次判断,直至不满足表达式条件(>10)。然后结束循环。这里可以看出来,循环执行的需要:
- 初始值(这里是i=1);
- 循环条件(这里是i<=10);
- 变量调整(这里是i=i+1);
初始值决定了循环从哪里开始,循环条件用于控制循环从哪里结束,变量调整则是对变量进行更新(不更新的话会是死循环)。
for
for
循环是使用场景最多的,其形式如下:
for(exp1;exp2;exp3)
其中,exp1
对应初始值,exp2
对应循环条件,exp3
对应变量调整。这里与上述的三个条件吻合。下面用for
循环实现打印1~10:
int main()
{
for(i=1;i<=10;i++)
{
printf("%d ", i);
}
return 0;
}
这种形式较while
循环更加的简洁,能够很容易的看到循环是如何进行的。
do…while
这个循环是三个循环里使用最少的,它适用于至少执行一次循环的情况。do...while
的形式如下:
do
statement;
while(exp);
do...while
会先执行一次语句,然后再判断表达式。
break和continue
在执行循环的过程中,在满足某种条件下,需要提前终止循环。C语言提供了break
和continue
两个关键字用于这种控制。
break
是永久终止循环,只要执行break
,会直接执行循环外面的语句。
continue
则是跳过本次循环,继续执行continue
之后的代码。continue
在for
循环和while
循环中是有差异的。
while中的break和continue
先看一段代码:
#include <stdio.h>
int main()
{
int i = 1;
while(i<=10)
{
if(i == 5)
break;//当i等于5后,就执行break,循环就终止了
printf("%d ", i);
i = i+1;
}
return 0;
}
这里的执行结果是屏幕会打印1 2 3 4。因为当i == 5
的时候,会跳出循环,不再执行循环体内之后的语句。如果将break
换成continue
:
#include <stdio.h>
int main()
{
int i = 1;
while(i<=10)
{
if(i == 5)
continue;
printf("%d ", i);
i = i+1;
}
return 0;
}
这里会打印1 2 3 4 然后进入死循环。因为当i == 5
的时候,continue
跳过本次循环之后的代码,因此i = i+1
没有被执行,所以i
会一直是5。而i == 5
一直满足循环条件,所以是死循环。
for中的break和continue
for
循环中的break
与while
中一样,都是结束循环。至于continue
,先看一段代码:
int main()
{
int i = 1;
for(i=1; i<=10; i++)
{
if(i == 5)
continue;//这里continue跳过了后边的打印,来到了i++的调整部分
printf("%d ", i);
}
return 0;
}
打印结果是除过5之外的1~10。这里continue仅跳过了之后的打印部分,但循环会直接到更新部分(i++
),这里是与while
不一样的。
do…while中的break和continue
与while
一致,不再赘述。
循环嵌套
很多时候需要在循环体内部嵌套循环,用于解决更加复杂的问题。先看个小练习。
打印100~200之间的质数
写代码前,先做思考。需要打印100~200之间的质数,那么需要做:
- 产生100~200之间的数字;
- 判断这个数字是不是质数。如何判断呢?质数的定义是一个数只能被1和它本身整除时,就是质数。那么需要产生2~这个数字-1这些数字去试除,如果都不能整除,则这个数字就是质数。
有了思路,就可以开始写代码了:
#include <stdio.h>
int main()
{
int i = 0;
for(i=100; i<=200; i++)//产生100~200
{
int j = 0;
int flag = 1;//标记是否为质数,1是质数,0不是质数
for(j=2; j<i; j++)//产生2~i-1
{
if(i % j == 0)
{
flag = 0;
break;
}
}
if(flag == 1)
printf("%d ", i);
}
return 0;
}
再往深里想想:
3. 质数不可能是偶数,所以可以在101、103…199之间找
4. 一个数如果可以写成x = a*b,那么a和b之间必然会有一个数字小于sqrt(x)。
按照这个思路改造代码:
#include <stdio.h>
#include <math.h>
int main()
{
int i = 0;
for(i=101; i<=200; i+=2)//产生101~199
{
int j = 0;
int flag = 1;//标记是否为质数,1是质数,0不是质数
for(j=2; j<=sqrt(i); j++)//产生2~sqrt(i)
{
if(i % j == 0)
{
flag = 0;
break;
}
}
if(flag == 1)
printf("%d ", i);
}
return 0;
}
这个代码的效率更高,外层循环较第一个代码减少了一半,内层则是原来循环次数的开平方。
goto的使用场景
goto
语句仅可用于多层循环的快速结束。