目录
我们在这补充两点知识:EOF和getchar()(很重要!缓冲区问题)、putchar()
前言:c语言是一门结构化的程序设计语言
1.顺序结构、2.选择结构、3.循环结构
我们生活中所有的情况也就这三种
二、分值语句和循环语句
本章我们重点学习分值语句和循环语句
1.什么是语句
c语言中由一个分号,隔开的就是一条语句。比如:
printf("hello");
1 + 2;
2.分支语句(选择结构)
2.1 if
语法结构:
if(表达式)
语句;
---------------------------------------------------------------------------------------------------------------------------------
if(表达式)
语句1;
else //默认if中的表达式的补集
语句2;
---------------------------------------------------------------------------------------------------------------------------------
// 多分支
if(表达式1)
语句1;
else if((表达式2)
语句2;
...
else //默认表达式1 U 表达式2 U 表达式3 U ...的补集
语句n;
解释一下,如果表达式的结果为真,则语句执行。
在c语言中如何表示真假?
0表示假,非0表示真。
如果条件成立,要执行多条语句,应该使用代码块。
#include<stdio.h>
int main()
{
if(表达式)
{
//语句列表1;
}
else
{
//语句列表2;
}
return 0;
}
这里的一对{}就是一个代码块。
如果不加{},则if只能跟后面第一个分号之前的语句保持关联.
如果没有代码块,else只能匹配离自己最近的未匹配的if
注意:if条件判断相等时,注意是用==而不是=;
if练习
输出1-100之间的所有奇数。
#include<stdio.h>
int main()
{
int i = 0;
while (i <= 100)
{
if (i % 2 == 1)
printf("%d ", i);
i++;
}
return 0;
}
2.2 switch
switch语句也是一种分值语句。常常用于多分支的情况。
比如:
输入1,输出星期一
输入2,输出星期二
输入3,输出星期三
输入4,输出星期四
输入5,输出星期五
输入6,输出星期六
输入7,输出星期七
如果我们写成if...else的形式程序太冗杂了,我们就需要简单的语法,switch语句
switch(整形表达式)
{
语句项;
}
而语句项是什么?
是一些case语句:
如下:
case 整型常量表达式:
语句;
我们用代码来表示一下:
#include<stdio.h>
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;
default:
printf("输入错误\n");
break;
}
return 0;
}
我们day输出几,就会从case几进入,大家可以想想如果没有break会输出什么?
没有break的话,从case进入后,会从case几后的语句进行顺序输出
如:我们一周只区分工作日和休息日
#include<stdio.h>
int main()
{
int day = 0;
scanf("%d", &day);
switch (day)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("工作日\n");
break;
case 6:
case 7:
printf("休息日\n");
break;
default:
printf("输入错误\n");
break;
}
return 0;
}
default 子句(default 相当于if语句中的最后的else。)
如果表达的值为所有的case标签的值都不匹配怎么办?
其实没事,结果就是所有的语句都被跳过。
程序并不会终止,也不会报错,因为这种情况在c中并不认为适合错误。
但是,如果你并不想忽略不匹配所有标签的表达式的值时,
你可以在语句列表中加一条default子句,把下面的标签
default:
写在任何一个case标签可以出现的位置,当switch表达式的值不匹配所有case标签的值时,这个default子句后面的语句就会执行
编程好习惯
每一个switch语句都放一条default子句是好习惯。
switch练习
#include<stdio.h>
int main()
{
int n = 1;
int m = 2;
switch (n)
{
case 1:
m++;
case 2:
n++;
case 3:
switch (n)
{
//switch允许嵌套shiy
case 1:
n++;
case 2:
m++;
n++;
break;
default:
break;
}
case 4:
m++;
break;
default:
break;
}
printf("m = %d, n = %d\n", m, n);
return 0;
}
思考一下m和n都是几??
3.循环语句
3.1 while
我们已经掌握了if语句
if(条件)
语句;
当条件妈祖的情况下,if语句后的语句执行,否则不执行,但是这个语句只能执行一次。
但是,我们生活中很多例子是:一件事需要做很多次。
c语言给我们引入了循环语句,其中while语句,可以实现循环。
while语法结构
while(表达式)
循环语句;
比如我们实现:
在屏幕实现打印1~10的数字
#include<stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
printf("%d ", i);
i++;
}
return 0;
}
这个代码已经帮我们了解了while语句的基本语法,下面我们了解一下
while语句中的break和continue
3.1.1break介绍
#include<stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
break;
printf("%d ", i);
i++;
}
return 0;
}
这里代码输出1 2 3 4
总结:break在while循环中的作用
其实在循环中子要遇到break,就停止后面的所有操作,之间跳出循环,所有break是用于终止循环的。
3.1.2 continue介绍
#include<stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
continue;
printf("%d ", i);
i++;
}
return 0;
}
这里代码输出结果是什么?
输出 1 2 3 4 后,变成死循环
那我们改变一下,我们把while循环写成这样
#include<stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
i++;
if (i == 5)
continue;
printf("%d ", i);
}
return 0;
}
我们的输出结果为:1 2 3 4 6 7 8 9 10
我们跳过了输出5的情况
总结:continue在while循环中的作用就是:
continue适用于终止本次循环的,也就是本次循环中continue后边的代码不会再执行,而是直接跳转到while语句的判断部分,进行下一次循环的入口判断。
我们在这补充两点知识:EOF和getchar()(很重要!缓冲区问题)、putchar()
getchar()是stdio.h中的库函数,它的作用是从stdin流中读入一个字符,也就是说,如果stdin有数据的话不用输入它就可以直接读取了,第一次调用getchar()时,确实需要人工的输入,但是如果你输了多个字符,以后的getchar()再执行时就会直接从缓冲区中读取了。返回值是char强制转换为int的形式返回读取的字符。
putchar()是输出字符
EOF-end of file值为-1,怎么打出来EOF呢,我们摁住CTRL+z就行了
大家可以拿这个代码测试一下EOF
#include<stdio.h>
int main()
{
int ch = 0;
while ((ch = getchar()) != EOF)
{
putchar(ch);
}
return 0;
}
我们主要讲的是getchar()
getchar有一个int型的返回值。当程序调用getchar时.程序就等着用户按键。用户输入的字符被存放在键盘缓冲区中。直到用户按回车为止(回车字符也放在缓冲区中)。什么意思呢,我们举个例子
#include<stdio.h>
int main()
{
int ret = 0;
char password[20] = { 0 };
printf("请输入密码:");
scanf("%s", password);
printf("请确认(Y/N)");
ret = getchar();
if (ret == 'Y')
printf("确认成功\n");
else
printf("放弃确认\n");
return 0;
}
这里的输出结果就出现了问题
当我们输完密码后,我们还没有输出字符就直接放弃确认了。 为什么会这样呢?
那这个'\n'是哪里来的,其实是我们输入密码时的回车进了缓冲区,在我们ret接受getchar()数据时'\n'直接从缓冲区给了getchar(),导致直接输出放弃确认。
那我们应该怎么解决呢?
如果我们在使用getchar()的时候让缓冲区为空getchar()是不是就可以等待我们输入了。
我们从前面的例子找到灵感,我们在给ret赋值之前,先一步使用getchar()清空缓冲区的数据不就直接解决了吗。代码如下:
#include<stdio.h>
int main()
{
int ret = 0;
char password[20] = { 0 };
printf("请输入密码:");
scanf("%s", password);
//缓冲区还有给'\n';
getchar();
printf("请确认(Y/N)");
ret = getchar();
if (ret == 'Y')
printf("确认成功\n");
else
printf("放弃确认\n");
return 0;
}
这时我们输入完密码后,就可以正常输入了。
还有一点是scanf中要输入%s的话,空格和回车都会导致输入结束
如果我们用上个例子,我们输入的密码是123456 ABAA,这时,scanf中的%s只能接受到空格前面的123456,而后面的空格和ABCD则进入了缓冲区,而后面的getchar()这个缓冲区清理只读了一个空格也就结束了,所以最后我们给ret赋值时,赋值了一个A,所以我们再一次放弃确认了。
那怎么解决呢,我们可以用一个循环,把前面的缓存区不管是什么全都清空
代码如下:
#include<stdio.h>
int main()
{
int ch;
int ret = 0;
char password[20] = { 0 };
printf("请输入密码:");
scanf("%s", password);
//缓冲区还有' ABCD\n';
while ((ch = getchar()) != '\n')//只要ch不是\n我们就一直循环
{
;
}
printf("请确认(Y/N)");
ret = getchar();
if (ret == 'Y')
printf("确认成功\n");
else
printf("放弃确认\n");
return 0;
}
这样,我们就可以完美解决getchar的缓冲区问题了,这个很重要!!!
3.2 for
我们已经知道了while循环,但是我们为什么还要一个for循环呢?首先来看看for循环的语法
语法
for(表达式1;表达式2;表达式3)
循环语句;
表达式1为初始化部分,用于初始化循环变量的。表达式2为条件判断部分,用于判断循环什么时候终止。表达式3为调整部分,用于循环条件的调整。
实际的问题:
使用for循环在屏幕上打印1 ~ 10的数字
#include<stdio.h>
int main()
{
//初始化 //判断 //调整
for (int i = 1; i <= 10;i++)
{
printf("%d ", i);
}
return 0;
}
for循环执行流程
我们比较while和for两个语句可以发现在while循环中依然存在循环的三个必要条件,但是由于风格的问题使得三个部分很可能偏离较远,这样查找修改就不够集中和方便。所以,for循环的风格更胜一筹。for循环使用的频率也最高
break和centinue在for循环中
我们发现在for循环中也可以出现break和continue,他们的意义和在while循环中是一样的,但是还是有些差异。
#include<stdio.h>
int main()
{
//while中的continue
int i = 1;
while (i <= 10)
{
if (i == 5)
continue;
printf("%d ", i);
i++;
}
return 0;
}
#include<stdio.h>
int main()
{
int i;
for (i = 1;i <= 10; i++)
{
if (i == 5)
continue;
printf("%d ", i);
}
return 0;
}
while会死循环,for不会。
for语句的循环控制变量
一些建议:
1.不可再for循环体内修改循环变量,防止for循环失去控制。
2.建议for语句的循环控制变量的取值采用铅笔后开区间写法。
for循环的变种(1)
#include<stdio.h>
int main()
{
//初始化 //判断 //调整
for (;;)
{
printf("hehe\n");
}
return 0;
}
1.for循环的初始化、调整、判断都可以省略
但是,for循环的判断部分如果被省略,判断条件就是:恒为正。
2.如果不是非常熟练,建议大家不要随便省略。
for循环的变种(2)
#include<stdio.h>
int main()
{
int x, y;
for (x = 0,y = 0;x < 2 && y < 5;x++,y++)
{
printf("hehe\n");
}
return 0;
}
for循环可以有两个变量。
3.3 do while
do...while语句的语法
do
循环语句;
while(表达式);
举个例子:打印1~10
#include<stdio.h>
int main()
{
int i = 1;
do
{
printf("%d ", i);
i++;
} while (i <= 10);
return 0;
}
do...while在break和continue的运用上和while一样。
do...while语句的特点
循环至少执行一次,使用的场景有限,所以不是经常使用。
#include<stdio.h>
int main()
{
int i = 10;
do
{
printf("%d ", i);
i++;
} while (i <= 10);
return 0;
}
这个循环是可以进的,但如果是while和for初始化i = 10的时候是无法进入循环的。
4.随机数怎么做
要想做猜数游戏,首先要会做随机数,这里stdlib.h头文件中给了rand的随机数函数,但这个函数,有些问题,就是每一次编译器执行这个随机数都会重复。
所以我们需要用srand()设置rand函数的随机起点。那怎么设置呢?
srand(整形),但我们如果括号里填的是固定的整数时,srand给rand函数定义的随机数是固定的,所以我们需要时间戳。
时间戳是什么?
当前计算机的时间-计算机的起始时间(1970.1.1.0:0:0) = (xxxx)秒。
时间戳是个随时改变的数,所以我们可以用它来做srand中的整数。
所以我们需要time.h头文件中的time变量(长整型),所以我们就可以用srand给rand定义随机数了
srand((unsigned int) time(NULL)),这时候的rand就可以每次得出的随机数都不一样了。
5.goto语句
c语言中提供了可以随意滥用的goto语句和标记跳转的符号。
从理论上goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码
但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程,例如一次性跳出两层或多层循环。
这种清空使用break是达不到目的的。他只能从最内层循环退出到上一层循环。
但goto会影响代码的稳定性,除非必要,建议不要使用
goto语句的例子:
#include<stdio.h>
int main()
{
printf("hello\n");
goto again;
printf("你好\n");
again:
printf("hehe\n");
return 0;
}
这里因为goto跳转到again了,所以你好是不会被打印出来的
下期我们5.学习函数,持续更新,喜欢记得关注。