C语言复习(2)——语句

C语言复习(2)——语句

在这里插入图片描述

2.1 空语句

C中最简单的语句,本身只包含一个分号。空语句不执行任何任务,但仍有作用。适用的场合便是语法要求出现一条完整语句,但并不需要它执行任何任务。

2.2 表达式语句

C不存在专门的“赋值语句”,赋值就是一种操作,就像加法和减法一样,赋值利用“=”运算符在表达式中进行。在表达式尾部加上分号,就转化为语句,下面的表达式

x=y+3;
ch=getchar();

实际上是表达式语句,而非赋值语句。理解这点非常重要,因为下面的语句也是合法的:

y+3;
getchar();

当他们被执行时,表达式被求值,但是结果不保存在任何地方。因此,第一条语句并不具备任何效果,,而第二条语句则读取输入中的下一个字符接着将其丢弃(注:可以用于清空输入缓冲区)。
如果你觉得编写一条没有任何效果的语句有些奇怪,可以考虑以下语句:

printf("Hello world!\n");

printf是一个函数,函数将返回值,但printf函数的返回值(实际打印的字符数)我们并不关心,所以弃之不理。所谓的“没有效果”只是表达式的值被忽略,但printf所执行的打印是有用的工作,称之为“side effect”。
同理a++;这条语句没有赋值操作,但确是一条合理的表达式。++操作符增加了a的值,这就是该语句的“side effect”。

2.3 if语句

语法如下:

if(expression)
{
	statement1
} 
else
{
	statement2
}

注:请在任何时候都为if和else后的语句添加花括号
如果expression为真(非零),执行statement1,否则跳过他。如果存在else子句,它后面的statement2只有当expression的值为假()时才会执行。

注意以下代码:

int a=0;
if(0==(a=0))
{	
	printf("hehe\n");
}
else
{
	printf("haha\n");
}

赋值运算的返回值就是所赋的值,故a=0的返回值是0,此时0==0所以if中的表达式返回值是1。
在这里插入图片描述
“悬空的else” 问题
先看代码:

int a = 0;
int b = 2;
if(a == 1)
	if(b == 2)
		printf("hehe\n");
else
	printf("haha\n");

你认为else是哪个if的子句呢?这里故意用奇怪的缩进,让你有所迷惑,你是否认为输出的是“haha”
答案是else子句从属于最靠近他的不完整的if语句,所以这个代码块什么都不输出。如果想让它从属于第一个if,就要把第二个if补充完整,加上一条空的else子句,或者直接用花括号。
花括号,永远的神!

if (a == 1)
{
	if (b == 2)
		printf("hehe\n");
}
else
	printf("haha\n");

输出“haha”

2.4 while 语句

语法如下:

while(expression)
{
	statement1
}
statement2

while的流程:
expression != 0 ,执行循环体 statement1 。
expression == 0,循环结束,跳出循环执行 statement2 。
对expression的测试在statement1(循环体)之前进行,如果为假(expression==0),循环体一次也不执行。

2.4.1 break 和 continue

先上图:
在这里插入图片描述
以代码举例:

int ch;
while((ch=getchar())!=EOF) 
{
	putchar(ch);
}
//标准输入循环复制字符到标准输出,直到找到文件尾结束标识。

putchargetchar函数。
如果循环体中执行了continue语句,循环体内的部分将不再执行,而是立即开始下一轮循环。如果循环体遇到某些值才会执行的情况下,Continue语句会相当好用。

int ch;
while((ch=getchar())!=EOF) 
{
	if(ch<'0' || ch>'9')
		continue;
	putchar(ch);
}
//只打印数字字符

在这里插入图片描述
注意continue不要放在循环步进之前,不然容易造成死循环,错例如下:

int i=1;
while(i<=10)
{
	if(5==i)
		continue;
	printf("%d ",i);
	i++;
}

while将在i==5后无限continue,因为始终跳过了i++
在这里插入图片描述

如果把i++放在continue之前就能避免错误。

int i=0;
while(i<10)
{
	i++;
	if(5==i)
	continue;
	printf("%d ",i);
}

在这里插入图片描述

如果循环体中加入break语句,循环就将永久性退出。

int ch;
while((ch=getchar())!=EOF) 
{
	if(ch<'0' || ch>'9')
		break;
	putchar(ch);
}
//遇到数字以外字符停止循环输入

在这里插入图片描述

提示:while语句有时在表达式中就可以完成整个语句的任务,于是循环体就无事可做,这种情况下循环体就用空语句来表示。单独用一行来表示一条空语句是比较好的做法,不至于让人误以为程序接下来的一条语句才是循环体。

while((ch=getchar())!='\n')
	;

这条代码的作用是丢弃当前输入行的剩余字符,用处不小。

具体输入缓冲区可参考博客C语言中的输入输出流和缓冲区(重点)详解

2.5 for语句

语法如下:

for(exp1;exp2;exp3)
{
	statement
}

