分支语句和循环语句

C语言是结构化的程序设计语言有顺序结构,选择结构,循环结构三种结构

分支语句

  • if
  • switch

循环语句

  • while
  • for
  • do while

goto语句

什么是语句?

C语言中由一个分号隔开的句子,就是一个语句

1
2
3
4
5
int main()
{
;//空语句
return 0;
}

if语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
语法结构:
if(表达式)
语句; //一个语句不用大括号,多个语句需要大括号,形成一个代码块

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

if(表达式)
语句1
else if(表达式)
语句2
else(表达式)
语句3;
1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
int age = 10;

if (age>=18)
printf("成年\n");

else
printf("未成年\n");

return 0;
}

再来一个例子,看看会暑促和什么

1
2
3
4
5
6
7
8
9
10
int main()
{
int age = 60;

if (age < 18)
printf("少年n");
else if (18<= age < 26)
printf("青年\n");
return 0;
}

结果输出是青年,那么为什么呢?因为这个写法是错误

来看一下else if的表达式,已经设定age的值为60,因此18<=age 为真,变成1,接着又是<26这个表达式,1<26为真,所以输出else if的语句,所以输出的是青年,而不为

正确的写法应该是

1
2
3
4
5
6
7
8
9
10
int main()
{
int age = 60;

if (age < 18)
printf("少年n");
else if (age >= 18 && age < 26)
printf("青年\n");
return 0;
}

因此if语句的操作逻辑是:如果表达式的结果为真,则语句执行

1
2
3
4
5
6
7
8
9
10
11
int main()
{
int a = 0;
int b =2;
if(a == 1)
if(b == 2)
printf("hehe\n");
else
printf("haha\n");
return 0;
}

结果是不打印,那么是为什么呢?

乍一看以为第一个ifelse对上,表达式不成立,直接看else,应该是haha啊,但是else是与它最近的if配对的,第一个if不成立,导致它管理的语句也不会执行,因此不会进行打印

当你遇到这种写代码的人,就可以拉出去枪毙

优化后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main()
{
int a = 0;
int b =2;
if(a == 1)
{
if(b == 2)
{
printf("hehe\n");
}
else
{
printf("haha\n");、
}
}
return 0;
}

所以代码风格很重要

来点小练习

判断一个数是不是奇数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main()
{
int num = 15;

if ( num %2 ==1 )
{
printf("奇数\n");
}
else
{
printf("偶数\n");
}

return 0
}

输出1-100之间的奇数

1
2
3
4
5
6
7
8
9
10
int main()
{
int i = 0;
for ( i = 1; i <= 100; i++)
{
if ( i % 2 == 1)
printf("%d ", i);
}
return 0;
}
1
2
3
4
5
6
7
8
9
int main()
{
int i = 0;
for ( i = 1; i <= 100; i+=2)
{
printf("%d ", i);
}
return 0;
}

switch语句

switch语句也是一种分支语句,常常用于多分支的情况

1
2
3
4
switch(整型表达式)
{
语句项;
}

但是语句项是什么呢

1
2
3
4
//是一些case语句
//如下:
case 整型常量表达式:
语句;

来个例子感受一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int main()
{
int day = 0;
scanf("%d", &day);
switch (day)
{
case 1:
printf("星期一\n");
break;//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;
}

如果是1-5工作日,67休息日呢?就可以这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
}
return 0;
}

break语句

实际效果是把语句列表划分为不同的部分

但是上述的例子输入别的值时没有反馈,应该怎么办呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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;//default 没有顺序,可以穿插在case语句中
}
return 0;
}

循环语句

while循环

与if语句十分相似

1
2
3
4
5
6
int main()
{
if (1)
printf("hehe\n");
return 0;
}

while的用法呢

1
2
3
//while 语法结构
while(表达式) //非0会一直进入循环
循环语句:
1
2
3
4
5
6
int main()
{
while (1)
printf("hehe\n");
return 0;
}

