Bootstrap

[C]第二章--分支语句与循环语句(1)--知识解析

什么是语句?

在C语言中,由一个分号;隔开的一段代码就是语句,比如:
return 0;/100 + 1 ;/printf("a");等都是语句.

分支语句

分支语句就是选择结构.其中最常见的关键词就是if.
那if语句的语法结构是什么样的呢?以下列举几种经常使用的结构:
1
结构1

if(表达式)
	语句;

结构2

if(表达式)
	语句1;
else
	语句2;

结构三

if(表达式1)
	语句1;
else if(表达式2)
	语句2;
else
	语句3;

解释一下:
如果表达式的结果为真,则语句1执行,否则表达式2执行.

在C语言中如何表示真假呢?
0 表示假
非0表示真

这与逻辑认知下的0为假,1为真有些差池,在C语言中非0即为真.

#include <stdio.h>
int main()[
	if(表达式){
		语句列表1;
	}
	else{
		语句列表2;
	}
	return 0;
]

这里是一个选择语句的"坑".并不是跟在if之后的else之前的所有语句都会雨露均沾的执行到.
if/else默认只执行紧接着其的第一行代码,也就是说像这样的语句列表并不会全部执行到.为了解决这个问题,我们引入代码块的概念.
这里的一对{ }就是代码块;
用大括号{ }包裹的一系列语句的列表就是一个代码块.
为了避免错误使用.建议读者就将代码块的使用加入平常选择结构的使用.这样习惯成自然,就完全不用纠结于到底有没有执行这个语句列表了.这也有利于好的编程习惯的养成.

悬空else

一起来看下面这行代码:

#include <stdio.h>
int main(){
	int a = 0;
	int b = 2;
	if(a == 1)
		if(b == 2)
			printf("bingo\n");
	else
		printf("failed\n");
	return 0;
}

这里的else究竟和哪个if匹配的呢?
是不是很容易产生歧义?
这就是悬空else,难以直观的看出来if…else…结构究竟是如何配对的问题,这在C语言的初学阶段是很常见的.

  • 解决方案:
    1.适当的使用{ }可以使代码的逻辑更加清晰,多用代码块.
    2.代码风格的统一很重要.
    以下演示一下:
#include <stdio.h>
int main(){
	int a = 0;
	int b = 2;
	if(a == 1){
		if(b == 2)
			printf("bingo\n");
	}
	else{
		printf("failed\n");
	}
	return 0;
}

结论:
else总是与最近的if配对.

多分支

#include <stdio.h>
int main(){
	int coding = 0;
	printf("你会好好敲代码吗?(选择1或0)");
	if(coding == 1) {
		printf("坚持,你会有好成绩");
	}
	else if(coding == 0){
		printf("放弃回家睡大觉吧.");
	}
	else if(coding == -1){
		printf("输入错误啦");
	}
	return 0;
}

简单的逻辑语句,就不多赘述了.

if书写形式的对比

  • 代码一:
if(condition)
	return x;
return y;
  • 代码二:
if(condition){
	return x;
}
else{
	return y;
}
  • 代码三:
int num = 1;
if(num = 5){
	printf("goal");
}
  • 代码四:
int num = 1;
if(5 == num){
	printf("goal");
}

比较上面4个代码,其实各有利弊.

  1. 代码一利用了 if不加大括号只执行紧接的第一句语句,代码看起来很整洁,但是有些新手会混淆.
  2. 代码二就比代码一直观很多了,但是二者所陈述的内容都是一样的,加上了不必要的大括号,在实际使用上就会显得繁琐很多.
  3. 代码三是一串和预期效果不太相同的代码,通过分析得知num = 5这个语句,按寻常逻辑应该是num == 5的比较语句,而这里因为少写了一个等号 =,就使它变成了一个赋值语句,那么这句语句再被if嵌套,他就成为了一定会判定成真的语句了.
    所以一定要注意代码的严谨性.
  4. 代码四中5 == num这样书写判断语句虽然可以一定程度上提升代码安全性,因为编译工具会自动检查出代码缺陷并警告,但是这样大大削减了代码的可读性,这一句"有违常理"的语句,会使人很难读懂其中的意思.
    很不建议这么书写.