statement为循环体。
exp1为初始化,在循环开始时执行一次。
exp2为条件部分,在循环体每次执行前都要执行一次,与while语句中的expression一样。
exp3为调整部分,循环体statement每次执行完毕后执行exp3,紧接着执行exp2。
所有三个表达式都是可选的,如果省略条件部分exp2,表示测试的值始终为真;

在for语句中使用break语句,则立刻退出循环。而continue语句则把控制流直接转移到调整部分exp3。

将for语句转化为while语句:

exp1;
while(exp2)
{
	statement
	exp3;
}

for和while的区别在于出现continue语句时。for语句的continue跳过循环体,直接转到调整部分。在while语句中,调整部分是循环体的一部分,所以continue可能会把调整部分也跳过,直接去向条件部分。
for循环流程图如下:在这里插入图片描述
查看while流程图

2.6 do while 语句

类似while语句,只是条件部分在循环体执行之后才进行。所以这种循环的循环体至少要执行一次。语法如下:

do
{
	statement
}while(expression)

在这里插入图片描述
当需要循环体至少执行一次时,选择do while语句

2.7 switch 语句

switch(expression)
{
	case constant-expression1:
	statement1;
	case constant-expression2:
	statement2;
	....
}

每个case必须具有一个唯一的值。expression的结果必须是整型值,当expression的返回值与常量表达式(constant-expression)匹配,即确定了语句进入点。
具体流程:

  1. 计算expression值
  2. 进入语句列表中case标签值与expression的值匹配的语句。
  3. 从这条语句开始,直到语句列表的结束,也就是switch语句的底部,之间的所有语句都将被执行。

注意:case的标签值只是确定了语句的进入点,但是不能划分语句列表。一旦进入语句后,就将贯穿后续的case语句,而不是停留在单个的case标签。如果想要在某个case中执行完语句后跳出switch语句块——使用break语句。

2.7.1 switch 中的 break 语句

在某个case的statement执行后添加break,便会直接跳到语句列表的末尾。

int main()
{
int i;
scanf("%d", &i);
switch (i)
{
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;
}
return 0;
}

break语句的实际效果是把语句列表分为不同部分,你会发现最后一个case的语句后面的break貌似没什么用,但是我们放在那里也没什么害处,之所以加在那里是为了以后维护方便,万一以后多了一个“周八”呢。
switch并非循环语句,continue没有任何作用。
为了使同一个statement在多个case标签之下都能运行,可以活用break,代码如下:

int main()
{
	int i;
	scanf("%d", &i);
	switch (i)
	{
	case 1:
	case 2:
	case 3:
	case 4:
	case 5:
		printf("工作日\n");
		break;
	case 6:
	case 7:
		printf("休息日\n");
		break;
	}
	return 0;
}

2.7.2 default 子句

此时你可能会有个疑问,如果case的标签值没有一个与expression的结果匹配,会发生什么情况?答案就是所有的case对应语句都被跳过,程序继续往下进行且不会报错。
但是你不想让辛辛苦苦写的switch语句块就这么被白白跳过了,即使没有用到case中的语句,好歹也得知会你一声吧。
你可以在语句列表中增加一条default子句。

default :
statement
break;

当不匹配所有的case值时,这个default后面的statement便会执行。还是上述代码,添加default后,可以知道输入错误。

int main()
{
	int i;
	scanf("%d", &i);
	switch (i)
	{
	case 1:
	case 2:
	case 3:
	case 4:
	case 5:
		printf("工作日\n");
		break;
	case 6:
	case 7:
		printf("休息日\n");
		break;
	default:
		printf("Wrong day\n");
		break;
	}
	return 0;
}

在这里插入图片描述
default 只能出现一次,可以放在语句列表的任一位置,建议放在末尾且带上break,因为语句流会像贯穿其他case一样贯穿default。否则如下代码,default放在前面又忘记break。

int main()
{
	int i;
	scanf("%d", &i);
	switch (i)
	{
	default:
		printf("Wrong day\n");
	case 1:
	case 2:
	case 3:
	case 4:
	case 5:
		printf("工作日\n");
		break;
	case 6:
	case 7:
		printf("休息日\n");
		break;
	}
	return 0;
}

在这里插入图片描述

注意:绝大部分情况下,每个case的语句后都会带上break,如果你需要贯穿case标签,请务必注释,如果没有注释,一个粗心的维护程序员便有可能认为此处缺少break语句是个错误,是bug的起源,于是当他“修正”这个“bug”时,不仅错过了他原先寻找的bug,还引入了新bug。

2.8 总结

  1. if语句根据条件执行语句
  2. while(exp)
    exp!=0 执行循环
    exp==0 跳出while
  3. for与while类似,但是便利在与把控制循环的表达式收集起来放在一个地方
  4. do while 语句保证循环体至少执行一次
  5. 当循环内部执行break语句时,循环就会退出。
  6. continue语句会跳过循环体的剩余部分,立即开始下一次循环。在while和do while语句中,会跳到判断循环是否要进行的条件部分,而for语句中则是先跳到调整部分(exp3),再进入判断循环是否要进行的条件部分(exp2)
  7. goto语句应尽量避免使用
青山不改 绿水长流
  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值