很好你现在进入了无限死循环

试着用while语句打印出1-10的数字

1
2
3
4
5
6
7
8
9
10
int main()
{
int i - 1;
while (i <= 10)
{
printf("%d ", i);
i++;
}
return 0;
}

while循环中,break只要被触发就会永久的终止循环

1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
int i - 1;
while (i <= 10)
{
if(i == 5)
break;

printf("%d ", i);
i++;
}
return 0;
}

结果是 1 2 3 4

那么我想让代码继续跑下去呢?那首先想到的肯定是continue,那写一个试试看

1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
int i - 1;
while (i <= 10)
{
if(i == 5)
continue;

printf("%d ", i);
i++;
}
return 0;
}

结果很奇怪,只有1 2 3 4 并且后面的光标还在闪烁,说明程序还在运行,也就是进入了死循环

因为在while循环中,continue的作用是跳过本次循环continue后边的代码,直接去判断部分,看是否进行下一次循环

来看一下别的代码

1
2
3
4
5
6
7
int main()
{
int ch = 0;
while ((ch = getchar()) != EOF)
putchar(ch);
return 0;
}

先来分析一下

getchar()

putchar()被执行时的过程

1
2
3
4
5
6
7
8
int main()
{
int ch = getchar();
//printf("%c\n", ch);
putchar(ch);//输出一个字符,可以完全替代上面的语句

return 0;
}

输入一个大写的A就会输出一个大写的A

已经知道了putchar()输出错误时会返回EOFend of file -文件的结束标志)

那么回到原语句

跑起来之后,就可以一直输入一个字符,输出一个相同的字符,如果想要停止的话可以输入ctrl + z

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main()
{
char password[20] = {0};
printf("请输入密码:>");
scanf("%s",password);//这里没有取地址的原因是,数组本身存储的就是地址
printf("请确认密码(Y/N):>");
int ch = getchar();
if (ch == 'y')
{
printf("确认成功\n");
}
else
{
printf("确认失败\n");
}
return 0;
}

但是运行之后发现,还没确认就接着确认失败是为什么呢?

因为不管getchat还是scanf都是输入函数,他们都需要去中间的缓冲区读取数据,而我们通过键盘来给缓冲区以信息而我们输入一个密码后需要回车进行确认。因此缓冲区的数据是xxxxx\n,而scanf拿走的只有xxxxx,剩下的\n就会在缓冲区等待,而getchar就会直接进行读取\n,因此就会直接显示结果。所以这就为我们修改代码提供了思路。我们应该进行清理缓冲区。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main()
{
char password[20] = {0};
printf("请输入密码:>");
scanf("%s",password);//这里没有取地址的原因是,数组本身存储的就是地址
printf("请确认密码(Y/N):>");
//清理缓冲区
getchar();//处理\n
int ch = getchar();
if (ch == 'y')
{
printf("确认成功\n");
}
else
{
printf("确认失败\n");
}
return 0;
}

这样刚才的问题就解决了,但是当我输入密码的时候是xxxxx xxxxx,它又变成了刚才的样子又是为什么呢?

因为此时的缓冲区是xxxxx xxxxx\n,而scanf之拿走了空格之前的字符,剩下的字符就又被剩下了,因此现在就需要使用while循环不团的清理缓存区剩下的字符,直到把\n也清理完

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int main()
{
char password[20] = {0};
printf("请输入密码:>");
scanf("%s",password);//这里没有取地址的原因是,数组本身存储的就是地址
printf("请确认密码(Y/N):>");
//清理缓冲区
//getchar();//处理\n
//清理缓冲区的多个内容
int tmp = 0;
while((tmp = getchar()) != '\n')
{
//空语句
}
int ch = getchar();
if (ch == 'y')
{
printf("确认成功\n");
}
else
{
printf("确认失败\n");
}
return 0;
}

试着用getchat来只进行打印数字

