业精于勤荒于嬉,行成于思毁于随。
在笔者初阶的文章里,已经介绍过分支和循环语句,不过由于是初阶,所以并不细致,今天我们正式打开了中阶的大门,开始一步一步的深入C语言的学习。
C语言是结构化的程序设计语言,那么今天这一篇,我们来说一说分支和循环语句的一些知识。
第七篇
一、什么是语句?
C语言的语句可以分为五类:
- 、表达式语句
- 、函数调用语句
- 、控制语句
- 、复合语句
- 、空语句
我们主要介绍的是控制语句。
控制语句用于控制程序的执行流程,以实现程序的各种结构方式,它们由特定的语句定义符组成,C语言有九种控制语句。
分为以下三类:
1、条件判断语句,也叫分支语句:if语句、switch语句
2、循环执行语句,do while语句、while语句、for语句
3、转向语句,break语句、goto语句、continue语句、return语句
二、C语言是结构化的程序设计语言
1、顺序结构
顺序结构就没什么可讲的了,就是从上至下依次执行的结构。
2、选择结构(if、switch)
2.1、if语句语法结构
if(表达式)
语句
int age = 0;
scanf("%d", &age);
if (age >= 18)
printf("成年\n");
return 0;
如果表达式的结果真,就执行;如果表达式的结果为假,就不执行。
注意,C语言中如何表示真假?0就是假,非0就是真
if(表达式)
语句1
else
语句2
int age = 0;
scanf("%d", &age);
if (age >= 18)
printf("成年\n");
else
printf("未成年\n");
return 0;
如果表达式成立,就执行语句1,否则执行语句2
多分支:
if(表达式1)
语句1
else if(表达式2)
语句2
else
语句3
int age = 0;
scanf("%d", &age);
if (age < 18)
printf("青少年\n");
//注意,不可以写成 18<=age<=30 这种写法是错误的
else if (age >= 18 && age < 30)
printf("青年\n");
else if (age >= 30 && age < 50)
printf("中年\n");
else if (age >= 50 && age < 80)
printf("中老年\n");
else if (age >= 80 && age < 100)
printf("老年\n");
else
printf("老寿星\n");
return 0;
如果表达式1成立,就执行语句1,否则判断表达式2,如果表达式2成立,就执行语句2;如果表达式1和2都不成立,就执行语句3
如果需要执行多条语句,就使用大括号 “ { } ” 括起来。如:
if (age < 18) {
printf("青少年\n");
printf("好好学习\n");
}
2.2、悬空else
int a = 0;
int b = 2;
if (a == 1)
if (b == 2)
printf("hehe\n");
else
printf("haha\n");
return 0;
那么这段代码的结果是什么呢?其实它没有任何结果,因为else匹配的是最近的一个if,也就是说,这个排版具有欺骗性,最终什么也没有执行。真实的排版应该这样:
int a = 0;
int b = 2;
if (a == 1)
if (b == 2)
printf("hehe\n");
else
printf("haha\n");
return 0;
所以,为了代码的可读性,一定记得分隔,或者使用大括号:
int a = 0;
int b = 2;
if (a == 1) {
if (b == 2)
printf("hehe\n");
}
else
printf("haha\n");
return 0;
2.3、if书写形式的对比
if (condition)
{
return x;
}
return y;
这段代码的意思也是条件满足就返回x,否则返回y。因为只要返回了,就不会继续向下执行代码。
但是可读性不如下面的代码段:(推荐使用下面的代码风格)
if (condition)
{
return x;
}
else
{
return y;
}
再来看这种代码:
int num = 1;
if (num == 5)
printf("haha\n");
我们应该都是这样书写代码,但是这种代码逻辑上不如这样书写规范:
int num = 1;
if (5 == num)
printf("haha\n");//这种写法更容易发现一些细节的问题,所以推荐这样书写
判断变量与常量是否相等时,把常量放在等号的左边是一种好习惯。
2.4、switch语句
我们想实现一个功能,就是输入的数字对应上星期。
比如,输入1,就输出星期一。输入2,就输出星期二。该怎么实现?
使用switch语句:
switch(整形表达式)
{语句项}
那么语句项是什么?是一些case语句
case 整形常量表达式:
语句;
int day = 0;
scanf("%d", &day);
switch (day)
{
case 1:
printf("星期一\n");
case 2:
printf("星期二\n");
case 3:
printf("星期三\n");
case 4:
printf("星期四\n");
case 5:
printf("星期五\n");
case 6:
printf("星期六\n");
case 7:
printf("星期日\n");
}
但这样好像没有达到我们的需求,因为我们想的是只输出一个,这一下把后面的也输出了,为什么?
因为switch语句只决定从哪进入,而不会去管执行到哪,所以我们需要加上break来限制执行的语句:
int day = 0;
scanf("%d", &day);
switch (day)
{
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;
}
所以我们可以根据需求来跳出语句,不一定每一个语句项都使用一次break。
一般而言,switch语句会添加default情况,也就是所有的case都没匹配,去执行的语句。一般写在最后,且添加break语句。
我们来看一看switch语句的一个小题目吧:
#include<stdio.h>
int main()
{
int n = 1;
int m = 2;
switch (n)
{
case 1:
m++;
case 2:
n++;
case 3:
switch (n)
{
case 1:
n++;
case 2:
m++; n++;
break;
}
case 4:
m++;
break;
default:
break;
}
printf(" m = %d,n = %d \n", m, n);
return 0;
}
答案是 m=5,n=3。
注意break只跳出一层。
3、循环结构中的while
3.1、while语句
int i = 0;
while (i < 10)
{
printf("%d ", i);
i++;
}
我们从这段代码来看一看while循环的逻辑:
while后面的括号用来书写表达式,表达式的作用就是判断是否执行循环的语句,所以我们需要及时更改循环有关的一些变量。当判断为假的时候,循环终止。我们可以在循环里使用break和continue语句。
关于break,我们应该也比较熟悉了,就是给一个判断条件,达到条件就跳出这一层循环。那么continue呢?
#include<stdio.h>
int main()
{
int i = 0;
while (i < 10)
{
if (5 == i)
continue;
printf("%d ", i);
i++;
}
return 0;
}
结果如图:
continue的作用就是跳过本次循环,跳转到while循环的判断部分,进入下一次循环的入口判断,执行后一次循环(这个程序终止的原因是i++没有执行)。
3.2 while循环中的EOF
EOF就是end of file,也就是文件结束标志。
我们来看看循环判断条件带有EOF的代码:
int main()
{
int ch = 0;
while ((ch = getchar()) != EOF)//读到的结果不等于EOF,就循环
{
putchar(ch);
}//那么怎么返回EOF?ctrl+z即可
return 0;
}
可以看到,这段代码的结果是同步输出(可以参考下图getchar的返回值简介),最后按下ctrl和z退出循环。(这里注意,对于scanf来说,这两个按键不一定起作用,这是vs编译器本身的问题)
3.3附加:关于scanf和getchar
我们先来看一段代码:
#include<stdio.h>
int main()
{
char password[20] = { 0 };
printf("请输入密码:\n");
scanf("%s", password);
printf("请确认密码(Y/N):\n");
int ch = getchar();
if ('Y' == ch)
printf("确认成功\n");
else
printf("确认失败\n");
}
结果如下:
可以看到,我们并没有输入Y或者N,程序自己就输出了,这是为什么?
这就需要我们理解一下缓冲区的概念了,如图:
那么这段代码就是这样的:
我们首先输入了密码,密码的数据值被password
接收,但是缓冲区还剩余一个‘\n’
,所以getchar读取了‘\n’
,之后进行判断,程序继续执行。
那么我们怎么改进这段代码?很简单,处理掉回车就可以,也就是说,我们再写一个getchar()
:
#include<stdio.h>
int main()
{
char password[20] = { 0 };
printf("请输入密码:\n");
scanf("%s", password);
getchar();
printf("请确认密码(Y/N):\n");
int ch = getchar();
if ('Y' == ch)
printf("确认成功\n");
else
printf("确认失败\n");
}
注意scanf只读取空格或者回车之前的数据,所以如果我们输入了123456 abcdef 程序依然会自行判断,因为缓冲区还有数据,那么该怎么改进?
#include<stdio.h>
int main()
{
char password[20] = { 0 };
printf("请输入密码:\n");
scanf("%s", password);
//getchar();
int tmp = 0;
while ((tmp = getchar()) != '\n')
{
;
}
printf("请确认密码(Y/N):\n");
int ch = getchar();
if ('Y' == ch)
printf("确认成功\n");
else
printf("确认失败\n");
}