C语言入门(5/100)
通过Day 4对于 if
语句、switch
语句等分支结构(选择结构)的学习,初次接触到了C语言的语句与结构,对于如何将实际问题转变为C程序,在脑海中形成了简单的概念
今天,Day 5 的学习中,我们将尝试接触相较于分支结构
更加复杂一些的循环结构
:
- 补充 Day 4:
scanf
函数 - 循环结构 :
while
循环getchar
函数、putchar
函数do while
循环for
循环
一、补充 Day 4: scanf
函数
在 Day 4 最后的1.4.5 实际操作环节给出的代码中,我们提到了scanf
函数
1.1 代码示例:
#include <stdio.h>
int main()
{
//定义一个grade变量用来存放成绩
int grade;
printf("请输入您毕业设计的成绩:");
scanf("%d",&grade);
//判断输入的成绩是否超过100
if(grade<=100){
//如果没有超过一百,据题意那就保留十位数部分去掉个位数部分
grade=grade/10;
switch(grade)
{
/* 因为不管是100还是90以上都是:优秀。所以根据switch case 语句的语法
如果没有遇到 break 那就接着执行下面的语句 */
case 10:
case 9:
printf("恭喜您!您的成绩为:优秀");
break;
case 8:
printf("您的成绩为:良好");
break;
case 7:
printf("您的成绩为:中等");
break;
case 6:
printf("您的成绩为:及格");
break;
default :
printf("很遗憾您的成绩为:不及格\n要加油啊!不要挂科。");
}
}else //如果输入的数超过100,则输出:输入错误
{
printf("输入错误!");
}
return 0;
}
1.2 scanf
函数详解
scanf
函数:- 用于接收键盘输入的内容, 是一个阻塞式函数;
- 程序会停在
scanf
函数出现的地方, 直到接收到数据才会执行后面的代码
scanf
函数的调用格式为:
scanf("格式控制字符串", 地址列表);
scanf("%d", &num)
- 基本用法:
#include <stdio.h>
int main()
{
int number;
scanf("%d", &number); // 接收一个整数
printf("number = %d\n", number);
}
- 接收多条数据:
#include <stdio.h>
int main()
{
int number;
int value;
// 可以输入 数字 空格 数字, 或者 数字 回车 数字
scanf("%d%d", &number, &value);
printf("number = %d\n", number);
printf("value = %d\n", value);
}
或者
#include <stdio.h>
int main()
{
int number;
int value;
// 输入 数字,数字 即可
scanf("%d,%d", &number, &value);
printf("number = %d\n", number);
printf("value = %d\n", value);
}
二、循环结构
循环结构
是程序中一种很重要的结构。
- 其特点是,
- 在给定条件成立时,反复执行某程序段,直到条件不成立为止;
- 给定的条件称为
循环条件
,反复执行的程序段称为循环体
;
2.1 while
循环
2.1.1 while
语法结构:
while(循环条件)
{
循环体;
}
while
语句的语义是:
计算表达式的值,当值为
真(非0)
时, 执行循环体代码块。
因此,while
循环的执行流程就是,
- 首先,判定"循环条件"是否为真,
- 如果为假,直接跳到循环语句后面。
- 如果"循环条件"为
真
,执行一次循环体; - 再次判断"循环控制条件"是否为真;
- 为
真
继续执行循环体; - 为假跳出循环。
- 为
- 重复以上操作, 直到"循环条件"为假为止。
示例,在屏幕上打印1~100的数字:
#include<stdio.h>
int main()
{
int i = 1;
while (i < 101)
{
printf("%d ", i);
i ++ ;
}
return 0;
}
while练习:
- 计算1 + 2 + 3 + …n的和
- 获取1~100之间 7的倍数的个数
2.1.2 while 语句中的break
和 continue
break
作用,示例:
在循环中只要遇到
break
,就停止后期的所有的循环,直接终止循环。
continue
作用,示例:
continue
是用于终止本次循环的。
也就是本次循环中,continue
后边的代码不会再执行, 而是直接跳转到while
语句的判断部分(进行下一次循环的入口判断)。
在这个程序中,当i=5
时进行判断5 == i
后,就执行continue
语句,结束本次循环,重新进入到判定部分,即while(i<11)
,然后又重复的进行判断if(5 == i)
,再接着重复上面的的流程,所以进入了死循环。
注
:
while
语句中的表达式一般是关系表达或逻辑表达式- 当表达式的值为
假
时不执行循环体,反之则循环体一直执行。
- 当表达式的值为
- 一定要记着在循环体中改变循环变量的值,否则会出现死循环(无休止的执行)。
2.1.3 getchar()
函数
首先,我们来看一段while()
循环的代码
//代码什么意思?
//代码1
#include <stdio.h>
int main()
{
int ch = 0;
while ((ch = getchar()) != EOF)
putchar(ch);
return 0;
}
//这里的代码适当的修改是可以用来清理缓冲区的.
//代码2
#include <stdio.h>
int main()
{
char ch = '\0';
while ((ch = getchar()) != EOF)
{
if (ch < ‘0’ || ch > ‘9’)
continue;
putchar(ch);
}
return 0;
}
//这个代码的作用是:只打印数字字符,跳过其他字符的、
getchar
的作用:
- 从一个流里读取一个字符,或者从标准输入(键盘)里面获取一个字符。
getchar
的返回类型:int
,返回的值就是我们从流或者键盘获取的那个字符
那为什么我们用
int
来接收getchar
返回的值呢?
- 当一个字符用
getchar
输入的时候,我们就要将其存储到相应的变量当中(当然,不存储也是完全没有任何问题的) - 我们在讲字符存入到变量当中时,本质上是将字符的ascii码值存入到变量所开辟的内存空间中
- 例如字符’a’的ascii码值就是97,当我们将其存储时,就是将其ascii码值转换为二进制,存放到我们变量所开辟的空间中,这是Reason 1 ;
- Reason 2 就是,如果getchar 在遇到读取错误或者**EOF(end of file文件结束标志)**时,getchar()会返回一个EOF
那么EOF究竟是什么呢?它有没有具体的值呢?
来通过 EOF
的定义看一下。
看到如上EOF的定义,那么它的返回值-1跟计算机定义它的返回类型为整型有什么关系呢?
-1是整型数据,在内存中占据四个字节
综合储存值类型
(ascii值)和储存空间大小
(4字节)考虑,C语言程序设计者最终采用了int作为getchar()的返回类型。
注
:getchar()
函数用法:
- 当我们输入字符s之后,我们要敲回车键输入才会停止,然后才会执行printf()语句进行输出,将字符s真正输出出来。
在上述代码框中,大家可以看到有两个字符s
- 第一个是我们输入的字符;
- 第二个是执行printf()语句后输出的语句。
2.1.4 putchar()
函数
那么,难道输出字符只能用prinf进行输出吗?难道没有一个函数与getchar进行对应吗?
答案是有的,那个函数就是putchar
putchar
的作用 :
写一个字符到流里面或者到标准输出(显示器)中。
用法:
2.2 do-while
循环
格式:
do
{
循环体;
能够让循环结束的语句;
....
}
while (循环条件 );
do-while
循环执行流程:- 首先不管
while
中的条件是否成立, 都会执行一次"循环体"; - 执行完一次循环体,接着再次判断
while
中的条件是否为真;- 为
真
继续执行循环体; - 为假跳出循环
- 为
- 重复以上操作, 直到"循环控制条件"为假为止
注
:while和do while应用场景
- 绝大多数情况下
while
和do while
可以互换, 所以能用while,就用while; - 无论如何都需要先执行一次循环体的情况, 才使用
do while
; - do while 曾一度提议废除,但是他在输入性检查方面还是有点用的。
示例:口令校验:
#include<stdio.h>
int main()
{
int num = -1;
do
{
printf("请输入密码,验证您的身份\n");
scanf("%d", &num);
}
while(123456 != num);
printf("主人,您终于回来了\n");
}
2.3 for
循环
我们已经知道了while循环,但是我们为什么还要一个for循环呢?
首先来看看for循环的语法:
2.3.1 语法
for
循环一般形式:
for(表达式1; 表达式2; 表达式3)
{
循环语句;
}
- 表达式1
表达式1为初始化部分,用于初始化循环变量的。我们称之为条件初始化。
- 表达式2
表达式2为条件判断部分,用于判断循环时候终止。我们称之为条件判断。
- 表达式3
表达式3为调整部分,用于循环条件的调整。我们称之为条件更新。
- 循环语句
每一次进入循环条件判断通过后需要执行的语句,如果想要执行多条语句需要用 {}
将我们需要要执行的多条语句括起来形成一个语句块。
从上面可以看出:for语句与while语句与do while语句不同的地方在于它的条件初始化、条件判断、条件更新更为紧凑,都在同一个()内,方便进行后续的修改,
而do while 与while语句这三个部分相隔就比较远,不便于进行修改,也因此我们使用for循环的频率更高。
它的执行过程如下:
- 执行表达式1,对循环变量做初始化;
- 判断表达式2,若其值为
真(非0)
,则执行for循环体中执行代码块,然后向下执行;若其值为假(0)
,则结束循环; - 执行表达式3 (
i++
)等对于循环变量进行操作的语句; - 执行for循环中执行代码块后执行第二步;第一步初始化只会执行一次。
- 循环结束,程序继续向下执行。
注意
:for循环中的两个分号一定要写。
示例:
#include <stdio.h>
int main()
{
int i = 0;
//for(i=1/*初始化*/; i<=10/*判断部分*/; i++/*调整部分*/)
for (i = 1; i <= 10; i++)
{
printf("%d ", i);
}
return 0;
}
2.3.2 break
与continue
在for循环中
- 通过对比while和do while,它们在使用continue和break时,唯一的区别点在于
- for在执行
continue
后进入的是条件更新语句,而while与do while则进入条件判断语句,然后进入下一次循环, - 而使用
break
时两者都一样,都是跳出循环。
- for在执行
2.3.3 for
循环注意事项
-
不可在for 循环体内修改循环变量,防止 for 循环失去控制。
-
建议for语句的循环控制变量的取值采用“前闭后开区间”写法。原因就是左闭右开可以清楚的看出循环次数。(当然,这并不是强制的,有时也应该根据使用场景进行灵活变通)
下面给出一个例子,帮助大家理解第二条建议:
int i = 0;
//前闭后开的写法
for(i=0; i<10; i++)
{
}
//两边都是闭区间
for(i=0; i<=9; i++)
{
}
观察上面两个例子,
- 前者采用的是左闭右开,后者采用的是完全闭区间
- 而前者很容易就能看出该循环的循环次数为10次,即10减去0
- 而后者则需要9-0+1才能得到真正的循环次数
- 虽然左闭右开不是强制规定的,但却是众多程序员所极力推荐的,因为这样写的话将会有更好的阅读体验,也有助于后续的调试。
2.4 三种循环比较
while
, do-while
和for
三种循环在具体的使用场合上是有区别的,如下:
- 在知道循环次数的情况下更适合使用for循环;
- 在不知道循环次数的情况下适合使用while或者do-while循环:
- 如果有可能一次都不循环应考虑使用while循环
- 如果至少循环一次应考虑使用do-while循环。
但是从本质上讲,while,do-while和for循环之间是可以相互转换的。
2.5 多重循环
多重循环就是在循环结构的循环体中又出现循环结构。
在实际开发中一般最多用到三层重循环。
因为循环层数越多,运行时间越长,程序越复杂,所以一般用2-3层多重循环就可以了。另外不同循环之间也是可以嵌套的。
多重循环在执行的过程中,外层循环为父循环,内层循环为子循环,
父循环一次,子循环需要全部执行完,直到跳出循环。父循环再进入下一次,子循环继续执行
使用for循环打印9×9乘法表
#include <stdio.h>
int main()
{
// 定义相乘数字i,j以及结果result
int i, j, result;
for(i=9;i>=1;i--)
{
for(j=1;j<=i;j++)
{
printf("%d*%d=%d ",i,j,result=i*j);
}
printf("\n");
}
return 0;
}