请回答c语言-分支和循环结构【入门】
请回答c语言-分支和循环结构【入门】
目录
分支语句
- if
- switch
循环语句
- while
- for
- do while
goto语句
1.五种语句
一般C语句可分为以下五类:
- 表达式语句
- 函数调用语句
- 控制语句
- 复合语句
- 空语句
本章主要展开的是控制语句
控制语句用于控制程序的执行流程,以实现程序的各种结构方式,它们由特定的语句定义符组成
C语言有九种控制语句,可分成以下三类:
- 条件判断语句也叫分支语句:if语句、switch语句;
- 循环执行语句:do while语句、while语句、for语句;
- 转向语句:break语句、goto语句、continue语句、return语句。
2. 分支语句(选择结构)
2.1 if 语句
2.1.1 if 语句语法结构
那if语句的语法结构是怎么样的呢?
//语法结构:
//单
if(表达式)
语句;
//双
if(表达式)
语句1;
else
语句2;
//多分支
if(表达式1)
语句1;
else if(表达式2)
语句2;
else
语句3;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
if为真则执行语句,否则不执行该语句
回忆一下,上次说过在C语言中如何表示真假?
0表示假,非0表示真
2.1.1 if语句书写
for example:
#include <stdio.h>
int main()
{
int level = 0;
scanf("%%d", &level);
if (level < 16)
{
printf("小火龙
");
}
else if (level >= 16 && level < 36)
{
printf("火恐龙
");
}
else if(level>=36&&level<=100)
{
printf("喷火龙
");
}
else//悬垂else,最后一个else可以不用写条件
{
printf("不可能");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
切记不可以在选择语句打印火恐龙中这么写,没有这样的语法
if(16<=level<36)
- 1
注1:适当的使用{}可以使代码的逻辑更加清楚。
注2:else是和它离的最近的if匹配的。
2.1.2 if 语句代码风格
代码风格决定了可读性高低,也决定了他人对你代码的看法,如果要更好地提高优化代码风格
推荐食用《高质量c++/c编程指南》。
这里我们来看四种代码风格
代码2看上去明显比代码1更加规范,可读性更高
//代码1
if (condition) {
return x;
}
return y;
//代码2
if (condition)
{
return x;
}
else
{
return y;
}
//代码3
int num = 1;
if (num == 5)
{
printf("hehe
");
}
//代码4
int num = 1;
if (5 == num)
{
printf("hehe
");
}
- 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
要点:对于3,4我们其实可以学到,当我们要比较一个常量和一个变量的if表达式时:
如果有一天我们在判断语句中只写了一个=,那么就会导致if语句中始终为真了,那这句语句就可以直接执行,这就产生了一个bug,为了避免这个bug,有时候我们可以可以写成常量在前。因为当我们写错时,系统会主动报错,提示我们常量是不能赋值的,这就避免运行时出错再回去找问题在哪里。
小结:来一个练习
//打印1-100之间的奇数
int main()
{
int i = 0;
for(i=1;i<100;i++)
{
if (i %% 2 != 0)
printf("%%d ", i);
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
2.2 switch语句
switch语句也是一种分支语句。
为了方便if语句某些状况,常常用于多分支的情况。
比如:
输入1,输出LEBRON
输入2,输出CURRY
输入3,输出KD
输入4,输出HARDEN
输入5,输出PG
输入6,输出GIANNIS
输入7,输出077
那我没写成if…else if …else if 的形式太复杂,那我们就得有不一样的语法形式。
这就是switch 语句。
一般我们在写菜单的时候都会用到switch语句
2.2.1 switch的语句结构
这就是switch 语句。
当然我们之前说过switch是不能使用浮点型表达式的
switch(整型表达式)
{
语句项;
}
> 而语句项是什么呢?
//是一些case语句:
//如下:
case 整形常量表达式:
语句;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2.2.2 break in the switch
在switch语句中,我们没办法直接实现分支,没有break就不是真正的分支。每个语句加了break就会跳出这个switch循环语句
如果不加break语句就会一直往下顺序执行
int main()
{
int input = 0;
scanf("%%d", &input);
switch (input)
{
case 1:
printf("LEBRON
");
break;
case 2:
printf("CURRY
");
break;
case 3:
printf("KD
");
break;
case 4:
printf("HARDON
");
break;
case 5:
printf("PG
");
break;
case 6:
printf("GIANNIS
");
break;
case 7:
printf("077
");
break;
}
}
- 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
有时候我们的需求变了:
不加break可以实现多个整形常量表达式到一个语句,如下
int main()
{
int input = 0;
scanf("%%d", &input);
switch (input)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("LEBRON
");
break;
case 6:
printf("GIANNIS
");
break;
case 7:
printf("077
");
break;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
小结:
break语句 的实际效果是把语句列表划分为不同的分支部分
好习惯
在最后一个 case 语句的后面加上一条 break语句(之所以这么写是可以避免出现在以前的最后一个 case 语句后面忘了添加 break语句)
2.2.3 default
如果前面的case均不能匹配,就可以用到default,习惯上一般放在最后
如果没有default的情况下输入了不匹配的值,会发生什么,结果就是所有的语句都被跳过。程序并不会终止,也不会报错
但是,如果你并不想忽略不匹配所有标签的表达式的值时该怎么办呢?你可以增加一条default子句
当 switch 表达式的值并不匹配所有case 标签的值时,这个default 子句后面的语句就会执行
所以,每个switch语句中只能出现一条default子句,且可以出现在任何位置
小结:
好习惯:
在每个 switch 语句中都放一条default子句是个好习惯,甚至可以在后边再加一个 break 。
3. 循环语句
- while
- for
- do while
3.1 while循环
我们已经掌握了,if语句:
当条件满足的情况下,if语句后的语句执行,否则不执行。
但是这个语句只会执行一次。
那么当同一件事情我们需要完成很多次那我们怎么做呢?
C语言中给我们引入了: while 语句,可以实现循环。
对于while语句还是表达式为真就执行循环语句,为假就不执行
//while 语法结构
while(表达式)
循环语句;
- 1
- 2
- 3
3.1.1 while语句书写
比如我们实现:
还是打印1-100的奇数。
int main()
{
int i = 1;
while (i <= 100)
{
printf("%%d ", i);
i += 2;
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3.1.2 break and continue in while
3.1.2.1 break
以下给出一段有break的实例
#include <stdio.h>
int main()
{
int i = 1;
while(i<=10)
{
if(i == 5)
break;
printf("%%d ", i);
i = i+1;
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
这里代码输出的结果是 :
是 1 2 3 4 not 1 2 3 4 5
小结:
break在while循环中的作用:
在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。
3.1.2.2 continue
以下还是一段类似的代码用到了continue
continue的作用是跳过本次循环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
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
这里代码输出的结果是什么?
打出1 2 3 4之后就停不下来
小结:
continue在while循环中的作用就是:
continue是用于终止本次循环的,也就是本次循环中continue后边的代码不会再执行,而是直接跳转到while语句的判断部分。进行下一次循环的入口判断。
3.1.3 while循环例子
我们来看一些while例子
这段代码我们在之前的文章中有提到过
可以实现输入一段代码打印一段代码,最后想停下来就按CTRL+c
#include <stdio.h>
int main()
{
int ch = 0;
while ((ch = getchar()) != EOF)
putchar(ch);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
这里涉及到了多组输入的写法,在在线OJ题中也常常能见到
现在来解决一下什么是EOF?什么是getchar和putchar?
getchar函数是接受输入流的标准输入函数,当读取失败后会返回EOF
getchar和scanf类似,不同的是getchar只能用来打印标准输入(stdin)中的字符,而scanf可以打印浮点型和整型
putchar函数类似于printf,用来向标准输出(stdout)打印字符数据
具体了解getchar和putchar以及scanf缓冲区问题可以参考这位老铁的文章
3.2 for 循环
既然我们有了while循环,为什么我们还要有for循环呢?
3.2.1 语法
for(表达式1; 表达式2; 表达式3)
循环语句;
- 1
- 2
表达式1为初始化部分,用于初始化循环变量的。
表达式2为条件判断部分,用于判断循环时候终止。
表达式3为调整部分,用于循环条件的调整。
3.2.2 for语言的书写
下面来举一个实际例子:
使用for循环 在屏幕上打印1-100的奇数
int main()
{
for (int i = 1; i < 100; i+=2)
{
printf("%%d ", i);
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3.2.3 break and continue
3.2.3.1 break in the for
看一个代码
break是直接结束该循环的
所以这里只打印了1 2 3 4
3.2.3.2 continue in the for
还是一样的代码
continue只会跳过这次循环剩下的过程在
这里只是跳过5
3.2.4 for语句的循环控制变量
好习惯:
- 最好不要在for 循环体内修改循环变量,防止 for 循环失去控制。
- for语句的循环控制变量的取值建议采用“前闭后开区间”写法。
//前闭后开的写法
int i = 0;
for(i=0; i<10; i++)
{
...;
}
- 1
- 2
- 3
- 4
- 5
- 6
3.2.5 for循环的其他写法
1.for循环中的初始化部分,判断部分,调整部分是可以省略的
中间判断部分如果省略,则会构成死循环
for(;;)
{
printf("我是for循环
");
}
- 1
- 2
- 3
- 4
这种情况会导致另外一个问题
int i = 0;
int j = 0;
//这里打印多少个9012?
for (int i=0; i < 10; i++)
{
for (; j < 10; j++)
{
printf("9012
");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
应该是只有10次因为这里从i循环第二次开始,j循环始终不进入,最后只走i循环的次数,有10次,但是如果从一开始就写成for (j=0; j < 10; j++)
,就会打出100次,原因显然
小结:
for循环是平时使用很多的循环
3.3 do while 循环
do while循环至少执行一次,可是这个语句使用的场景有限,所以不是经常使用。
3.3.1 do while语句的语法
do
循环语句;
while(表达式);
- 1
- 2
- 3
3.3.2 do while 语句的书写
只执行一次的情况
int main()
{
int i = 10;
do
{
printf("%%d
", i);
} while (i < 10);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
3.3.3 do while循环中的break和continue
3.3.3.1 break in the do while
还是一样跳出循环打印一个10
int main()
{
int i = 10;
do
{
if (5 == i)
break;
printf("%%d
", i);
} while (i < 10);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
3.3.3.2 continue in the do while
死循环 ,i无法变成其他数字于是一直在循环
int main()
{
int i = 10;
do
{
if (5 == i)
continue;
printf("%%d
", i);
} while (i < 10);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
4.练习提高
- 计算 n的阶乘
int main()
{
int n = 0;
scanf("%%d", &n);//5
int i = 0;
int ret = 1;
for (i = 1; i <= n; i++)
{
ret = ret * i;
}
printf("%%d
", ret);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 计算 1!+2!+3!+……+10!
int main()
{
int n = 0;
int i = 0;
int ret = 1;
int sum = 0;
for (n = 1; n <= 10; n++)
{
ret = 1;//再从1开始乘,这步不能忘
for (i = 1; i <= n; i++)
{
ret = ret * i;
}
sum += ret;
}
printf("%%d
", sum);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 打印99乘法表
int main()
{
int i = 0;
int j = 0;
for (i = 1; i <= 9; i++)
{
for (j = 1; j <= i; j++)
{
printf("%%d*%%d=%%d",i,j, i * j);
printf(" ");
}
printf("
");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
输出如下:
- 在一个有序数组中查找具体的某个数字n。(二分查找法)
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);//取得数组长度写法
int num = 0;
scanf("%%d",&num);
int left = 0;
int right = sz - 1;
while (left<=right)
{
int mid = (left + right) / 2;
if (arr[mid] < num)
{
left = mid + 1;
}
else if (arr[mid] > num)
{
right = mid - 1;
}
else
{
printf("找到了,下标是:%%d
", mid);
break;
}
}
if (left > right)
{
printf("找不到
");
}
return 0;
}
- 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
- 编写代码,演示多个字符从两端移动,向中间汇聚。
用到的特殊函数:
为了实现汇聚的变化所以要用sleep函数 所以要调用windows.h,这样可以有一个延时的效果
为了用字符串的长度要用string.h中的字符串函数也就是strlen
int main()
{
char arr1[] = "I can do all things";
char arr2[] = "###################";
int left = 0;
int right = strlen(arr1) - 1;
printf("%%s
", arr2);
//while循环实现
while (left <= right)
{
Sleep(500);
arr2[left] = arr1[left];
arr2[right] = arr1[right];
left++;
right--;
printf("%%s
", arr2);
}
//for循环实现
for (left = 0, right = strlen(arr1) - 1;
left <= right;
left++, right--)
{
Sleep(500);
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%%s
", arr2);
}
return 0;
}
- 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
- 编写一个密码
输错三次自动跳出
#include<stdio.h>
#include<string.h>
int main()
{
int i = 0;
char password [20]="";
//这里我们假设密码是123456
for (i = 0; i < 3; i++)
{
printf("请输入密码:");
scanf("%%s",password);//password不取地址的原因是password是数组名,数组名本来就是地址
if(strcmp(password,"123456")==0);//比较两个字符串是否相等要用strcmp函数
{
printf("登陆成功
");
break;
}
else
{
printf("密码错误
");
}
}
if(3==i)
{
printf("输错三次密码退出程序
");
}
return 0;
}
- 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
我们需要知道strcmp如何使用,查询MSDN,
strcmp 在MSDN上是这么写的:
返回值:
- 猜数字游戏(电脑随机生成1-100)的数字
玩家猜小了,电脑会告诉你猜小了,同理猜大了和猜的对
本小游戏需要生成随机数,如何生成随机数?
用rand srand 和time
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
void menu()
{
printf("***************************
");
printf("***** 1. play ******
");
printf("***** 0. exit ******
");
printf("***************************
");
}
void game()
{
int guess = 0;
//猜数字游戏的过程
//播撒随机数种子
int r=rand()%%100+1;
//猜数字
while(1)
{
printf("猜数字:
");
scanf("%%d",&guess);
if(guess<r)
{
printf("猜小了
");
}
else if(guess>r)
{
printf("猜大了
");
}
else
{
printf("恭喜你,猜对了!
");
break;
}
}
}
int main()
{
int input=0;
srand((unsigned int)time(NULL));//放在主函数里面只要一次就够了
do
{
//打印菜单
menu();
printf("请选择");
scanf("%%d",&input);
switch(input)
{
case 1:
game();
break;
case 0:
printf("退出游戏
");
break;
default:
printf("选择错误
");
break;
}
}while(input);
return 0;
}
- 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
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
注:随机数取值可以从0-RAND_MAX,RAND_MAX是32767,注意要把范围改到范围1-100
为了保证随机数每次都不同,我们不仅要用rand还要用srand
srand需要用时间戳来随机播撒种子,关于时间戳的概念可以自行搜索,利用time函数,如下:
小结:
做完这几道练习题,会对分支与循环结构会有更深理解,想要学好c语言老铁要继续坚持!
下一章会主要从函数讲起