目录
循环语句
一.while 循环
1.语法结构
2.break 和 continue 的用法
3.while 中的清理缓冲区
(1)getchar 和 putchar 的使用
(2)缓冲区的概念
(3)为什么清理缓冲区
(4)如何清理缓冲区
(5)我们来再看一个例子
二.do while 循环
1.基本形式
2.do while 和 while 的区别
3.break 和 continue 的用法
三.for 循环
1.基本形式
2.break 和 continue 的用法
3.两个好习惯
4.一些变种
(1)for 条件的省略
(2)for 的嵌套
(3)for 初始化的省略
(4)两个变量的
(5)容易犯错
四.goto 语句
1.两个小函数
(1)system函数
(2)strcmp函数
2.goto的用法
3.实例——关机程序
结束语
1.while
2.for
3.do while
while(表达式)
循环语句;
我们进行实现
()中的表达式,表达为真,继续循环,表达为假出循环,0表示假,!0表示真
#include
int main()
{
int i = 1;
while(i<=10) //()中的表达式,表达为真,继续循环,表达为假出循环,0表示假,!0表示真
{
printf("%d ", i);
i = i+1;
}
return 0;
}
#include
int main()
{
int i = 1;
while(i<=10)
{
if(i == 5)
{ //当i等于5的时候,if判断这个成立,所以break执行,if是判断break是否执行的,是在整个while中
break;
} //而当break执行的时候,会直接终止循环,下面的循环都不在执行,全部停止
printf("%d ", i);
i = i+1; //这个break虽然在if里,但是if只是判断它发生不,一旦执行,整个while都停下来
}
return 0;
}
打印的结果为 1 2 3 4
break在while循环中的作用:
其实在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。
所以:while中的break是用于永久终止循环的。
我们再来看continue
#include
int main()
{
int i = 1;
while(i<=10)
{
if(i == 5) //当i等于5的时候,if里的开始执行,continue执行,就会跳过后面的代码,直接回到while再开始循环
{
continue; //这个时候跳过后面的i++,导致后面陷入到死循环中,也不打印,也不++,就死在这了。
}
printf("%d ", i); //所以我们知道continue的用法就是跳过它后面的代码,回到上面的while中在进行循环
i++;
}
return 0;
}
这个打印的结果是 1 2 3 4 _ 后面就是一个死循环,因为continue的作用就是跳过后面的代码,重新回到上面的循环中,继续执行,而这个跳过了 i++,所以i的值一直是5,所以会一直continue,就陷入到死循环中了,我们怎么解决呢?
#include
int main()
{
int i = 1;
while(i<=10)
{
i = i + 1;
if(i == 5) //当i等于5的时候,if里的开始执行,continue执行,就会跳过后面的代码,直接回到while再开始循环
{
continue; //所以等于5的时候,跳过了打印,回到上面的循环中,再进行,所以打印出来没有5,结果是1 2 3 4 6 7 8 9 10
}
printf("%d ", i); //所以我们知道continue的用法就是跳过它后面的代码,回到上面的while中在进行循环
}
return 0;
}
我们把 i++放到continue的前面,这样就不会跳过这个调整部分了,所以就能继续循环,跳过后面的代码,回到上面的循环,打印结果就是1 2 3 4 6 7 8 9 10
continue在while循环中的作用就是:
continue是用于终止本次循环的,也就是本次循环中continue后边的代码不会再执行,
而是直接跳转到while语句的判断部分。进行下一次循环的入口判断。
所以我们就常用在:某一次条件条件发生了,这一次循环后的代码不想让她执行了,就直接跳过去
当我们想要在输入一个字符,并且打印它的时候,我们头脑中最先想到的一定是scanf和printf,这两个函数搭配使用来输出并且打印。
#include
int main()
{
char n;
scanf("%c", &n);
printf("%c", n);
return 0;
}
当我们用getchar和putchar的时候
#include
int main()
{
char n;
//scanf("%c", &n);
//printf("%c", n);
n = getchar();//从键盘中获取一个字符
putchar(n);//输出一个字符到屏幕上
return 0;
}
注意:scanf和printf可以针对各种各样的数据进行输入输出。但是getchar和putchar仅仅针对字符
当我们对他们加上while循环后,我们来看
int main()
{
int ch = 0;
while ((ch=getchar()) != EOF) //这个!=EOF于scanf是一样的效果,看他是是否读到这个字符,读到了就是返回1,读取失败
{ //返回EOF,而1!=EOF,判断真,就继续循环读,EOF!=EOF判断为假,就出循环结束不读了
putchar(ch); //想停止于scanf一样就是ctrl+Z停止下来
}
return 0;
}
这里又出现了我们常见的 EOF
所以下面来看getchar与scanf返回值的相同
在我们多组输入的时候,我们就介绍过 EOF,那这么getchar也可以看到 EOF,我们来对比一下
#include
int main()
{
int a, b;
while (scanf("%d %d",&a,&b) != EOF)
{
//代码段;
}
return 0;
}
这里他们俩的效果是一样的道理,我们在输入的时候,scanf 和 getchar 都是会去读取你所输入的数据,当他俩读取不到的时候,就会返回 EOF,所以我们这个用循环去判断,保证他们可以读取完你的数据,从而来实现多组输入,getchar 也一样,也是为了读取完你的数据,我们想停下来,也是一样 ctri + Z 就可以停止下来。
我们 getchar 读取数据的时候是从缓冲区拿的,我们来看图
所以我们来看一段代码
#include
int main()
{
char ch = 0;
while ((ch = getchar()) != EOF) {
putchar(ch);
}
return 0;
}
我们输入几个数据打印出来的效果是这样的
为什么我们打印的值都是换行后排列的呢
当我们在输入的时候,和最后执行的时候,我们先输入 a 然后输入回车,才在下面进行打印,回车就是 \n
这个时候我们在缓冲区里的就是 a \n ,这两个字符,但是我们 getchar 在拿的时候是一个一个字符拿的
第一次我先拿A,第二次我再拿这个 \n,所以我们打印的时候,会出现换行的效果
getchar 就是这样一个一个字符拿的,直到里面没有字符可以拿了,就返回 EOF
我们来看一段代码
int main()
{
//数组名本来就是地址,所以下面scanf可以不用再取地址了,不用 & 了
char password[20] = { 0 };
int ch = 0;
printf("请输入密码:>");
scanf("%s", password);//123456
//当我们输入密码后,我们回车后,直接就是:请确定密码(Y/N):>确认失败
//原因就是,我们scanf在拿的时候,只拿他自己需要的,我们这里时%s,所以他就只拿字符串,后面的他不要,他不拿
//他只拿属于自己类型的,后面或者有空格,或者就像这里的\n,他都不拿
//所以scanf就只拿123456,现在里面剩个\n,到了getchar拿了,就只剩个\n了,\n !== Y,所以直接就失败了
printf("请确认密码(Y/N):>");
ch = getchar();
if (ch == 'Y')
printf("确认成功\n");
else
printf("确认失败\n");
return 0;
}
来看我们的结果
直接输出,确认失败,这是为什么呢?我们来看图片中的缓冲区
我们scanf在拿的时候,只拿他自己需要的,我们这里时%s,所以他就只拿字符串,后面的他不要,他不拿
他只拿属于自己类型的,后面或者有空格,或者就像这里的\n,他都不拿
所以scanf就只拿123456,现在里面剩个\n,到了getchar拿了,就只剩个\n了,\n !== Y,所以直接就失败了
像刚才上面出现的那种情况,我们就需要一个代码来帮 scanf 把 \n 给拿走,现实情况中,不仅仅只有 \n ,可能还有会空格,其他的scanf拿不了的,都需要一段代码帮他拿走
while (getchar()!='\n')
{
;
}
就是这样的简单代码,我们加入到里面,我们也不管他拿走存到哪里,也不管他里面是什么代码,我让你过来,就是让你过来,拿代码,拿到 \n 后,判断为假,你出循环了,你任务就结束了。
int main()
{
//数组名本来就是地址,所以下面scanf可以不用再取地址了,不用 & 了
char password[20] = { 0 };
int ch = 0;
printf("请输入密码:>");
scanf("%s", password);//123456
//消除\n - 清理缓冲区
//当我们不加这段代码的时候,我们刚输入密码123456,我们回车进行下一步确定密码时,直接结束,说确定失败了
//所以现在加上这个代码,把后面的没有用的给拿走,不管输出啥,也不管存到哪,就给拿走就完了
//这里可以用!=EOF,也可以用!=\n,因为我们最后一个是\n,所以我们让!=,所以读到最后的\n的时候,为假的,就出循环了
//就把scanf拿不了的,都给拿走了,下面就能正常进行了
while (getchar()!='\n')
{
;
}
//我们来看我们的缓冲区,这里有scanf还要getchar都来接受
//scanf 缓冲区 键盘
//getcahr 123456\n
//当我们输入密码后,我们回车后,直接就是:请确定密码(Y/N):>确认失败
//原因就是,我们scanf在拿的时候,只拿他自己需要的,我们这里时%s,所以他就只拿字符串,后面的他不要,他不拿
//他只拿属于自己类型的,后面或者有空格,或者就像这里的\n,他都不拿
//所以scanf就只拿123456,现在里面剩个\n,到了getchar拿了,就只剩个\n了,\n !== Y,所以直接就失败了
//所以我们在scanf后面加个getchar,帮scanf拿不走的给拿走,我们后面就能正常了,给拿走,可以存也可以不存
//我们就是让他把scanf拿不了的拿走就行了,里面输出不输出,或者存不存,都不管他
printf("请确认密码(Y/N):>");
ch = getchar();
if (ch == 'Y')
printf("确认成功\n");
else
printf("确认失败\n");
return 0;
}
所以现在加上这个代码,把后面的没有用的给拿走,不管输出啥,也不管存到哪,就给拿走就完了
这里可以用!=EOF,也可以用!=\n,因为我们最后一个是\n,所以我们让!=,所以读到最后的\n的时候,为假的,就出循环了
就把scanf拿不了的,都给拿走了,下面就能正常进行了
这个代码的作用是:只打印数字字符,跳过其他字符的
#include
int main()
{
char ch = '\0'; //初始化,被害怕
while ((ch = getchar()) != EOF)
{
if (ch < '0' || ch > '9') //这里的0-9是数字字符,需要看ASCII表,对应的就是数字,所以这个范围就是只打印数字字符
continue; //跳过其他的字符,当不在0-9的范围,if执行,就会continue,下面的不执行了,回到上面的while
putchar(ch); //就只打印0-9里面的,不符合if,所以就不会continue,就会去打印
}
return 0;
}
运行结果为,只能打印,0--9之间的字符,其余全部不打印,因为即便是\n出现了输入缓冲区的作用也会因为满足判断条件,而被终止不会被打印出来
int main()
{
int i = 1;
do
{
printf("%d ", i);
i++;
} while (i<=10);
return 0;
}
这个就是上来先给你干一次,再去循环,判断在后面,while是先循环判断,在去执行一次,do while 是先执行一次,后再判断
#include
int main()
{
int i = 1;
do
{
if (5 == i)
break; //用法都是一样的,就是看清楚break放在哪里,注意看打印到几
printf("%d ", i);
i = i + 1;
} while (i <= 10);
return 0;
}
#include
int main()
{
int i = 1;
do
{
if (5 == i)
continue; //看清楚这个,就是死循坏了,因为continue跳过后面的代码,然后回到上面,所以i值不变了,也不打印了,死循环了
printf("%d ", i); //要看清楚放的地方是哪里,具体问题具体分析不要太过于死板
i = i + 1;
} while (i <= 10);
return 0;
}
其实 break 和 continue 的用法都是一样的,都是直接打破循环,直接跳过后面的代码回到上面,就是具体问题具体分析,看 continue 跳过了哪些代码,会不会产生死循环,有些调整该放到 continue 的放到上面,看清楚从哪打破,从哪些跳过去就好
先对比while中的,初始化,判断,调整的位置
int main()
{
int i = 1;//1 - 初始化
while (i < 10)//2 - 判断
{
printf("%d ", i);
i++;//3 - 调整
}
return 0;
}
现在我们再来看用for
使用for在屏幕上打印1~10
for(初始化;判断;调整)
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
printf("%d ", i);
}
return 0;
}
//代码1 1 2 3 4
#include
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
if (i == 5)
break; //break用法都是一样的,直接终止循环
printf("%d ", i);
}
return 0;
}
//代码2 1 2 3 4 6 7 8 9 10
#include
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
if (i == 5) //这个就跟while中的有点区别,但是continue都是一样的效果,都是直接跳过后面的代码,再回到上面的循环中
continue; //在while中,可能调整在continue后面所以会发生死循环,但是for不会,他的调整在上面,不怕continue的跳过
printf("%d ", i);
}
return 0;
}
其实 break 和 continue 的用法都是一样的,都是直接打破循环,直接跳过后面的代码回到上面,就是具体问题具体分析,看 continue 跳过了哪些代码,会不会产生死循环,有些调整该放到 continue 的放到上面,看清楚从哪打破,从哪些跳过去就好
在 for 中就不会容易出现像 while 中 continue 跳过的时候出现死循环,因为 for 的调整部分是在 for 里面,所以不会被 continue 给跳过
1. 不可在for 循环体内修改循环变量,防止 for 循环失去控制。
2. 建议for语句的循环控制变量的取值采用“前闭后开区间”写法。
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
//0~9
//打印数组的内容
int i = 0; //别在for{}改变变量的值,这样可能发生死循环,调整是在for()中进行的
for (i = 0; i < 10; i++) //就是这样写,前闭后开,写i<10 不写 i<=9,但是还是看题目的条件,都是全部都是这样的
{
printf("%d ", arr[i]);
}
return 0;
}
for循环的初始化,判断和调整三个部分都可以省略
但是省略调判断部分,判断就恒为真,循环就死循环
for (;;)
{
printf("hehe\n"); //这个就是一个死循环
}
int i = 0;
int j = 0;
for (i=0; i < 3; i++)
{
for (j = 0; j < 3; j++) //俩个循环套娃,打印9次
{
printf("hehe\n");
}
}
打印9个 hehe
int i = 0;
int j = 0;
//如果省略掉初始化部分,这里打印多少个hehe?
for(; i<3; i++)
{
for(; j<3; j++) //当省略到初始化的部分,只打印3个,再第一个i=0时,下面的循环3次后,j=3,就一直等于3了
{
printf("hehe\n"); //所以再回到上面的那个循环里,j还是一直等于3,所以就不打印了,直到i出循环
}
}
只会打印3个 hehe,因为一个循环后面,不会初始化,所以第二个 for 循环结束后,j 一直就是3,所以第一个 for 循环在第二个中就不会再 打印了,所以就只能打印3个 hehe
//使用多于一个变量控制循环
int x, y;
for (x = 0, y = 0; x<2 && y<5; ++x, y++)
{
printf("hehe\n"); //打印两次,去看好他们的判断条件,是或还是且,看清楚循坏几次,两个变量都要看
}
return 0;
}
就是要看清楚两个变量,都要注意他们的条件和判断,看什么时候出循环
//请问循环要循环多少次?
#include
int main()
{
int i = 0;
int k = 0;
for(i =0,k=0; k=0; i++,k++) //看清楚啊,这是赋值,不是相等的判断,是赋值!!!,k为0了,所以就不循环了,
k++; //k=0,是赋值,直接0为假,直接出循环了,
return 0;
}
要看清楚这里的判断不再是判断了,直接变成赋值了,k=0,是赋值,直接0为假,直接出循环了
先简单介绍一下,下一期会主要讲解的
这个函数头文件是 stdlib.h ,是用来执行电脑命令的一个库函数
这个函数头文件是 string.h ,是用来判断两个字符串是否相等的一个库函数
从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。 但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程。
例如:一次跳出两层或多层循环。 多层循环这种情况使用break是达不到目的的。它只能从最内层循环退出到上一层的循环
for(...)
for(...)
{
for(...)
{
if(disaster)
goto error;
}
}
…
error:
if(disaster)
// 处理错误情况
#include
#include
#include
int main()
{
char input[100];
system("shutdown -s -t 60"); //这引用这个库函数,来传递系统命令,-s 就是关机。-a 取消关机
//这是Windows系统下的一个关机命令,-t 60,就是六十秒后执行,注意空格
flag: //这里就是goto回到这的标志,goto后面加这个,就是回到这里
printf("你的电脑将在一分钟后关机,如果输入“我是猪”,就会取消关机!\n请输入: ");
scanf("%s",input);
if(0==strcmp(input,"我是猪")) //判断字符串相等不能直接判断,需要函数strcmp
{
system("shutdown -a");//取消关机命令
}
else
{
goto flag;
}
return 0;
}
system就是执行系统的命令,可以自己百度多做了解
而strcmp函数,就是判断两个字符串是否相等
第一个字符串 > 第二个字符串 返回的数值 < 0
第一个字符串 < 第二个字符串 返回的数值 > 0
第一个字符串 = 第二个字符串 返回的数值 为 0
但是这个goto也没必要,用循环也是一样,所以goto能不用就不用,多个嵌套的时候,看情况用
#include
#include
int main()
{
char input[10] = {0};
system("shutdown -s -t 60");
while(1)
{
printf("电脑将在1分钟内关机,如果输入:我是猪,就取消关机!\n请输入:>");
scanf("%s", input);
if(0 == strcmp(input, "我是猪"))
{
system("shutdown -a");
break;
}
}
return 0;
}
下一节会讲几个,分支语句和循环语句的典型重要例题并加以说明。
我的gitee仓库:https://gitee.com/he-yangtongxue/bit.c.test