一、前言
在我们的人生道路上,基本上逃不出这三种情况:一直往前走(顺序结构)、在分岔口上进行人生中重要的抉择(选择结构)、在一个周期内日复一日的重复一件事(循环结构)。
我们将这三种结构引入到C语言的编程当中,所以C语言是一门结构化的程序设计语言。
由于顺序语句就是从上往下按顺序执行,易于理解,故本章并未对其进行详细介绍。本章主要介绍分支语句和循环语句,另外再介绍C语言当中的goto语句。
二、本章重点
本章重点学习分支语句和循环语句的使用。
分支语句(选择结构) | 循环语句(循环结构) | goto语句 |
if switch | while for do while | goto |
三、什么是语句?
C语言中由一个分号 ; 隔开的就是一条语句。比如:
int main()
{
; // 空语句
1 + 2; // 语句
printf("hehe\n"); // 语句
return 0; // 语句
//}
Note:只有一个 ; 的语句也是一条语句,为空语句,在特殊场景下使用。
四、分支语句(选择结构)
如果你好好学习,校招时拿一个好offer,走上人生巅峰。
如果你不学习,毕业等于失业,回家卖红薯。
这就是选择!
![]() | ![]() |
1.if语句
①语法结构
// 单分支
if (表达式) // 如果表达式为真(非0),执行语句;如果表达式为假(0),不执行语句
语句;
// 双分支
if (表达式) // 如果表达式为真(非0),执行语句1;如果表达式为假(0),执行语句2
语句1;
else
语句2;
// 多分支
if (表达式1) // 如果表达式1成立,则只执行语句1
语句1;
else if (表达式2) // 如果表达式1不成立,表达式2成立,则只执行语句2
语句2;
else // 如果表达式1和表达式2都不成立,则只执行语句3
语句3;
Note:如果表达式的结果为真,则语句执行。在C语言中,0为假,非0为真。
比如:
// 代码1(单分支)
int main()
{
int age = 0;
scanf("%d", &age);
if (age < 18)
printf("未成年\n");
return 0;
}
// 代码2(双分支)
int main()
{
int age = 0;
scanf("%d", &age);
if (age < 18)
printf("未成年\n");
else
printf("成年\n");
return 0;
}
// 代码3(多分支)
int main()
{
int age = 0;
scanf("%d", &age);
if (age < 18)
printf("少年\n");
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
printf("老寿星\n");
return 0;
}
★Question:代码3中的条件表达式(age >= 18 && age < 30)写成(18 <= age < 30)可以吗?
★Answer:不可以。若age输入40,我们会发现终端输出青年,和我们的预期结果不一样。
(18 <= age < 30),程序先执行表达式左半部分18 <= age,条件为真(返回非0),表达式左半部分赋值为1;程序再执行表达式右半部分(1 < 30),条件为真。
(18 <= age < 30)表达式为真,该判断条件下的语句执行,终端输出青年。这是错误代码。
此时需要借助逻辑与操作符&&来帮助我们判断表达式真假,即(age >= 18 && age < 30)。这样当age输入40时,终端才会输出我们的预期结果——中年。
如果条件成立,要执行多条语句,则应该使用代码块 {}。
int main()
{
if (表达式)
{
语句列表1;
}
else
{
语句列表2;
}
return 0;
}
比如:
// 代码1
int main()
{
int age = 0;
scanf("%d", &age);
if (age > 18) // 未使用{},if语句只能控制第一条语句
printf("成年\n");
printf("可以谈恋爱\n"); // 此句代码不受if语句控制
return 0;
}
// 代码2
int main()
{
int age = 0;
scanf("%d", &age);
if (age > 18) // {}使得两条语句属于同一个逻辑,且代码阅读效果更好
{
printf("成年\n");
printf("可以谈恋爱\n"); // 若想此句代码块受if语句控制,需使用{}
}
return 0;
}
②悬空else
当你写了这个代码:
int main()
{
int a = 0;
int b = 2;
if (a == 1)
if (b == 2)
printf("hehe\n");
else
printf("haha\n");
return 0;
}
初学者可能以为终端会输出haha,但是运行却发现终端没有输出。这是因为上面代码的else是与第二个if进行匹配。
Note:else默认与距离最近且未匹配的if进行匹配(就近原则),而不是else和哪个if对齐就和哪个if进行匹配。
改正:
// 适当的使用{}可以使代码的逻辑更加清楚,代码风格很重要
int main()
{
int a = 0;
int b = 2;
if (a == 1)
{
if (b == 2)
{
printf("hehe\n");
}
}
else
{
printf("haha\n");
}
return 0;
}
改正后终端输出haha。加上代码块后,虽然else与第二个if距离最近,但是是与第一个if进行匹配。
③if书写形式的对比
请大家将下面的代码1与代码2比较阅读,代码3和代码4比较阅读,并评价哪种代码风格更优?
// 代码1
if (condition)
{
return x;
}
return y;
// 代码2
if (condition)
{
return x;
}
else
{
return y;
}
// 代码3
int num = 1;
if (num == 5)
{
printf("hehe\n");
}
// 代码4
int num = 1;
if (5 == num)
{
printf("hehe\n");
}
代码1是条件成立返回x,条件不成立返回y吗?
答案是肯定的。但不易看懂,可读性太差,写成代码2的风格会更好一些。
代码3如果条件判断句(num == 5)误写成(num = 5),代码还会按预期结果运行吗?
答案是否定的。(num = 5)是将5赋值给num,5为非0,条件判断始终为真,终端始终输出5,且不会报错。因此在比较常量和变量相等的时候,写成代码4的风格会更好一些,即将常量放在左边。代码4即使误写成(5 = num),也易于检查。因为变量num的值不能赋值给常量,编译都无法通过。
Note:代码风格非常重要,要养成良好的代码风格。在这里给大家推荐一本林锐博士编写的书籍《高质量程序设计指南——C++/C语言》,该书中详细介绍了如何规范地写代码。
④练习
<1>判断一个数是否为奇数
#include <stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
if (num % 2 == 1)
{
printf("%d是奇数\n", num);
}
else
{
printf("%d不是奇数\n", num);
}
return 0;
}
<2>输出1~100之间的奇数
#include <stdio.h>
int main()
{
int num = 1;
while (num <= 100)
{
if (num % 2 == 1)
{
printf("%d ", num);
num++;
}
else
{
num++;
}
}
return 0;
}
2.switch语句
①语法结构
switch语句也是一种分支语句。 常常用于多分支的情况。
比如:
- 输入1,输出星期一
- 输入2,输出星期二
- 输入3,输出星期三
- 输入4,输出星期四
- 输入5,输出星期五
- 输入6,输出星期六
- 输入7,输出星期七
写成if……else if……else if……的形式太复杂,那我们就得有不一样的语法形式。这就是switch语句。
switch (整型表达式)
{
case 整形常量表达式:
语句;
}
Note:switch后面跟整型表达式,case后面跟整型常量表达式。
②在switch语句中的break
在switch语句中,我们没法直接实现分支。搭配break使用才能帮助我们跳出switch语句,实现真正的分支。
比如:
// 代码1
int main()
{
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");
}
return 0;
}
// 代码2
int main()
{
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;
}
return 0;
}
代码1中当我们输入5时,终端输出星期五星期六星期天,此时我们已经看到了分支的影子,但貌似还并没有像我们预期的那样实现真正的分支。
代码2是实现分支的正确代码,需要搭配break使用。当我们输入5时,终端输出星期五,是我们预期的结果。通过case语句进入预期的分支,通过break语句跳出switch分支语句。
Note:case类似于分支语句的入口,进入我们预期的分支;break类似分支语句的出口,跳出switch分支语句。两者需搭配相互使用。
Note:我们要注意switch、case表达式的使用条件。
- 如果day用float定义(float day = 0;),switch (day)是错误代码,day必须是整型表达式。
- case 1.0是错误代码,case后面必须跟整型常量表达式。
- int n = 1; case n是错误代码,case后面必须跟整型常量表达式。
- case 1 + 0是正确代码,1 + 0是整型常量表达式。
有时候我们的需求变了:当输入1~5时,终端输出“weekday”;当输入6~7时,终端输出“weekend”。
所以我们的代码就应该这样实现了:
int main()
{
int day = 0;
scanf("%d", &day);
switch (day)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("weekday\n");
break;
case 6:
case 7:
printf("weekend\n");
break;
}
return 0;
}
case语句里面的break并非必须使用,要根据逻辑来选择加不加break;但是switch-case语句里面绝对不能出现continue。
Note:break语句的实际效果是把语句列表划分为不同的部分。
Note:在这里给大家介绍一个编程的好习惯,每次写switch语句时,最好在最后一个case语句里面加上一条break语句。
虽然最后一个case语句里面不加break语句也能正常走出分支结构,但是笔者的推荐写法可以避免出现在以前的最后一个case语句后面忘了添加break语句,后续再添加case语句时会产生bug的现象。
③default子句
如果表达的值与所有的case标签的值都不匹配怎么办?
其实也没什么,结构就是所有的语句都被跳过而已。程序并不会终止,也不会报错,因为这种情况在C中并不认为是个错误。
但是,如果你并不想忽略不匹配所有标签的表达式的值时该怎么办呢?
你可以在语句列表中增加一条default子句,把下面的标签写在任何一个case标签可以出现的位置。
default:
当 switch表达式的值并不匹配所有case标签的值时,这个default子句后面的语句就会执行。所以,每个switch语句中只能出现一条default子句。它可以出现在语句列表的任何位置,而且语句流会像贯穿一个case标签一样贯穿default子句。
比如:
int main()
{
int day = 0;
scanf("%d", &day);
switch (day)
{
default:
printf("输入数据有误,请输入1-7的数字\n");
break;
case 1:
case 2:
case 3:
case 4:
case 5:
printf("weekday\n");
break;
case 6:
case 7:
printf("weekend\n");
break;
}
return 0;
}
Note:在这里给大家介绍一个编程的好习惯,在每个switch语句中都放一条default子句,甚至可以在后边再加一个break。
④练习
<1>阅读下面代码,程序终端输出的结果是什么?
#include <stdio.h>
int main()
{
int n = 1;
int m = 2;
switch (n)
{
case 1:
m++;
case 2:
n++;
case 3:
switch (n) // switch允许嵌套使用
{
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。
五、循环语句(循环结构)
如果你买彩票没有中就老实学习,老实学习还是菜鸟就买彩票,买彩票没有中就老实学习,老实学习还是菜鸟就买彩票……
这就是循环!
日复一日年复一年,当你有朝一日买彩票中了500万,或者成为业界的大牛,就不用继续买彩票和老实学习,直接迎娶白富美。
这就是跳出循环!
|
1.while循环
①语法结构
我们已经掌握了if语句:当条件满足的情况下,if语句后的语句执行,否则不执行,但是这个语句只会执行一次。
然而我们发现生活中很多的实际的例子是:同一件事情我们需要完成很多次。
那我们怎么做呢?C语言中给我们引入了:while语句,可以实现循环。
while (表达式)
循环语句;
while循环的执行流程图 |
![]() |
比如我们用while循环实现:在屏幕上打印1~10的数字。
int main()
{
int i = 1;
while (i <= 10)
{
printf("%d ", i);
i = i + 1;
}
return 0;
}
②while循环中的break和continue
<1>break介绍
break在while循环中的作用:在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。
比如:
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
break; // 在循环中只要遇到break,就停止后期的所有的循环,直接终止循环
printf("%d ", i);
i = i + 1;
}
return 0;
}
终端的输出结果为1 2 3 4。
Note:while循环中的break是用于永久终止循环的。
<2>continue介绍
continue在while循环中的作用:在循环中只要遇到continue,本次循环中continue后边的代码不会再执行,而是直接跳转到while语句的判断部分,进行下一次循环的入口判断。
比如:
// 代码1
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
continue; // 在循环中只要遇到continue,本次循环中continue后边的代码不会再执行,而是直接跳转到while语句的判断部分,进行下一次循环的入口判断
printf("%d ", i);
i = i + 1;
}
return 0;
}
// 代码2
int main()
{
int i = 1;
while (i <= 10)
{
i = i + 1;
if (i == 5)
continue;
printf("%d ", i);
}
return 0;
}
代码1的终端输出结果为1 2 3 4 (死循环)。
代码2的终端输出结果为2 3 4 6 7 8 9 10 11。
Note:while循环中的continue是用于终止本次循环的,直接跳转到while语句的判断部分,进行下一次循环。
③练习
<1>下面代码是什么意思?
#include <stdio.h>
int main()
{
int ch = 0;
while ((ch = getchar()) != EOF)
putchar(ch);
return 0;
}
该代码为输入一个字符并将其输出,当遇到文件结束标志EOF时停止循环。
Note:
- getchar()函数的返回类型是整型,返回值是输入字符的ASCII码值或者EOF(-1)。因此定义整型变量ch来接收输入字符的ASCII码值或者EOF(-1)。
- putchar()函数将整数ch以对应ASCII码值的字符形式进行输出。
- EOF(end of file)是文件结束标志,值为-1。getchar()函数读取失败的时候就会返回EOF,Windows操作系统下键盘输入ctrl+z时输入EOF。
- scanf()函数和getchar()函数并不是直接从键盘上读取数据,实际上,键盘输入数据后,数据先存储在输入缓冲区中,然后scanf()函数和getchar()函数再从输入缓冲区中读取数据。因此,输入函数读取数据时,首先看输入缓冲区中有无数据,有数据直接读取数据,无数据等待键盘输入数据。
<2>下面代码是什么意思?
#include <stdio.h>
int main()
{
int ch = 0;
while ((ch = getchar()) != EOF)
{
if (ch < '0' || ch > '9')
continue;
putchar(ch);
}
return 0;
}
该代码为输入一个字符,输入字符为'0'~'9'时将该字符输出,输入字符为其他字符时则不输出,当遇到文件结束标志EOF时停止循环。
<3>基于以上两个问题的讲解,请设计一个输入密码并确认密码的使用场景。
有些同学可能会写出下面的错误代码:
#include <stdio.h>
int main()
{
printf("请输入密码:");
char password[10] = { 0 };
scanf("%s", password);
printf("是否确认密码(Y/N):");
int ret = getchar();
if (ret == 'Y')
{
printf("确认成功\n");
}
else
{
printf("放弃确认\n");
}
return 0;
}
当输入密码摁下回车键后,程序还未等我们是否确认密码终端就已经输出放弃确认了。
这是因为输入的密码被password读取走后,输入缓冲区还剩下最后摁下的回车键(字符为'\n')。这会导致getchar()函数将直接从输入缓冲区接收字符'\n',并将'\n'的ASCII码值传给ret,由于与字符'Y'不相等从而放弃确认。
因此我们需要在是否确认密码前先清空输入缓冲区,但下面的代码为什么依旧是错误的:
#include <stdio.h>
int main()
{
printf("请输入密码:");
char password[10] = { 0 };
scanf("%s", password);
printf("是否确认密码(Y/N):");
getchar();
int ret = getchar();
if (ret == 'Y')
{
printf("确认成功\n");
}
else
{
printf("放弃确认\n");
}
return 0;
}
当输入密码摁下回车键后,程序可以让我们是否确认密码了。这是因为getchar()函数将输入缓冲区里的残留字符'\n'读取清空了,输入缓冲区里没有数据,因此等待键盘输入数据来确认。
但是该代码错误的原因是,假如我们的密码为123456 abcd(有空格),我们发现程序又不能按照我们的预期结果运行了。
这是因为scanf()函数读取到空格就结束读取,输入缓冲区里还剩下 abcd,依旧不能是否确认密码,所以需要while循环将输入缓冲区全部读取清空。
下面为本题正确的代码:
#include <stdio.h>
int main()
{
printf("请输入密码:");
char password[10] = { 0 };
scanf("%s", password);
printf("是否确认密码(Y/N):");
while (getchar() != '\n')
{
;
}
int ret = getchar();
if (ret == 'Y')
{
printf("确认成功\n");
}
else
{
printf("取消确认\n");
}
return 0;
}
有些细心的同学可能会发现,实际上password存储的密码并不是123456 abcd,而是123456。
这是因为scanf()函数读取到空格就结束,至于想将密码存储空格并不是本章的重点,我们只需要掌握如何通过循环语句清空输入缓冲区就可以了。
2.for循环
①语法结构
for (表达式1; 表达式2; 表达式3)
循环语句;
表达式1为初始化部分,用于初始化循环变量的。表达式2为条件判断部分,用于判断循环时候终止。表达式3为调整部分,用于循环条件的调整。
for循环的执行流程图 |
![]() |
比如我们用for循环实现:在屏幕上打印1~10的数字。
int main()
{
int i = 0;
//for (i = 1/*初始化部分*/; i <= 10/*条件判断部分*/; i++/*调整部分*/)
for (i = 1; i <= 10; i++)
{
printf("%d ", i);
}
return 0;
}
Question:在循环结构中,已经存在了while循环,为什么还要出现一个for循环呢?
Example:现在我们对比一下for循环和while循环的结构。
int main() { int i = 0; // 实现相同的功能,使用while i = 1; // 初始化部分 while (i <= 10) // 条件判断部分 { printf("hehe\n"); i = i + 1; // 调整部分 } //实现相同的功能,使用for for (i = 1; i <= 10; i++) // 初始化部分,条件判断部分,调整部分 { printf("hehe\n"); } return 0; }
通过上面代码我们可以发现,while循环和for循环都存在循环的三个必要条件,但是二者的代码风格有所不同。
Answer:while循环的三个部分很可能偏离较远,这样查找修改就不够集中和方便。for循环的风格更胜一筹,将三个影响循环的部分集中起来,更好处理。 for循环使用的频率也最高。
②for循环中的break和continue
在for循环中也存在break和continue,他们的意义和在while循环中是一样的。
但是在代码风格上还是有些差异,请见下面代码:
// 代码1
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
if (i == 5)
break;
printf("%d ", i);
}
return 0;
}
// 代码2
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
if (i == 5)
continue;
printf("%d ", i);
}
return 0;
}
for循环不易出现死循环现象,这是因为for循环中的continue跳过continue后面的代码后,先调整循环变量,再进入条件判断部分,不容易造成死循环。
while循环易出现死循环现象,这是因为while循环中的continue跳过continue后面的代码后,有时并不调整循环变量,而是直接进入条件判断部分,容易造成死循环。
Note:在这里给大家介绍两个关于for循环的循环控制变量的编程的好习惯。
- 不可在for循环体内修改循环变量,防止for循环失去控制。
- 建议for语句的循环控制变量的取值采用“前闭后开区间”写法。
// 前闭后开的写法 for (i = 0; i < 10; i++) // 在该写法中循环10次一目了然 { printf("%d ", i); } // 两边都是闭区间 for (i = 0; i <= 9; i++) { printf("%d ", i); }
③一些for循环的变种
<1>for循环的三个部分的省略变种
比如:
int main()
{
for (;;)
{
printf("hehe\n");
}
return 0;
}
实际上,初始化、条件判断、调整三个部分在for循环中都可以省略。其中for循环的条件判断部分如果被省略,则判断条件恒为真,死循环。
Note:for循环的三个部分的省略容易造成程序bug,因此如果不是非常熟练,建议不要省略。
比如下面两个代码:
// 代码1 int main() { int i = 0; int j = 0; for (i = 0; i < 10; i++) { for (j = 0; j < 10; j++) { printf("hehe\n"); } } return 0; } // 代码2 int main() { int i = 0; int j = 0; for (; i < 10; i++) { for (; j < 10; j++) { printf("hehe\n"); } } return 0; }
代码1不必运行程序,观看代码就显然知道是在终端循环输出100次hehe。
但是如果把代码1的初始化部分省略掉,写成代码2的形式,程序终端应该打印几次hehe呢?
对于使用省略不熟练的同学,可能依旧想当然地认为和代码1一样在终端循环输出100次hehe,但是实际上是终端循环输出10次hehe。
i=0进入外层循环,内层循环输出10次hehe,j=10内层循环结束;i=1进入外层循环,此时j=10并未初始化,不满足条件判断部分,终端不输出hehe;……;i=9进入外层循环,此时j=10并未初始化,不满足条件判断部分,终端不输出hehe。因此代码2终端总共输出10次hehe。
通过上述可知,省略前和省略后结果大不相同,因此不要随便省略。
<2>for循环的循环控制部分可用多个循环变量控制变种
比如:
int main()
{
int x, y;
for (x = 0, y = 0; x < 2 && y < 5; ++x, ++y)
{
printf("hehe\n");
}
return 0;
}
在上面代码中,for循环的循环控制部分使用了x,y两个循环变量进行控制。
Note:for循环的循环控制部分也可以用两个及以上的循环变量来进行控制。
④练习
<1>阅读下面代码,请问循环要循环多少次?
#include <stdio.h>
int main()
{
int i = 0;
int k = 0;
for (i = 0, k = 0; k = 0; i++, k++)
k++;
return 0;
}
答案是该代码循环0次。
for循环的条件判断部分(k=0)是将0赋值给k,0为假,不进入循环结构,循环0次;
若条件判断部分(k=0)改成(k==0),则循环1次。
3.do...while()循环
①语法结构
do
循环语句;
while (表达式);
do...while()循环的执行流程图 |
![]() |
比如我们用do...while()循环实现:在屏幕上打印1~10的数字。
int main()
{
int i = 0;
i = 1;
do
{
printf("%d\n", i);
i++;
} while (i <= 10);
return 0;
}
Note:
- while循环、for循环是先判断在执行;do...while()循环是先执行再判断。
- while循环、for循环可能循环执行0次;do...while()循环至少执行一次。
- do...while()循环使用的场景有限,不是经常使用。
②do...while()循环中的break和continue
在do...while()循环中也存在break和continue,他们的意义和在while循环中是一样的。
为了帮助大家体验使用场景,请大家阅读下面代码:
// 代码1(break使用场景)
int main()
{
int i = 0;
do
{
if (5 == i)
break;
printf("%d ", i);
i++;
} while (i < 10);
return 0;
}
// 代码2(continue使用场景)
int main()
{
int i = 0;
do
{
if (5 == i)
continue;
printf("%d ", i);
i++;
} while (i < 10);
return 0;
}
代码1的终端输出结果为0 1 2 3 4。
代码2的终端输出结果为0 1 2 3 4 (死循环)。
六、分支语句与循环语句总练习
<1>计算n的阶乘。
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
int ret = 1;
int i = 0;
for (i = 1; i <= n; ++i)
{
ret = ret * i;
}
printf("%d\n", ret);
return 0;
}
<2>计算1!+2!+3!+……+n!。
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
int sum = 0;
int ret = 1;
int i = 0;
for (i = 1; i <= n; ++i)
{
ret = ret * i;
sum += ret;
}
printf("%d\n", sum);
return 0;
}
<3>在一个有序数组中查找具体的某个数字x。
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; // 有序数组
int left = 0;
int right = sizeof(arr) / sizeof(arr[0]) - 1;
int x = 0;
scanf("%d", &x); // 输入欲查找的数字x
int mid = 0;
// 折半查找(二分查找)
while (left <= right)
{
mid = (left + right) / 2;
if (x < arr[mid])
{
right = mid - 1;
}
else if (x > arr[mid])
{
left = mid + 1;
}
else
{
break;
}
}
if (left <= right)
{
printf("%d在该数组中的位序为%d\n", x, mid + 1);
}
else
{
printf("该数组中没有值为%d的数\n", x);
}
return 0;
}
<4>编写代码,演示多个字符从两端移动,向中间汇聚。
#include <stdio.h>
#include <Windows.h>
#include <stdlib.h>
int main()
{
char arr1[] = "For the ideal that I hold dear to my heart,I'd not regret a thousand times to die.";
char arr2[] = ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";
int left = 0;
int right = sizeof(arr2) / sizeof(arr2[0]) - 2;
while (left <= right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
Sleep(300); // 休眠操作,单位是ms,需包含<Windows.h>
system("cls"); // 清屏操作,system是库函数,用于执行系统命令,需包含<stdlib.h>
left++;
right--;
}
printf("%s\n", arr2);
return 0;
}
<5>编写代码,模拟用户登录情景,并且只能登录三次。(只允许输入三次密码,如果密码正确则提示登录成功,如果三次均输入错误则退出程序。)
#include <stdio.h>
#include <string.h>
int main()
{
char password[10];
int i = 1;
while (i <= 3)
{
printf("请输入密码:");
scanf("%s", password);
if (strcmp(password, "123456") == 0) // 两个字符串比较不能用(password == "123456")
{
break;
}
else
{
printf("密码输入错误,您还剩%d次输入密码的机会!\n", 3 - i);
i++;
}
}
if (i > 3)
{
printf("退出程序\n");
}
else
{
printf("登陆成功\n");
}
return 0;
}
<6>编写游戏,实现猜数字游戏。(计算机给一个1~100之间的随机数,用户在该范围内猜随机数为何值。)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
void menu()
{
printf("##########################\n");
printf(" Guess The Numbers Game \n");
printf(" 1.play \n");
printf(" 0.exit \n");
printf("##########################\n");
}
void game()
{
int rand_num = rand() % 100 + 1;
int guess_num = 0;
while (1)
{
printf("请输入你要猜的数字:");
scanf("%d", &guess_num);
if (guess_num > rand_num)
{
printf("猜大了,请继续猜@。@\n\n");
}
else if (guess_num < rand_num)
{
printf("猜小了,请继续猜@。@\n\n");
}
else
{
printf("牛波一,你猜对了~。~\n\n");
break;
}
}
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择(1/0):");
scanf("%d", &input);
switch (input)
{
case 1:
printf("游戏开始\n");
game();
break;
case 0:
printf("游戏退出\n");
break;
default:
printf("输入错误,请重新输入!\n");
break;
}
Sleep(500);
system("cls");
} while (input);
return 0;
}
七、goto语句
C语言中提供了可以随意滥用的goto语句和标记跳转的标号。从理论上goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程,例如一次跳出两层或多层循环。这种情况使用break是达不到目的的。它只能从最内层循环退出到上一层的循环。
goto语句真正适合的场景如下:
for (...)
{
for (...)
{
for (...)
{
if (disaster)
goto error;
}
}
}
error:
if(disaster)
// 处理错误情况
Note:
- goto语句不能跨函数跳跃,只能在本函数内跳跃。
- goto语句在代码里跳来跳去,易打乱代码流程,不推荐大家使用,了解其用法即可。
下面是使用goto语句的一个例子(一个关机程序):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char input[10] = { 0 };
system("shutdown -s -t 60");
again:
printf("电脑将在1分钟内关机,如果输入\"我是猪\",就取消关机!\n请输入:");
scanf("%s", input);
if (strcmp(input, "我是猪") == 0)
{
system("shutdown -a");
}
else
{
goto again;
}
return 0;
}
而如果不使用goto语句,则可以使用循环:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char input[10] = { 0 };
system("shutdown -s -t 60");
while (1)
{
printf("电脑将在1分钟内关机,如果输入\"我是猪\",就取消关机!\n请输入:");
scanf("%s", input);
if (0 == strcmp(input, "我是猪"))
{
system("shutdown -a");
break;
}
}
return 0;
}