前言
C语言是一种结构化的计算机语言,这里指的通常是顺序结构、选择结构、循环结构,掌握这三种结构之后我们就可以解决大多数问题。
分支结构可以使用if
、switch
来实现,而循环可以使用for
、while
、do while
来实现。
1. while循环
C语言中提供了三种循环语句,while
就是其中一种。
1.1 while 与 if 的对比
while的语法:
while(表达式)
语句;
具体我们可以通过与if语句对比一下来观察:
//代码1
int main()
{
if(1)
printf("hello\n");
return 0;
}
int main()
{
while(1)
printf("hello\n");
return 0;
}
通过运行我们可以发现,if
语句只能执行一次后面的打印语句,而while
循环可以一直打印。
1.2 while语句的执行流程
首先执行判断表达式,如果表达式值为0(为假),循环直接结束;表达式的值不为0(为真),则执行循环语句,语句执行后再继续进行判断。
1.3 while循环实践
比如:循环打印1~10的值
int main()
{
int i = 1;
while (i <= 10)
{
printf("%d ", i);
i++;
}
return 0;
}
2. for循环
通常for
循环是循环中使用最多的,语法如下:
2.1 语法形式
for(表达式1; 表达式2; 表达式3)
语句;
在这里表达式1用于初始化循环变量,表达式2用于循环结束条件的判断,表达式3用于循环变量的调整。
2.2 执行流程
进入循环首先执行表达式1初始化循环变量,然后执行表达式2进行判断,如果表达式2的结果为0,则 循环结束;表达式2不为0则执行循环语句,执行完成后,再执行表达式3调整循环变量,然后再进行表达式2判断。
整个循环中,表达式1的初始化部分只执行1次,接下来就是表达式2、循环语句、表达式3在循环。
2.3 for循环实践
还是以打印1~10的值为例:
int main()
{
int i = 1;
for (i = 1; i <= 10; i++)
{
printf("%d ", i);
}
return 0;
}
3. do-while循环
3.1语法形式
一般do while
循环使用的语句比较少,它的语法如下:
do
语句;
while(表达式);
while
循环for
循环都是先判断再进入循环,而do while
循环是先进入循环体执行循环语句,再执行while
后的判断表达式,表达式为真就进行下一次循环,为假则跳出不再循环。
3.2 执行流程
3.3 do while 循环的实践
这里我们还是以打印1~10的值为例:
int main()
{
int i = 1;
do
{
printf("%d ", i);
i++;
} while (i <= 10);
return 0;
}
4. break和continue语句
在执行循环的时候,我们经常会遇到某些情况需要提前终止循环,而在C语言中提供了break
和continue
两个关键字:
break
的作用是永久终止循环,只要break
执行,那么就会直接跳出循环,执行当前循环外的语句。continue
的作用是跳过本次循环continue
后边的代码,进行下一轮循环。
4.1 while循环中的break和continue语句
4.1.1 break举例
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 8)
break;
printf("%d ", i);
i++;
}
return 0;
}
这时我们再来看看结果:
这里我们可以看到,只打印到了7就停止了,这是因为i在等于8的时候就执行了break语句,直接跳出了整个循环,所以只打印到了7就停止。
4.1.2 continue举例
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 8)
continue;
printf("%d ", i);
i++;
}
return 0;
}
在这段代码中的结果是会造成死循环,因为continue的特点是跳过当次循环后的代码,所以当 i 循环一直到值为 8 的时候,就会跳过后面的 printf 和 i++ 语句,导致 i 的值一直为 8 ,造成程序死循环,所以要避免将 continue 放在调整语句之前。
4.2 for循环中的break和continue
4.2.1 break举例
和 while 循环一样, for 循环中的 break 也是用于终止循环,只要执行到了break循环就彻底终止:
int main()
{
int i = 0;
for (int i = 1; i <= 10; i++)
{
if (i == 8)
break;
printf("%d ", i);
}
return 0;
}
所以当 i 等于 8 的时候,break执行,跳出循环,结果打印1~7。
4.2.2 continue举例
如果把上面的代码中的break换成continue会什么结果:
int main()
{
int i = 0;
for (int i = 1; i <= 10; i++)
{
if (i == 8)
continue;
printf("%d ", i);
}
return 0;
}
这里打印了1~10,但是没有打印8,这是因为当 i == 8 的时候, continue执行跳过了打印的语句,但是调整语句 i++ 在continue之前,所以 i 继续自增,变成 9, 不满足 if 语句,跳过continue,继续执行printf语句,所以结果没有打印 8。
4.3 do while循环中的break和continue语句
do while 语句中的break和continue作用与 while 循环中几乎一样,这里不再叙述。
5. goto语句
C语言中还提供了一种方法,就是goto
语句和跳转标号,它可以实现在同一个函数内跳转到设置好的标号处。
比如:
int main()
{
printf("hello\n");
goto next;
printf("world\n");
next:
printf("跳过了world的打印\n");
return 0;
}
goto
语句如果使用不好就会导致在函数内乱跳转;但也并非全是缺点,如果在多层循环代码中想要快速跳出,那么使用goto
就会很方便:
for(...)
{
for(...)
{
for(...)
{
if(表达式)
goto next;
}
}
}
next:
如果我们使用break的话,一次只能跳出一层循环,想全部跳出需要3个break,但使用goto的话,满足条件直接跳出所有循环,就会更加快捷。
6. 猜数字游戏
当我们了解了分支与循环的结构之后,就可以尝试着写一个猜数字的小游戏,在控制台展示出来:
不过,在写之前我们还要先了解几个函数,因为在游戏里我们会用到它们:
6.1 rand、srand、time函数与随机数
6.1.1 rand函数
在写程序的时候,有很多时候需要用到随机数,于是我们就可以使用rand
函数。如下所示:
int rand(void);
注:在使用rand
函数时需要包含头文件
#include <stdlib.h>
但通过程序多试几次发现,rand
函数实际上生成的是一个伪随机数,每次生成的数字都是一样的:
第一次:
第二次:
伪随机数并不是真的随机数,而rand
函数生成的是基于一个叫种子的基准值进行运算从而生成的随机数。
之所以每次生成的随机数都是一样的,是因为种子的默认值为“1”。
如果想生成真正的随机数,那么就需要种子是一直变化的。
6.1.2 srand函数
C语言中又提供了一个函数叫srand
,是用来初始化随机数生成器的。
void srand(unsigned int seed);
在调用rand
函数前先调用srand
函数,用过srand
的参数设置rand
函数的种子,这样每次生成的随机数就会变化。
6.1.3 time函数
而一般在写程序的时候,大多数时候都会使用时间做为种子,因为时间是一直在变化的。
在C语言中有一个函数叫time
,可以返回当前的时间:
time_t time (time_t* timer);
使用time
函数需要包含头文件:
#include <time.h>
如果只用time
函数返回时间戳,那就可以写成:
time(NULL);
6.1.4 生成随机数
了解了这些这时就可以把代码改下:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main()
{
srand((unsigned int)time(NULL));
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
return 0;
}
这时再看得到的结果:
第一次:
第二次:
这时得到的就是真正的随机数。
6.2 代码实现
游戏要求:
- 自动生成1~100的随机数
- 根据玩家猜的数字电脑给出大了或者小了的反馈,直到正确。
//打印开始界面
void menu()
{
printf("************************\n");
printf("*******猜数字游戏********\n");
printf("*********1.开始*********\n");
printf("*********0.退出*********\n");
printf("************************\n");
}
//游戏主体
void game()
{
//生成随机数,设定范围1~100以内
int r = rand() % 100 + 1;
//玩家要猜的数字
int num = 0;
while (1)
{
printf("请猜数字:");
scanf("%d", &num);
if (num > r)
{
printf("猜大了\n");
}
else if (num < r)
{
printf("猜小了\n");
}
else
{
printf("恭喜你,猜对了!\n");
break;
}
}
}
int main()
{
//用于选择开始游戏、退出游戏
int input = 0;
//设置种子,为了后面调用rand函数
srand((unsigned int)time(NULL));
do
{
//打印界面(封装为menu函数)
menu();
printf("请选择:");
scanf("%d", &input);
//根据玩家的输入来选择分支
switch(input)
{
case 1:
//游戏主体(封装为game函数)
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
//对于输入0和1之外的处理
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
6.3 逻辑分析
6.3.1 main()函数
- 首先进入
main
函数,因为游戏一开始就要打印一个菜单,所以我们使用do while
循环,do while
的特点就是第一次直接进入循环语句。 - 先打印菜单,然后使用
scnaf
让玩家输入,根据玩家输入的值选择switch
的分支语句,如果输入 1 就进入case1
语句,开始游戏;选择 0 那么就提醒玩家退出游戏,接着break
跳出,如果输入非 0 和 1 的数字就走default语句提示重新选择。 - 使用
input
做为循环条件是因为,如果玩家输入 1 进入游戏之后,无论输赢导致游戏结束,都会再让玩家选择一次,也就是再打印一次菜单,再scanf
输入选择,避免了游戏结束直接退出程序。而玩家输入0的话,整个循环也就随着停止,及退出游戏,如果输入其他的,只要是大于0就会提示重新选择,然后再次循环。
6.3.2 game()函数
- 如果玩家选择了1进入游戏主体,首先生成一个1~100的随机数并赋值给
r
- 创建一个
num
变量用于玩家输入,并且因为猜数字很难一次猜对,所以输入的动作我们也放在循环里。 while
循环让他一直循环,内部就是一个比较的过程,根据玩家输入的数字走不通的分支并进行提示,直到猜对之后break
跳出循环。