目录
if...else语句
编辑
易犯错误
打印100以内的奇数
switch...case语句
输出星期
循环语句
对比判断
1.break终止循环
2.continue
读取字符
缓冲区读取
只输出数字字符
for循环
do...while循环
n的阶乘求和
循环实现动态打印
猜数字游戏【总结】
goto
编辑 关机程序
goto
while循环
if...else语句
我们先引入一个重要的概念:0为真,非0为假。
分支判断语句if...else,默认情况下都只控制一条语句,如果我们想执行多条语句可以添加大括号。{}内表示代码段。
if语句默认与最近的else相匹配。
那我们如何按照自己意愿决定if...else的匹配关系呢?答案是加上大括号:
//形式1
if (condition)
{
return x;
}
return y;
//形式2
if (condition)
{
return x;
}
else
return y;
一般推荐第二种形式代替第一种,以提高可读性。
易犯错误
int num = 1;
if (num = 5)
{
printf("hehe\n");
}
这段代码会陷入死循环,注意区分赋值和等于
//正确
if (num == 5)
//容易检查错误
if(5 == num)
打印100以内的奇数
我们可以使用判断语句来输出100以内的所有奇数
int i = 1;
while (i <= 100)
{
if(i%2 == 1)
printf("%d\n", i);
i++;
}
但我们可以凭借尝试不用判断直接利用循环语句跳过2个数也能实现这个功能:
while (i <= 100)
{
printf("%d\n", i);
i+=2;
}
switch...case语句
switch...case语句作为分支语句,意为开关。有的时候它比if...else语句更方便,可读性更高。
输出星期
正常模式:
int day = 0;
scanf("%d", &day);
if (1 == day)
printf("星期1\n");
else if (2 == day)
printf("星期2\n");
else if (3 == day)
printf("星期3\n");
else if (4 == day)
printf("星期4\n");
else if (5 == day)
printf("星期5\n");
else if (6 == day)
printf("星期6\n");
else if (7 == day)
printf("星期天\n");
switch改写:
当我们输入4的时候程序进入了第4个语句,成功输出了星期4但是输出了后面的分支, 你可以把它想象成电流水流,需要一个闸门控制关闭——break意为中断,类似与闸门的关闭键,遇到它就会停止。
int day = 0;
scanf("%d", &day);
int n = 1;
switch (day)//整型表达式
{
case 1: //case 后必须是整型常量表达式
printf("星期1\n");
break;
case 2:
printf("星期2\n");
break;
case 3:
printf("星期3\n");
break;
case 4:
printf("星期4\n");
break;
case 5:
printf("星期5\n");
break;
case 6:
printf("星期6\n");
break;
case 7:
printf("星期天\n");
break;
}
现在我们打印休息日和工作日,可以这样修改代码:
switch (day)//整型表达式
{
case 1: //case 后必须是整型常量表达式
case 2:
case 3:
case 4:
case 5:
printf("工作日\n");
break;
case 6:
case 7:
printf("休息日\n");
break;
default:
printf("输入错误\n");
break;
}
这里就体现了switch语句的自由性,当我们输出1-7以外的数字时,我们可以使用default关键字(默认)来处理。default不一定要写在语句最后,可以为任意位置,所以我们最好在后面加上break。
循环语句
顾名思义,循环就是满足判断条件后就会继续重复执行的操作。
对比判断
当满足条件的时候他就会一直循环,我们输入一个横真条件就会进入死循环,为了灵活的控制循环,我们还添加了break和continue对循环进行控制。
1.break终止循环
遇到break循环跳出当前循环
2.continue
遇到continue忽略循环体内后面的内容,重新开始循环(跳过本次循环)
该循环到5的时候程序会进入死循环,正确做法是将i++放到循环第一句中使其不打印5。
读取字符
如果我们想从键盘中读取多个字符的话该怎么操作呢?
读取成功时返回它的整型值(对应ascii码值),这是为了适应当它读取失败时返回EOF(-1),我们也可以手动结束读取——键盘输入ctrl+z
putchar是输出字符, 成功将返回字符并输出在屏幕上,失败返回EOF。
ch通过接收getchar的返回值,对每个字符进行判断。当我们键入回车时,getchar也会读取并判断,然后通过屏幕打印出来,所以会出现单个字符占一行的效果。
缓冲区读取
我们实现一个简单的密码确认程序来验证一下缓存区是否存在。
当我们输入密码后敲出的回车直接被ch读取,导致直接打印确认失败,这是因为scanf在遇到\n或空格后会停止输入,剩下的内容被留在了缓冲区。为了避免这种情况,我们可以用getchar将空格给读走。
添加getchar后我们的代码能成功运行
还有一种情况需要考虑
为什么会发生这样的事呢?
换句话说还是没有处理干净,这时候我们利用循环来清除缓冲区的内容
只输出数字字符
int ch = 0;
while ((ch = getchar()) != EOF)//多组输入,注意优先级加括号
{
if (ch < '0' || ch > '9')
continue;
/*if(ch <= '9' && ch >= '0')*/
putchar(ch);
}
需要注意的是,虽然用char类型也能接收getchar的返回值,但最好还是用int(可能截断)
for循环
for循环是对while循环的一个整合,使得我们能精确地调整循环。
for(代码1;代码2;代码3)
分别代表初始条件,判断和更新
这段代码打印了除5之外的1到10的所有数字,与while循环不同的是,当更新条件放在continue后将不会执行,而for循环中使用continue能继续执行更新条件。
for的初始化,判断,调整三个部分可以省略, 但是省略掉判断部分,就意味着判断恒为真
如果我们省略初始部分,可能会出现这样的结果:
不省略前打印100次,省略后由于打印10次后j的值没有被重新初始化,导致它仍然为10。
所以最好不要随便省略判断条件。
do...while循环
它的特点是:至少执行一次,一般不常用。
下面代码的结果是?
int i = 1;
do
{
if (i == 5)
continue;
printf("%d ", i);
i++;
}
while (i <= 10);
答案是输出1 2 3 4,同样地,由于更新条件放在continue后,执行continue后进入while循环(死循环)。
n的阶乘求和
具体思路是从1到n依次求阶乘,并依次求和。
int i = 1;
int sum = 0;
int ret = 1;
int n = 0;
for (n = 1; n <= 3; n++)
{
ret = 1;
for (i = 1; i <= n; i++)
{
ret = i * ret;
}
sum = sum + ret;
}
printf("%d", sum);
注意每次循环后需要将ret变为1
第二种方法(消耗低)
n!= (n-1)! * n
int i = 1;
int sum = 0;
int ret = 1;
int n = 0;
for (n = 1; n <= 3; n++)
{
ret = n * ret;
sum = sum + ret;
}
printf("%d", sum);
循环实现动态打印
给定一段字符串和同等长度的#号,使其每循环一次,左右两边进行覆盖直到#被覆盖成字符串。
#include<stdio.h>
#include<windows.h>
#include<string.h>
int main(){
char arr1[] = "welcome to here!!!!";
char arr2[] = "###################";
int left = 0;
int right = strlen(arr1)-1;
while (left <= right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
Sleep(100);//休眠命令
system("cls");//清空屏幕命令
left++;
right--;
}
printf("%s\n", arr2);
}
大家可以复制这段代码到编译器中运行,可以观察到一个简单的动态效果。
猜数字游戏【总结】
我们结合本篇学的知识,用猜数字游戏做一个复习。
编写一个建议菜单:
void menu()
{
printf("*********************************\n");
printf("********** 1. play ************\n");
printf("********** 0. exit ************\n");
printf("*********************************\n");
}
int main()
{
int n = 0;
do
{
menu();
scanf("%d", &n);
switch (n)
{
case 1:
//game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,重新选择!\n");
break;
}
}
while (n);
return 0;
}
接下来我们完善game函数
要想实现猜数字这个功能,我们得需要电脑生成随机数,而rand是专门用来生成随机数的函数。
但rand生成的数字是伪随机,第二次运行程序的数字和第一次一模一样!
所以我们用srand(随机数初始化设置器)来让随机数变成真随机。
一直在变的是时间,所以用时间函数来设置初始化。它的返回值是一个时间戳(整形)我们这里是产生随机值,所以可以传NULL来产生随机值。
注意srand只能设置一次,所以不参与循环,我们可以把它添加到do...while循环里
srand((unsigned int)time(NULL));
由于time函数返回类型是time_t,而srand的参数是无符号整形,所以我们得强制转换。
void game()
{
int num = rand()%100+1;//1-100之间
int guess = 0;
while (1)
{
printf("请猜数字:>");
scanf("%d", &guess);
if (guess < num)
printf("猜小了\n");
else if (guess > num)
printf("猜大了\n");
else
{
printf("猜对\n");
break;
}
}
}
把上面的代码整合一下,我们的猜数字游戏就可以运行起来了,赶快去体验一下自己的第一个c语言小游戏吧!
goto
作为一个跳出一层或多层循环的函数,goto语句能实现的功能都能被其他语句实现,而且它的使用可能会导致程序出现一些问题(例如跳过某些程序可能导致程序出现不可调试的bug等)。它的出场率并不高,一般出现在需要一次性跳出多个循环的场景。(break只能跳出一层循环)
关机程序
顾名思义,就是能让电脑在特定时间关机的程序。我会用两种方式来写这个程序
goto
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
system("shutdown -s -t 60");//60秒内关机
again:
printf("请注意,你的电脑在1分钟内关机,如果输入:我是猪,就取消关机\n");
char input[20] = { 0 };
scanf("%s", input);
if (strcmp(input, "我是猪") == 0)
{
system("shutdown -a");
printf("关机取消\n");
}
else
goto again;
return 0;
}
运行结果:
while循环
int main()
{
char input[20] = { 0 };
system("shutdown -s -t 60");
while (1)
{
printf("请注意,你的电脑在1分钟内关机,如果输入:我是猪,就取消关机\n");
scanf("%s", input);
if (strcmp(input, "我是猪") == 0)
{
system("shutdown -a");
printf("关机取消\n");
break;
}
}
return 0;
}