综上所述:
代码一 和 代码三 的书写方式建议使用

switch语句

switch语句与if语句不同的是:
switch用于多分支选择,而if适合单分支(甚至"无分枝"的简单判断)

switch(整形表达式){
	语句项;
}

而什么是语句项?
是一些case语句.如下:

case 整型常量表达式:
	语句;

在switch语句中,我们没法直接实现分支
搭配break使用才能实现真正的分支.这也是其精髓之处.
比如:

#include <stdio.h>
int main(){
	int day = 0;
	switch(day){
		case 1:
			printf("Monday");
			break;
		case 2:
			printf("Tuesday");
			break;
		case 3:
			printf("Wednesday");
			break;
		case 4:
			printf("Thursday");
			break;
		case 5:
			printf("Friday");
			break;
		case 6:
			printf("Saturday");
			break;
		default:
			printf("Sunday");
			break;
		}
		return 0;
}
default语句就是之前的case语句都为命中时执行的语句.

循环语句

1. while

我们已经掌握了if选择语句,当条件满足的情况下,if语句后的语句执行,否则不执行.但是这个语句只会执行一次.
但是我们发现生活中很多实际的例子是:同一件事情我们要完成很多次.
那我们怎么做呢?
C语言中给我们引入了while语句,可以实现循环.

//while循环语法结构
while(表达式){
	循环语句;
}

比如在屏幕上打印1-10的数字.

#include <stdio.h
int main(){
	int i = 1;
	while(i <= 10){
		printf("%d ",i);
		i++;
	}
	return 0;
}

break 语句

  1. break在循环中的作用:
    其实在循环中只要遇到break,就停止后期所有的循环,直接跳出循环.
    所以,while中的break是用于永久终止循环的.

continue 语句

  1. continue在循环中的作用:
    本次continue后面的代码不会再执行,而是会直接跳转到while语句的判断部分,进行下一次循环的入口判断.
    所以,while中的continue是用于终止本次循环

2. for

我们已经知道了while循环,但是为什么还要一个for循环呢?

//for循环结构
for( 表达式1 ; 表达式2 ; 表达式3 )
	循环语句;
  • 表达式1为初始化部分,用于初始化循环变量的,在整个循环过程中只执行一次.
  • 表达式2为条件判断部分,用于判断循环何时终止
  • 表达式3为调整部分,用于更新循环变量.
    [其实必要的情况下三个表达式都可省略]

用for循环在屏幕上打印1-10的数字

#include <stdio.h>
int main(){
	int i = 0;
	for(i = 1; i <= 10; i++){
		printf("%d ",i);
	}
	return 0;
}

注:这里int i写在for语句之前是C语言写法
我们看到过很多次在for语言中的写法for(int i = 0;xx;xx)这样是C++写法

其实while中依然存在循环的三个必要条件,但是由于风格的问题使得三个部分偏离很远,这样查找修改就不够集中和方便,所以for循环更胜一筹.
for循环的使用频率也最高.

一些建议:

  1. 不要在for循环体内修改循环变量,防止for循环失去控制
  2. 建议for语句的循环控制变量的取值采用"前开后闭区间"的写法.[0 , 10)

3. do…while

//do...while语句格式
do
	循环语句;
while(表达式);

特点: 循环至少执行一次,使用的场景很局限.这里就不过多讲解了.

4. goto语句

goto本来不是为了循环而诞生的,但是与标签配合标记跳转可以实现循环,实践中没有goto语句也可以很容易的写出代码,一般不会使用goto,除非一些"必要情况".

  • 必要情况
    ->最常见的用法就是终止程序在某些深度嵌套的结构的处理过程,例如一次跳两层或多层循环.
    这样的情况使用break是达不到目的的,它只能从最内层退出到上一层的循环.而goto就可以直接跳转出去.
for(...){
	for(...){
		for(...){
			if(disaster)
				goto error;
		}
	}
}
error:
	if(disaster)
	//处理错误情况

goto这样循环语句中的"旁门左道",还是建议大家尽量不要采纳,

;