文章目录
- 前言
- 一,while 循环
- 二,for? ?循环
- 三,do? while 循环
- 四,goto语句
- 五,练习题巩固
- 总结
前言
本篇内容主要记录 循环语句:
包括while循环,for循环,do...while,goto循环详细讲解以及习题巩固练习
____________________________________________________________________________
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?****正文开始****
一、while 循环
在我们的日常生活中有很多实际的例子:
同一件事情我们需要完成很多次。 那我们怎么做呢? C语言中给我们引入了: while 语句,可以实现循环。
//while 语法结构
while(表达式)
循环语句;
Q : 比如我们实现:在屏幕上打印1-10的数字。
int main() {
int i = 0; // 初始化
while (i <= 10) {// 判断
printf("%d ", i);
i++; //调整部分
}
return 0;
}
这段代码中已经足够清晰的反应了程序的执行过程。
上面的代码已经帮我们了解了 while 语句的基本语法。
那我们再了解一下:
(一)while语句中的break和continue
1>break在while循环中
Q : 我们看这段代码,它的执行结果是什么呢?
int main() {
int i = 1;
while (i <= 10) {
if (5 == i)
break;
printf("%d ", i);
i++;
}
return 0;
}
我们看代码运行结果:
我们发现了break在while循环中的作用:
其实在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。
所以:while中的break是用于永久终止循环的。
2>continue在while循环中
Q : 我们看这段代码,它的执行结果是什么呢?
int main() {
int i = 1;
while (i <= 10) {
if (5 == i)
/*break;*/
continue;// continue 会跳过后面的语句
printf("%d ", i);
i++;
}
return 0;
}
我们看运行结果:
?Q : 我们再看这段代码,它的执行结果是什么呢?
int main() {
int i = 1;
while (i <= 10) {
i++;
if (5 == i)
continue;// continue 会跳过后面的语句
printf("%d ", i);
}
return 0;
}
我们看它的运行结果:
?我们能够发现:第一段代码运行到4之后,当i==5的时候发生了死循环。这是因为continue起了作用,我们就要提到continue 的作用了。
continue在while循环中的作用就是:
continue是用于终止本次循环的,也就是本次循环中continue后边的代码不会再执行,
而是直接跳转到while语句的判断部分。进行下一次循环的入口判断。
A :
因此第一段代码中当 i==5 的时候,走到continue时跳出了本次循环到了,但是这时候 i 还并没有i++,当下一次 i 进入循环的时候,i 的值还是5,再次continue,这就造成了死循环。
同理:
Q : 为什么第二段代码没有造成死循环呢?
A :
其实我们只要自己观察分析代码会发现,在 if 判断之前 i++ 了一次;这就会导致当 i==5时,continue跳出本次循环时,在下一次进入循环的时候 i 并不是仍然是5,而是6(因为i++了一次),所以 if 判断为假,不会continue跳出循环,而且会打印 数字,因此这就是为什么第二段代码没有造成死循环,并且打印的结果中没有数字5。
?(二)getchar 详解
Q : 我们在观察这段代码,他是什么意思?
int main() {
int ch = 0;
while ((ch = getchar())!= EOF) {
putchar(ch);
}
return 0;
}
这里的代码适当的修改是可以用来清理缓冲区的.
#include <stdio.h>
int main()
{
? ?char ch = '\0';
while ((ch = getchar()) != EOF)
{
? ? if (ch < ‘0’ || ch > ‘9’)
? ? ? ?continue;
? ? putchar(ch);
}
return 0; }
这个代码的作用是:只打印数字字符,跳过其他字符的
举例:? 请观察这段代码?他会正常输出我们想要的结果吗?
int main() {
char input[20] = { 0 };
printf("请输入密码:>");
scanf("%s", input); // abcdef
getchar(); // 拿走 \n
printf("请输入密码(Y/N):>");
int ch = getchar();
if (ch == 'Y') {
printf("确认成功\n");
}
else {
printf("确认失败\n");
}
return 0;
}
查看运行结果:
?我们发现如果连续的输入一段数字,程序会正常按照我们的意思输出,但是如果我们更改输入的方法,他还会正常吗?
我们观看这样的输入方式:
?在这里我们输入的密码:123? 456
我们在123和456之间加入一个空格,我们发现这就导致了我们直接略过了判断密码是否争取的那一步,并且输出了确认失败,这是为什么呢?
这是因为:
我们从键盘输入: 123 456
实际上是: 123 456\n
读取字符串的时候,遇到空格就结束了,所以getchar只都读走了123
缓冲区内部还有:_?(空格)456\n
所以一个getchar并不能解决问题,应该使用一种方法将缓冲区的所有字符带走,这时候就可以运用while循环,具体代码如下:
//清理缓冲区
int tmp = 0;
while ((tmp = getchar()) != '\n') {
; //空语句
}
通过清理缓冲区这时候就可以达到我们想要的结果:
整体代码如下:
int main() {
char input[20] = { 0 };
printf("请输入密码:>");
scanf("%s", input); // 123 456
//清理缓冲区
int tmp = 0;
while ((tmp = getchar()) != '\n') {
; //空语句
}
printf("请输入密码(Y/N):>");
int ch = getchar();
if (ch == 'Y') {
printf("确认成功\n");
}
else {
printf("确认失败\n");
}
return 0;
}
我们再看 演示结果:
?我们发现解决了问题
二,for? ?循环
一:语法
for(表达式1; 表达式2; 表达式3)
循环语句;
表达式1
表达式1为初始化部分,用于初始化循环变量的。
表达式2
表达式2为条件判断部分,用于判断循环时候终止。
表达式3
表达式3为调整部分,用于循环条件的调整。
我们继续以实例的方式了解for循环语句:
实际的问题:
Q :使用for循环 在屏幕上打印1-10的数字。
int main() {
int i = 0;
//for(i=1/*初始化*/; i<=10/*判断部分*/; i++/*调整部分*/)
for (i = 1; i <= 10; i++){
printf("%d ", i);
}
return 0;
}
现在我们来对比一下while循环和for循环:
int i = 0;
//实现相同的功能,使用while
i = 1;//初始化部分
while (i <= 10)//判断部分
{
printf("hehe\n");
i = i + 1;//调整部分
}
//实现相同的功能,使用while
for (i = 1; i <= 10; i++) {
printf("hehe\n");
}
可以发现在while循环中依然存在循环的三个必须条件,但是由于风格的问题使得三个部分很可能偏离较远,这样查找修改就不够集中和方便。所以,for循环的风格更胜一筹;for循环使用的频率也最高。
(一)break和continue在for循环中
我们发现在
for
循环中也可以出现
break
和
continue
,他们的意义和在
while
循环中是一样的。
但是还是有些差异:
1>break 在for循环中
//代码1
#include <stdio.h>
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
if (i == 5)
break;
printf("%d ", i);
}
return 0;
}
我们观察运行结果:
我们观察到输出的结果为:1 2 3 4?
这是因为: 当 i == 5 进入 if 判断当中时,直接跳出 for 循环?
到达 return 0;?
因此打印出 : 1 2 3 4(和while 循环类似)
其实在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。
2>continue?在for循环中
#include <stdio.h>
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
if (i == 5)
continue;
printf("%d ", i);
}
return 0;
}
我们观察运行结果:
我们观察到输出的结果是:1 2 3 4 6 7 8 9 10
跳过了数字5,但是它并不是和while循环一样发生了死循环,这是因为for在执行的时候会有执行顺序,当表达式2成立进入循环时遇到continue跳出本次循环时,会接着执行表达式3,也就是调整部分,i 会 i++,这时候 i 会自增成6,在下一次进入循环时,不进入 if 判断。
因此:
我们从结果上就会得到:打印出1 2 3 4? 6 7 8 9 10 跳过了数字 5 的打印。
这就是continue在for循环中的作用
建议:
? ?for (i = 0; i < 10; i++)? ----->建议写成前闭后开,10表示打印10次 提高可读性
?1. for ?的舒适化,判断,调整三个部分都可以省略
?2. 中间的判断部分如果省略,意味着判断恒为真,就构成了死循环
?3. 如果条件允许,不建议省略for循环的3个表达式
死循环举例:
for (;;) {
printf("hehe\n");// 死循环打印hehe
}
我们再来看这段代码:
?? ?int i = 0;
?? ?int j = 0;
?? ?for (i = 0; i < 3; i++){
?? ??? ?for (j = 0; j < 3; j++) {
?? ??? ??? ?printf("hehe\n");
?? ??? ?}
?? ?}
我们看运行结果:
我们发现这个程序打印了 9 行 hehe,这是因为当 i ==0 进入程序的时候 j 从0开始循环,当 j == 0 时, 打印一遍 hehe;当 j == 1 时, 打印第二遍 hehe ,d ;当 j == 2 ,打印第三遍 hehe;当 j ==3 不小于3的时候跳出 j 的循环 这时候 i++,此时 i == 1,同理,j 又从0开始打印 3遍hehe;i 再 i++;j 又打印3遍hehe,当 i==3 时 ,i < 3 不成立时,退出循环 ,这时候统计发现一共打印了9遍呵呵。
但是,如果我们省略表达式一(初始化),打印的结果会完全不同。
int main() {
int i = 0;
int j = 0;
for (; i < 3; i++) {
// j = 3 没再初始化了
for (; j < 3; j++) {
printf("hehe\n"); // 打印3个hehe
}
}
return 0;
}
我们观察运行结果:
?这是因为当 i++ 增到 i==1 进入j 的循环时,j 并没有初始化,还是i=1时候的i++是3,不会再进入j 的循环,因此只会打印? i?==1 第 一 次的3 个hehe。
总结:如果条件允许,不建议省略for循环的3个表达式
我们再来看这一道题 :?
//int main() {
// int i = 0;
// int k = 0;
// // k = 0 赋值0 结果是0 表示假 不进入循环
// for (i = 0, k = 0; k = 0; k++) {
// k++;
// }
// return 0;
//}
Q:问这段代码循环几次?
A : 通过代码我们发现 for循环中的表达式2 是k = 0,‘=’是赋值符号,因此是将数字0赋值给k,我们知道在C语言中0表示假,因此表达式2 判断为假,根本不会进入for循环,因此这段代码循环0次。
三,do? while 循环
do
语句的语法:
do
循环语句;
while(表达式);
do语句的特点 :?
循环至少执行一次,使用的场景有限,所以不是经常使用
#include <stdio.h>
int main()
{
int i = 1;
do
{
printf("%d\n", i);
i++;
} while (i < 10);
return 0;
}
这段代码是用while循环打印1-10。
(一)do while循环中的break和continue
1> break 在 do? while? 循环中
int main() {
int i = 1;
do {
if (i == 5)
break;//打印 1 2 3 4
printf("%d ", i);
i++;
} while (i <= 10);
return 0;
}
道理同break在while和for循环中一样。
2>?continue?在 do? while? 循环中
int main() {
int i = 1;
do {
if (i == 5)
continue;// 1 2 3 4死循环
printf("%d ", i);
i++;
} while (i <= 10);
return 0;
}
运行结果:
?原因和while循环中的道里一致,因为continue是跳出本次循环,不会执行后面的i++,所以如果当i==5时就会一直死循环。
这时候我们如果将i++放到continue之前结果为:
int main() {
int i = 1;
do {
i++;
if (i == 5)
continue;// 1 2 3 4死循环
printf("%d ", i);
} while (i <= 10);
return 0;
}
?我们发现和while循环中的将i++的第二种可能性一直,道理相同。
四,goto语句
C
语言中提供了可以随意滥用的
goto
语句和标记跳转的标号。
从理论上
goto
语句是没有必要的,实践中没有
goto
语句也可以很容易的写出代码。
但是某些场合下
goto
语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程。
例如:一次跳出两层或多层循环。
多层循环这种情况使用
break
是达不到目的的。它只能从最内层循环退出到上一层的循环。
goto
语言真正适合的场景如下:
// 多层循环这种情况使用break是达不到目的的,他只能从最内层循环退出上一层的循环
// 这时候 goto语句适合这种场景
for () {
for () {
for () {
if (disaster) {
goto error;
}
}
}
}
...
error:
if(disaster)
// 处理错误情况
goto again 用法(标签一致就行,但标签必须在同一个函数内)
int main() {
again:
printf("hehe\n");
printf("haha\n");
goto again; // 标签一致就行,标签必须在同一个函数内
return 0;
}
结果演示:?
会死循环打印hehe和haha.
小游戏,小整蛊:
//例如: 写一个关机程序
//只要程序启动了,就倒计时60秒关机,如果60秒之内,输入:我是猪,就取消关机,如果不输入,时间到就关机
shutdown windows提供的关机命令
shutdown -s -t 60秒之后关机
shutdown -a 取消关机
int main() {
char input[20] = { 0 };
system("shutdown -s -t 60");
again:
printf("请注意,你的电脑在1分钟内关机,如果输入:我是猪,就取消关机\n");
scanf("%s", input); //input本来就是地址 不用取地址
//判断
if (strcmp(input,"我是猪") == 0) {
// 取消关机
system("shutdown -a");
}
else {
goto again;
}
return 0;
}
五,练习题巩固
1.计算n的阶乘
int main() {
int n = 0;
scanf("%d", &n);// 5
int i = 0;
int ret = 1;
for (i = 1; i <= n; i++) {
ret *= i;
}
printf("%d\n",ret);
return 0;
}
?2.计算 1!+2!+3!+4!+.....n!
int main() {
int n = 0;//共n个数字
scanf("%d", &n);
int i = 0;// j 内部的第 i 个数字
int j = 0;// n 内部的第 j 个数字
int sum = 0;
for (j = 1; j <= n; j++) {//
int ret = 1;
for (i = 1; i <= j; i++) {
ret *= i;
}
sum += ret;
}
printf("%d\n", sum);
return 0;
}
当然这道题我们还有优化算法:
int main() {
int n = 0;
int i = 0;
int ret = 1;
int sum = 0;
for (n = 1; n <= 10; n++) {
ret = ret * n;
sum += ret;
}
printf("%d\n", sum);
return 0;
}
3.在一个有序数组中查找具体的某个数字n(二分查找)
这个是普通求法:
int main() {
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int k = 7;
int i = 0;
for (i = 0; i < 10; i++) {
if (arr[i] == k) {
printf("找到了,下标是%d\n", i);
break;
}
else if (i == 10) {
printf("找不到\n");
}
}
return 0;
}
我们发现,如果说这个数组中定义了100甚至更多的数字时,这样的算法就会耗时耗力,因为有一种更简便的算法:
二分法 -- 折半查找
int main() {
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
// 40 / 4 = 10
int k = 7;
int left = 0;
int right = sz - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (arr[mid] < k) {
left = mid + 1;
}
else if (arr[mid] > k) {
right = mid - 1;
}
else {
printf("找到了,下标是%d \n", mid);
break;
}
}
if (left > right) {
printf("找不到\n");
}
return 0;
}
? 4:反向打印一个数字
int main() {
int n = 0;
scanf("%d", &n);
while (n!=0) {
printf("%d", n % 10);
n = n / 10;
}
return 0;
}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?****正文结束****
———————————————————————————————————————————
总结
本篇文章的内容就记录完毕,由于本人技术水平有限,若各位读者发现错误,欢迎及时纠正。
|