分支语句和循环语句
分支语句
- if
- switch
循环语句
- while
- for
- do while
goto 语句
C语言是结构化的程序设计语言,分为顺序结构,选择结构,循环结构
1.什么是语句?
C语句可以分为以下五类:
- 表达式语句
3 + 5;
- 函数调用语句
printf("hehe");
- 控制语句
- 复合语句
- 空语句
;
控制语句用于控制程序的执行流程,以实现程序的各种结构方式,它们由特定的语句定义符组成,C语言有九种控制语句.
可分为以下三类:
- 条件判断语句也叫分支语句:
if
语句,switch
语句`; - 循环执行语句:
do while
语句,while
语句,for
语句`; - 转向语句:
break
语句,goto
语句,continue
语句,return
语句.
2.分支语句(选择结构)
如果好好学习,将来你会有一个更好的选择.
如果不学习,回家卖红薯.
这就是选择!
2.1 if语句
if语句的语法结构:
//单分支
if(表达式)
语句;
//双分支
if(表达式)
语句;
else
语句;
//多分支
if(表达式1)
语句;
else if (表达式2)
语句;
else
语句;
//代码1
#include <stdio.h>
int main(void)
{
int age = 0;
scanf("%d", &age);
//单分支
if(age < 18)
{
printf("未成年\n");
}
return 0;
}
//代码2
#include <stdio.h>
int main(void)
{
int age = 0;
scanf("%d", &age);
//双分支
if(age < 18)
{
printf("未成年\n");
}
else
{
printf("成年\n");
}
return 0;
}
//代码3
int main(void)
{
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;
}
在选择结构中,只执行 if
表达式为真时后面的语句块若表达式全为假,则都不执行,有 else
时执行 else
后面的语句块
C语言中,0表示假,非0表示真
2.1.1 悬空else
当写了如下代码
#include <stdio.h>
int main(void)
{
int a = 0;
int b = 2;
if (a == 1)
if (b = 2)
printf("hehe\n");
else
printf("haha\n");
return 0;
}
上述代码并没有任何结果
根据原作者的代码缩进可以得出,else
本应表示 a != 1
的情况,但C语言会忽视代码缩进,else
和自己最近的 if
进行匹配,其实判断完 a == 1
为假后,直接跳出了判断,代码终止.
这就需要我们需要良好的代码风格,应如下
#include <stdio.h>
int main(void)
{
int a = 0;
int b = 2;
if (1 == a)
{
if (2 == b)
printf("hehe\n");
}
else
{
printf("haha\n");
}
return 0;
}
上述代码打印出了 haha
.
同时,判断变量是否等于一个字面量时,更推荐类似于上面 1 == a
的写法,这样如果中间的 ==
误写成 =
时,编译器会直接编译不通过,减少许多麻烦.养成良好的代码风格是十分重要的.
这里推荐一本教程: 林锐 博士 出版的<高质量的C/C++编程风格>
2.1.2 if书写形式的对比
//代码1
if (condition){
return x;
}
return y;
//代码2
if (conditon)
{
return x;
}
else
{
return y;
}
//代码3
int num = 1;
if (num == 5)
{
printf("hehe\n");
}
//代码4
int num = 1;
if (5 == m)
{
printf("hehe\n");
}
上述的代码1和代码2,代码3和代码4,所表示的逻辑是一样的,但更推荐代码2和代码4的写法
代码2和代码4逻辑清晰,不容易出错,写出一个不仅自己能看得懂,更能让其他人也能快速明白程序的逻辑的代码,这是一个程序员必备的能力.
2.1.2 练习
- 判断一个数是否为奇数
- 输出 1-100 之间的奇数
//1.判断一个数是否为奇数
#include <stdio.h>
int main(void)
{
int num = 0;
scanf("%d", &num);
if (num % 2 == 1)
{
printf("%d是奇数\n");
}
else
{
printf("%d是偶数\n");
}
return 0;
}
//2.输出 1-100 之间的偶数
# include <stdio.h>
int main(void)
{
int i = 1;
while (i <= 100)
{
//判断如果i是偶数的话,就输出i
if (i % 2 == 0)
{
printf("%d ", i);
}
++i;
}
return 0;
}
2.2 switch语句
switch
语句也是一种分支语句.常常用于多分支的情况.
比如:
输入1,输出星期一
输入2,输出星期二
输入3,输出星期三
输入4,输出星期四
输入5,输出星期五
输入6,输出星期六
输入7,输出星期日
相比 if...eles if...else if...else
的形式,switch
语句更为简洁
switch(整型表达式)
{
case 整型常量表达式:
语句;
case 整型常量表达式:
语句;
...
}
需要注意的是,C语言的 switch
语句只支持整型表达式.整型常量表达式简便点说就是整型字面量.
学习完 switch
语句,对于上面的多分支情况,可能会打出如下代码
#include <stdio.h>
int main(void)
{
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;
}
发现并没有预期的效果,这里就要引入 break
关键字.
2.2.1 在switch语句中的break
在 switch
语句中,我们没办法直接实现分支,搭配 break
使用才能真正的实现分支.
#include <stdio.h>
int main(void)
{
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,输出weekday
- 输入6-7,输出weekend
代码应该这样实现:
#include <stdio.h>
int main(void)
{
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;
}
所以说,并不是每一分支都必须用到 break
,关键看需求,break
的作用就是跳出循环,在这的效果就是实现了 switch
语句的分支结构.
2.2.2 default语句
如果表达的值与所有的case标签的值都不匹配怎么办?
其实也没什么,结构就是所有的语句都被跳过而已.
程序并不会终止,也不会报错,因为这种情况中在C中并不认为是个错误.
但是如果不想忽略不匹配所有标签的表达式的值应该怎么办呢?
可以在语句列表中增加一条 default
语句.
default
可以出现在任何一个 case
语句出现的位置上.
当 switch
表达式的值并不匹配所有的 case
标签的值时,这个 default
子句后面的语句就会执行.
所以,每个 switch
语句中只能出现一条 default
子句.
但是他可以出现在语句列表的任何位置,而且语句流会像执行一个 case
标签一样执行 default
子句.
2.2.3练习
#include <stdio.h>
int main(void)
{
int n = 1;
int m = 2;
switch (n)
{
case 1:
m++; //执行 m = 3
case 2:
n++; //执行 n = 2
case 3:
switch (n)
{
case 1:
n++; //不执行
case 2:
m++;
n++; //执行 m = 4, n = 3
break;
}
case 4:
m++; //执行 m = 5
break;
default:
break;
}
printf("m = %d, n = %d\n", m, n);
return 0;
}
最终结果是 m = 5, n = 3
3. 循环语句
- while
- for
- do while
3.1 while循环
我们已经掌握了,if
语句
if(condition)
{
suit;
}
当这个条件满足的情况下,if
语句后的语句执行,否则不执行.
但是这个语句只会执行一次.
由于我们发现生活中很多的实际的例子是:同一件事情我们需要完成很多次.
那我们怎么做呢?
C语言给我们引入了:while
语句,可以实现循环.
while(condition)
{
suit;
}
while
语句执行的流程:
比如实现:
在屏幕上打印1-10的数字
#include <stdio.h>
int main(void)
{
int i = 1;
while (i <= 10)
{
printf("%d ", i);
++i;
}
return 0;
}
3.1.1 while语句中的break和continue
break介绍
#include <stdio.h>
int main(void)
{
int i = 1;
while (i <= 10)
{
if (i == 5)
{
break;
}
printf("%d ", i);
++i;
}
return 0;
}
上述代码输出的结果是1 2 3 4
总结:
break
在while
循环中的作用:
在循环中,只要遇到break
,就终止所有后续代码的执行,并且跳出循环.
在while
中,break
的作用就是永久终止循环
continue介绍
#include <stdio.h>
int main(void)
{
int i = 1;
while (i <= 10)
{
if (i == 5)
{
continue;
}
printf("%d ", i);
++i;
}
return 0;
}
上述代码输出的结果是1 2 3 4
,并且程序没有终止.
若++i
移到判断前呢
#include <stdio.h>
int main(void)
{
int i = 1;
while (i <= 10)
{
++i;
if (i == 5)
{
continue;
}
printf("%d ", i);
}
return 0;
}
上述代码的结果是2 3 4 6 7 8 9 10 11
总结:
continue
在循环中的作用:
终止本次循环中continue
后的代码,直接去while
的判断部分.
最后再看几个代码
- 代码1
#include <stdio.h>
int main(void)
{
int ch = 0;
while((ch = getchar()) != EOF)
{
putchar(ch);
}
return 0;
}
这个代码内容是读取你输入的字符并且将它输出到屏幕中,直到输入EOF
EOF
:end of file 在C语言对应的值是-1,因为字符类型的值是从0开始的
windows输入ctrl + z来表示EOFgetchar()
:读取成功,返回读取的ASCII码值
读取失败,返回EOF
对这个代码进行适当的修改,是可以用来清理缓存区的
这里引入了缓存区的概念,先从scanf()
和getchar()
读取输入的过程来说
以输入密码并确定这一操作来举例
#include <stdio.h>
int main(void)
{
char password[20] = {0,};
char input = 0;
printf("请输入你的密码:");
scanf("%s", password);
printf("请确认密码(Y/N)");
scanf("%c", &input);
if ('Y' == input)
{
printf("确认成功\n");
}
else
{
printf("确认失败\n");
}
return 0;
}
运行上述代码发现,输入密码后,没有给我确认的机会就直接确认失败了
现在研究一下这个代码的过程
- 键盘输入,输入的值存入缓存区.
比如我输入123456后,输入回车,表示我输入完毕
这时候缓存区里面存放了123456\n
- 第一次调用
scanf()
,scanf()
从缓存区里读取\n
之前的输入,如果此时缓存区空,则该函数进行等待 - 第二次调用了
scanf()
,这时缓存区还剩\n
,scanf()
直接读取了\n
并将该值与input
进行绑定 - 最终确认失败
那该如何修改这段代码,使之能满足我们的需求呢?
这里就要用到刚才说的,清理缓存区的方式,在输入input
的值之前,将缓存区清理干净
进行了这样的修改后,就能达到需求了
#include <stdio.h>
int main(void)
{
char password[20] = {0,};
char input = 0;
printf("请输入你的密码:");
scanf("%s", password);
printf("请确认密码(Y/N)");
while(getchar() != '\n')
{
;
}
input = getchar();
if ('Y' == input)
{
printf("确认成功\n");
}
else
{
printf("确认失败\n");
}
return 0;
}
在给input
输入值之前,我先将包含\n
之前的所有字符都使用getchar()
接收了,因为getchar()
并没有左值,这些值可以说被清空了,这个时候缓存区已经空了.
随后我进行正常给input
进行赋值,这个修改最终满足了需求.
- 代码2
#include <stdio.h>
int main(void)
{
char ch = '\0';
while ((ch = getchar()) != EOF)
{
if (ch < '0' || ch > '9')
{
continue;
}
putchar(ch);
}
return 0;
}
这段代码从键盘读取输入,如果输入的不是0-9的数字,直接跳过本次循环.如果输入的时0-9的数字,打印数字字符.
3.2 for循环
这里有一个打印1-10的while
循环代码
#include <stdio.h>
int main(void)
{
int i = 1; //1.初始化
while (i <= 10) //2.判断
{
printf("%d ", i);
++i; //3.调整
}
return 0;
}
发现控制循环有三个步骤:1.初始化 2.判断 3.调整
但是,这只是一个简单的打印1-10的代码.如果需要执行的语句不只是printf()
这一条,而是很多很复杂的语句,再找到对应的步骤就很困难,也很容易漏掉步骤,导致循环往出乎意料的结果发展.
相比,在确定循环首尾的情况下,for
循环更为简洁明了,易于控制理解.
3.2.1 语法
for (表达式1; 表达式2; 表达式3)
循环语句;
表达式1
表达式1为初始化部分,只执行进入for
循环条件判断之前的那一次
表达式2
表达式2为条件判断部分,用于判断循环是否终止
表达式3
表达式3为调整部分,用于调整循环条件
第一次进入for
循环步骤:表达式1->表达式2->循环语句->表达式3
之后循环步骤;表达式2->循环语句->表达式3
使用for
循环打印1-10代码如下
#include <stdio.h>
int main(void)
{
int i = 0;
//表达式1: i = 1 初始化
//表达式2: i <= 10 条件判断 判断为真执行循环语句
//表达式3: ++i 调整
for (i = 1; i <= 10; ++i)
{
printf("%d ", i);
}
return 0;
}
相比与while
循环,for
循环三个表达式更为集中,对循环的进出更为简洁明了.使用更为频繁.
3.2.2 break和continue在for循环中
for
循环中也可以出现break
和continue
关键字来控制循环,它们在for
循环中的功能和在while
循环中的功能是一样的
break
:
#include <stdio.h>
int main(void)
{
int i = 0;
for (i = 1; i <= 10; ++i)
{
if (5 == i)
{
break;
}
printf("%d ", i);
}
return 0;
}
上面这段代码的结果是
当5 == i
这个表达式判断为真后,执行相应的语句break
,跳出循环,并没有继续进行打印和循环
continue
#include <stdio.h>
int main(void)
{
int i = 0;
for (i = 1; i <= 10; ++i)
{
if (5 == i)
{
continue;
}
printf("%d ", i);
}
return 0;
}
上面这段代码的结果式
当5 == i
这个表达式判断为真后,执行相应的语句continue
,跳过本次循环,没有继续进行本次循环中的打印,++i
后条件判断为真,继续循环.
3.2.3 for语句的循环控制变量
建议:
- 在C语言中,建议不要在初始化时定义变量,这是
C++
的写法,C99标准后引入,若编译器不支持则会出现报错- 不可在
for
循环体内修改循环变量,防止for
循环失去控制- 建议
for
语句的循环控制变量的取值采用"前闭后开区间"写法
3.2.4 一些for循环的变种
//代码1
#include <stdio.h>
int main(void)
{
for(;;)
{
printf("hehe\n");
}
return 0;
}
上述代码,for
循环的初始化部分,条件控制部分,调整部分全部省略.
初始化和调整省略,这个循环什么也没有做.
条件控制省略,判断条件恒为真,循环可能跳不出去.
这段代码,在循环体内部也没有跳出循环的表达式,结果无限循环打印了hehe
//代码2
#include <stdio.h>
int main(void)
{
int i = 0;
int j = 0;
for (i = 0; i < 4; ++i)
{
for (j = 0; j < 4; ++j)
{
printf("hehe\n");
}
}
return 0;
}
这段代码,for
循环内嵌套了一个for
循环
i == 0
: j == 0 -> j == 1 -> j == 2 -> j == 3
i == 1
: j == 0 -> j == 1 -> j == 2 -> j == 3
i == 2
: j == 0 -> j == 1 -> j == 2 -> j == 3
i == 3
: j == 0 -> j == 1 -> j == 2 -> j == 3
随后i == 4
条件判断为假,跳出for
循环,共打印16次hehe
//代码3
#include <stdio.h>
int main(void)
{
int i = 0;
int j = 0;
for (; i < 4; ++i)
{
for (; j < 4; ++j)
{
printf("hehe\n");
}
}
return 0;
}
但如果将初始化部分省略,则会出现这个结果
i == 0
: j == 0 -> j == 1 -> j == 2 -> j == 3
i == 1
: j == 4
i == 2
: j == 4
i == 3
: j == 4
i == 0
时正常执行,当第二次外循环开始后,因为缺少了初始化部分,j == 4
并没有被更改,条件判断一直为假,内循环进不去,只打印了4次hehe
.
//代码4
#include <stdio.h>
int main(void)
{
int x, y;
for (x = 0, y = 0; x<2 && y<5; ++x, y++)
{
printf("hehe\n");
}
return 0;
}
可以使用多个变量来控制循环,三个部分放的是表达式,只要满足表达式的要求,都是可以被使用的.
上述代码打印了2次hehe
for
循环的初始化部分,条件控制部分,调整部分是可以省略的,但初学不建议,容易导致问题.
省略需要根据实际业务需求进行省略,一切代码都是为了实现需求的.
//代码5
#include <stdio.h>
int main(void)
{
int i = 0;
int j = 0;
for (i = 0, j = 0; j = 0; ++i, ++j)
{
++j;
}
return 0;
}
上述代码的for
循环体执行了0次,条件判断部分
j = 0恒为假,不进入
for`循环,循环体执行了0次.
3.3 do…while()循环
循环体至少执行1次
3.3.1 do语句的语法
do
循环语句;
while(表达式);
3.3.2 执行流程
3.3.3 do语句的特点
循环至少执行一次,使用的场景有限,所以不是经常使用.
使用do...while()
打印1-10
#include <stdio.h>
int main(void)
{
int i = 1;
do
{
printf("%d ", i);
++i;
} while (i <= 10);
return 0;
}
3.3.4 do while循环中的break和continue
#include <stdio.h>
int main(void)
{
int i = 1;
do
{
if(5 == i)
break;
printf("%d ", i);
++i;
} while (i <= 10);
return 0;
}
上述代码 打印出 1 2 3 4
#include <stdio.h>
int main(void)
{
int i = 1;
do
{
if(5 == i)
continue;
printf("%d ", i);
++i;
} while (i <= 10);
return 0;
}
上述代码 打印出 1 2 3 4 并且没有跳出循环
3.4 练习
3.4.1 计算n的阶乘
//不考虑溢出
#include <stdio.h>
int main(void)
{
int n = 0;
int ret = 1; //初识化结果变量
scanf("%d", &n); //输入n的值
while (n > 0) //循环计算
{
ret *= n;
--n;
}
printf("%d\n", ret); //打印
return 0;
}
3.4.2 计算1! + 2! + 3! +...+ 10!
第一种做法
#include <stdio.h>
int main(void)
{
int n = 10;
int ret = 1; //存储一项阶乘后的结果
int sum = 0; //存储总和
int i = 0;
int j = 0;
for (i = 1; i <= n; ++i)
{
ret = 1; //每进入一次内循环后需要初始化ret
for (j = 1; j <= i; ++j)
{
ret *= j; //内循环计算每项阶乘的结果
}
sum += ret; //将每一项相加
}
printf("%d\n", sum);
return 0;
}
得出结果4037913
,这一代码可以进行优化.
发现每一次都需要重新初始化ret
,并且重新计算对应项的阶乘,其实可以每次将计算的结果保存下来以供下一次使用,这样就少了一层循环,复杂度大大降低了.
改进后的代码:
#include <stdio.h>
int main(void)
{
int n = 10;
int ret = 1;
int sum = 0;
int i = 0;
for (i = 1; i <= n; ++i)
{
ret *= i; //ret每次只需乘对应项就能得到该数的阶乘值
sum += ret;
}
printf("%d\n", sum);
return 0;
}
3.4.3 在一个有序数组中查找具体的某个数字n
拿到题目第一反应是遍历数组查找得到对应索引
#include <stdio.h>
int main(void)
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; //定义有序数组
int key = 7; //待查找的值
int len = 0; //存放数组长度
int i = 0;
len = sizeof(arr) / sizeof(arr[0]); //得到数组长度
//遍历数组得到对应值的索引
for (i = 0; i < len; ++i)
{
if (arr[i] == key)
{
break;
}
}
//如果i == len,则表示没查找到
//如果i < len,则表示查找到了
if(i == len)
{
printf("没有该值\n");
}
else if (i < len)
{
printf("找到%d,在数组的索引为%d\n", key, i);
}
return 0;
}
最终结果得到了7
得索引6
这样确实可以得出结果,但如果数组的内容很大很大呢,不考虑内存的情况下,光是遍历数组就需要花费很多时间.
这里引入了一个查找有序数组的算法:二分查找
二分查找很符合我们的思维模式
如果猜一个范围为0-100的数,第一个猜的一般都是50,然后根据提示猜出的数是大是小再进行猜测25或者75,这样我们就能最多7次猜出这个数字了.
在这个题目里,一样可以运用二分查找思想来让我们相比遍历数组更快得到结果
- 首先我们需要知道数组的首位置
left
和末位值right
- 将
left
和right
相加除2得到mid
的值 - 接下来将循环
arr[mid]
与key
相比较.
若arr[mid] == key
,跳出循环,得到结果
若arr[mid] > key
,下一次查找范围为前半部分即left ~ mid-1
若arr[mid] < key
,下一次查找范围为后半部分即mid+1 ~ right
这是这个题目使用二分查找的思路
还有一个关键点:何时跳出循环
- 查找到值
- 没有范围查找了, 即
left > right
时
下面是实现代码:
#include <stdio.h>
int BinarySearch(int arr[], int size, int key);
int main(void)
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; //定义有序数组
int key = 7; //待查找的值
int size = sizeof(arr) / sizeof(arr[0]); //存放数组长度
int result = 0; //存放结果
result = BinarySearch(arr, size, key);
if (result == -1)
{
printf("未找到\n");
}
else
{
printf("找到了,索引为%d", result);
}
return 0;
}
/*
函数内容:对有序数组进行二分查找
输入参数:1.arr[] 有序数组名 2.size 数组的大小 3.key 待查找的值
输出参数:查找结果
返回值:若查到,返回该值索引;若没有,返回-1
*/
int BinarySearch(int arr[], int size, int key)
{
int left = 0; //查找范围最左的索引
int right = size - 1; //查找范围最右的索引
int mid = 0; //中间位置
while (left <= right)
{
mid = (left + right) / 2; //计算mid的值
if (arr[mid] == key)
{
return mid; //找到直接返回索引
}
else if (arr[mid] > key)
{
right = mid - 1; //比key大 right - 1
}
else if (arr[mid] < key)
{
left = mid + 1; //比key小 left + 1
}
}
return -1; //代码运行到这说明没有找到,返回-1
}
3.4.4 编写代码,演示多个字符从两端移动,向中间汇聚.
这道题用到了首尾指针向中间移动的思想
#include <stdio.h>
#include <string.h>
#include <windows.h>
int main(void)
{
char arr1[] = "###############";
char arr2[] = "Hello World!!!";
int left = 0;
int right = strlen(arr1) - 1;
while (left <= right)
{
arr1[left] = arr2[left];
arr1[right] = arr2[right];
printf("%s\n", arr1);
Sleep(1000); //单位是毫秒
system("cls"); //清理屏幕
++left;
--right;
}
return 0;
}
导入了两个新的库<string.h> 和 <windows.h>
使用strlen()
计算字符串的长度,使用sizeof
也可以,但因为字符串最后一位是'\0'
,得到的结果还需要再减一
使用Sleep()
进行休眠操作,使用system("cls")
进行清理屏幕操作
- 编写代码实现,模拟用户登陆情景,并且只能登陆三次.(只允许输入三次密码,如果密码正确则提示登陆成功,如果三次均输入错误,则退出程序)
#include <stdio.h>
#include <string.h>
int main(void)
{
//假定密码是123456
char password[20] = {0,}; //存放输入的密码
int i = 0;
int flag = 0; //密码正确为1, 三次均错误为0
for (i = 0; i < 3; ++i)
{
printf("请输入密码:");
scanf("%s", password);
if (strcmp(password, "123456") == 0)
{
flag = 1;
break;
}
else
{
printf("输入错误.\n");
}
}
if (flag == 1)
{
printf("登陆成功\n");
}
else
{
printf("三次输入失败,登陆失败.\n");
}
return 0;
}
上述代码导入了<string.h>
使用strcmp()
比较两个字符串内容是否相等:
- 相等返回0
- 第一个字符串大则返回1
- 第一个字符串小则返回-1
3.4.5 猜数字游戏
- 电脑会生成一个随机数
- 猜数字
- 猜大了,提醒猜大了,继续猜
- 猜小了,提醒猜小了,继续猜
- 猜中了,提醒猜中了,游戏结束
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void Menu();
void Game();
int main(void)
{
int choice = 0;
do
{
Menu();
printf("Please enter your choice>:");
scanf("%d", &choice);
srand((unsigned int)time(NULL)); //定义随机数起点,使用srand()和time()
switch (choice)
{
case 1:
Game();
break;
case 0:
printf("Exit game.\n");
break;
default:
printf("Your input is wrong, please re-enter your choice:\n");
break;
}
} while (choice != 0);
return 0;
}
void Menu()
{
//游戏开始菜单
//1.开始游戏 0.退出游戏
printf("##########################\n");
printf("####1.start 0.exit####\n");
printf("##########################\n");
}
void Game()
{
int random_num = rand() % 100 + 1; //随机一个1-100的数字
int guess = 0;
while (1)
{
printf("Please enter your guess.\n");
scanf("%d", &guess);
if (guess == random_num)
{
printf("You get it! Congraulations!\n");
break;
}
else if (guess < random_num)
{
printf("Your guess is small, guess again.\n");
}
else
{
printf("Your guess is big, guess again.\n");
}
}
}
上述代码有几个关键点:
- 先构造框架,然后再实现具体功能,边打代码边调试
rand()
可以返回一个伪随机数,不需要输入参数,一次运行内得到的数不一样,但每次运行得到的数字都是一样的.- 针对
rand()
的问题,可以使用srand()
来重新定义随机数起点,只要srand()
的参数在每次运行程序时不一样就可以了 - 时间戳很符合这个特性,时间戳是从美国时间1970年1月1日00:00时到现在经过的秒数,不考虑闰秒.时间是一直在变的.
- 通过观察文档发现:
srand()
接受的参数是unsigned int
类型,而time()
返回的是一个time_t
即long long int
的类型,需要经过强制转换,才能让参数被成功接收. - 在C语言获得随机数的操作如下:
#include <stdio.h> #include <stdlib.h> #include <time.h> int main() { srand((unsigned int)time(NULL)); //定义随机数起点 int random_num = rand(); //获得一个随机数 return 0; }
4. goto语句
C语言提供了可以随意滥用的goto
语句和标记跳转的符号.
从理论上goto
语句是没有必要的,实践中没有goto
语句也可以很容易地写出代码.
但是在需要跳出多层循环的场合下goto
还是用得着的.
多层循环中break
是达不到目的的,只能跳出本个循环,到上一个循环中.
goto
语句真正的适合场景如下
for(...)
for(...)
for(...)
{
if (disater)
goto error;
}
...
error:
if (disater)
//处理错误情况
下面是使用goto
语句的一个例子,然后使用循环的实现方式替换goto
语句`:
一个关机程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char input[10] = {0,};
system("shutdown -s -t 60");
again:
printf("电脑将在60s内关机,如果输入:我是猪,就取消关机!\n请输入:");
scanf("%s", input);
if (0 == strcmp(input, "我是猪"))
{
printf("好的我知道了,已经取消关机.\n");
system("shutdown -a");
}
else
{
goto again;
}
return 0;
}
用循环同样可以做
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char input[10] = {0,};
system("shutdown -s -t 60");
while(1)
{
printf("电脑将在60s内关机,如果输入:我是猪,就取消关机!\n请输入:");
scanf("%s", input);
if (0 == strcmp(input, "我是猪"))
{
printf("好的我知道了,已经取消关机.\n");
system("shutdown -a");
break;
}
}
return 0;
}
本章完.