1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
int ch = 0;
while((ch=getchar()) != EOF)
{
if(ch < '0' || ch > '9')//在ASCII中代表的是除了48~57的字符,即除了0~9执行if语句
continue;//跳出本次循环继续打印

putchar(ch);
}
return 0;
}

for循环

进入for循环之前再看一遍之前打印1~10的代码

1
2
3
4
5
6
7
8
9
10
int main()
{
int i = 1;//初始化
while (i <= 10)//判断部分
{
printf("%d ", i);
i++;//调整部分
}
return 0
}

会发现影响这个代码的地方有三个地方,分别是初始化,判断部分,调整部分。但是由于后期会在这三者中间加入越来越多的代码,后期会变得很难调整,而for循环就可以解决这个痛点

语法结构

1
2
for(表达式1; 表达式2; 表达式3;)//初始化 ; 判断 ; 调整
循环语法;
1
2
3
4
5
6
7
8
9
int main()
{
int i = 0;
for(i=1;i<=10;i++)
{
printf("%d", i);
}
return 0;
}

该代码与上方效果一致

if中的continue是会从调整再次开始的

例如

1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
int i = 0;
for(i=1;i<=10;i++)
{
if(i==5)
continue;

printf("%d", i);
}
return 0;
}

这里就不会出现像是while语句会出现的死循环,而是从调整再次开始

结果就是

1
1 2 3 4 6 7 8 9 10

同时建议for语句的循环控制变量的取值采取“前闭后开区间”写法

1
2
3
4
5
6
7
8
9
10
int main()
{
int arr[10] = {0};
int i = 0;
for(i = 0; i < 10; i++) //前闭后开 i<=9就是前闭后闭区间
{
printf("%d", arr[i]);
}
return 0;
}

for循环的三个部分都可以被省略

1
2
3
4
5
6
7
8
9
int main()
{
//当判断部分被省略时 - 判断恒为真
for (;;)
{
printf("hehe\n");
}
return 0;
}

来判断一下下列循环会循环几次

1
2
3
4
5
6
7
8
int main()
{
int i = 0;
int k = 0;
for(i = 0.k=0; k=0; i++,k++)
k++;
return 0;
}

do while()循环

do语句的语法:

1
2
3
do
循环语句;
while(表达式);

执行流程

1
2
3
4
5
6
7
8
9
10
11
int main()
{
int i = 1;
do
{
printf("%d ",i);
i++;
}while(i<=10);

return 0;
}
1
1 2 3 4 5 6 7 8 9 10

先执行再进行判断!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main()
{
int i = 1;
do
{
if(i==5)
{
break;
}
printf("%d ",i);
i++;
}while(i<=10);

return 0;
}
1
1 2 3 4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main()
{
int i = 1;
do
{
if(i==5)
{
continue;
}
printf("%d ",i);
i++;
}while(i<=10);

return 0;
}
1
1 2 3 4

练习

n的阶乘

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int main()
{
int n,i;
int sum =1;
for(i=1;i<=n;i++)
{
sum = sum *i;
}
printf("%d\n",sum);
return 0;
}

计算1!+2!+3!+4!+…+10!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int main()
{
int i =0;
int n =0;
int ret = 1;
int sum =0;
for(n=1;n<=3;n++)
{
ret *=n;
sum +=ret;
}
printf("%d\n",sum);
return 0;
}

在一个有序数组中查找具体的某个数字n(二分查找)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9,10};
int k =7;//要查找的数字
int sz=sizeof(arr)/sizeof(arr[0]);//数组的元素个数
int left =0;
int right = sz-1;
while(left<=right)
{
int mid = (left+right)/2;
if(arr[mid]<k)
{
left = mid+1;
}
else if(arr[mid]>k)
{
right = mid-1;
}
else
{
printf("找到了,下标是:%d\n",mid);
break;
}
}
if(left>right)
{
printf("没找到\n");
}
return 0;
}

编写代码,演示多个字符从两端移动,向中间汇聚