四、循环语句
1.while
while(表达式)
{
循环语句;
}
看代码:在屏幕上打印1-10
#include<stdio.h> //硬核输出 int main01() { printf("1 2 3 4 5 6 7 8 9 10");//如果要打印1-100,甚至更多 - 那太麻烦了 return 0; } //循环输出 int main02() { //循环的起始是1,终止是10 int i = 1;//初始化部分 while (i <= 10)//判断部分 { printf("%d ", i); i++;//调整部分 } //三个部分任何一个部分发生变化,都会影响到循环 return 0; }
while循环中的break和continue
#include<stdio.h> int main01() { int i = 1; while (i <= 10) { if (5 == i) { break; } printf("%d ", i); i++; } //结果是1 2 3 4 - 一旦满足条件break就永久跳出循环 return 0; } int main02() { int i = 1; while (i <= 10) { if (5 == i) { continue; } printf("%d ", i); i++; } //结果是1 2 3 4 ... ... - 死循环 - continue的作用是跳过本次循环continue后面的代码,直接去while循环判断部分,进行下一次循环入口的判断 //这里造成死循环的原因是一旦5==5成立,则会跳过下面的代码(跳过了i++),回到while(i<=10) return 0; }
getchar和putchar
int main01() { //getchar可以从键盘读取一个字符 - 它的返回值是字符(所对应的ASCII码值);如果读取时遇到了错误或文件结束,则返回EOF //putchar可以输出一个字符 //EOF - end of file - 文件结束标志 - 右击可以对EOF转到定义,发现EOF的值是-1 int ch = getchar(); printf("%c\n", ch); putchar(ch); //发现它不管输入多少字符,只能输出一个 return 0; } //使用循环的方式让putchar能输出多个字符 int main02() { int ch = 0; while ((ch = getchar()) != EOF) { putchar(ch); } //事实上getchar不是直接从键盘上读,而是在getchar与键盘之间的缓冲区读 //当输入"A回车"后 - 缓冲区其实存在两个字符 - 'A','\n' //CTRL+Z - getchar就读取结束 return 0; }
getchar所应用的场景:
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int main01() { char password[20] = { 0 }; printf("请输入密码:>"); //对于数组的数组名本身就是一个地址 - 所以可以不用& scanf("%s", &password);//123456\n printf("请确认密码(Y/N):>"); int ch = getchar(); if (ch == 'Y') { printf("确认成功\n"); } else { printf("确认失败\n"); } //发现我们在输入密码回车后 - 程序并没有等待我们确认密码 - 而是直接确认失败 //我们都知道:scanf和getchar在读取数据时,是在输入缓冲区里读 //当我们输入123456\n时,scanf只会读取除\n以外的数据;这时输入缓冲区里还剩1个\n,getchar一看输入缓冲区里有内容,就直接拿走了;'\n'=='Y'为假,执行else return 0; } //改正后: int main02() { char password[20] = { 0 }; printf("请输入密码:>"); scanf("%s", &password);//123456 abcdef\n printf("请确认密码(Y/N):>"); getchar();//清理缓冲区 - 把\n拿走 int ch = getchar(); if (ch == 'Y') { printf("确认成功\n"); } else { printf("确认失败\n"); } //这里我们输入123456 abcdef\n时发现它又停不下来了 //scanf这里只会把空格前面的字符读走,此时在缓冲区里还剩很多的字符 return 0; } //改正后的改正: int main03() { char password[20] = { 0 }; printf("请输入密码:>"); scanf("%s", &password);//123456 abcdef\n printf("请确认密码(Y/N):>"); int temp = 0; while ((temp = getchar()) != '\n')//使用循环清理缓冲区里的多个字符 { ; } int ch = getchar(); if (ch == 'Y') { printf("确认成功\n"); } else { printf("确认失败\n"); } return 0; }
看代码:结果是什么
#include<stdio.h> int main() { int ch = 0; while ((ch = getchar()) != EOF) { if (ch<'0' || ch>'9')//如果是非数字字符则执行continue跳过本次循环,再次判断;否则就输出 { continue; } else { putchar(ch); } } //这段程序的功能是只打印数字 return 0; }
2.for
for (表达式; 表达式; 表达式)
{
循环语句;
}
已经学习了while循环了,为什么还要学习for循环?或者说while循环有什么缺陷?
#include<stdio.h> int main01() { int i = 1;//初始化部分 //... //... while (i <= 10)//判断 { printf("%d ", i); } //... //... i++;//调整 //在未来写的代码越来越多的时候,这三个部分可能会隔的比较远,导致更改或阅读不方便 return 0; } //for循环很好的规避了这个问题 - 它把初始化、判断、调整三个部分放到了一个括号里 //for(表达式; 表达式; 表达式) //for(初始化; 判断; 调整) //看代码:使用for循环打印1-10 int main02() { int i = 0; for (i = 1; i <= 10; i++) { printf("%d ", i); } return 0; }
for循环中的break和continue
#include<stdio.h> int main01() { int i = 0; for (i = 1; i <= 10; i++) { if (5 == i) break; printf("%d ", i);//1 2 3 4 } //5==5为真,终止所在的for循环 return 0; } int main02() { int i = 0; for (i = 1; i <= 10; i++) { if (5 == i) continue; printf("%d ", i);//1 2 3 4 6 7 8 9 10 } //这里并没有跳过调整部分i++,所以不会死循环;而while循环中的continue很可能会跳过调整部分,造成死循环 return 0; }
使用for循环的建议及注意
1.不可在for循环内修改循环变量,防止for循环失去控制
#include<stdio.h> int main() { int i = 0; for (i = 1; i <= 10; i++) { printf("%d ", i); i = 5;// - err:死循环的原因 } return 0; }
2.建议for语句的循环控制变量的取值采用“前闭后开区间的写法”
#include<stdio.h> int main() { int arr[10] = { 0 }; int i = 0; //不建议写成for(i=0;i<=9;i++) - 前闭后闭区间 - 并不是这种写法是错的 - 而是说可读性相对来说较差 for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; }
3.for循环中关于定义初始化问题
#include<stdio.h> int main() { //这里是把i定义到了for循环内部 for (int i = 0; i < 10; i++) { printf("%d ", i); } //发现在VS2017中运行没有问题,其实这种写法是C++的语法。虽然可以运行,但是在其它平台上可能会造成跨平台的问题 return 0; }
for循环的一些其它形式
1.
#includ<stdio.h> int main() { //for循环的初始化、判断、调整都可以省略,语法是支持的 - 但不建议 //判断部分的省略 - 恒为真 - 死循环 for (;;) { printf("hehe\n"); } return 0; }
先看代码:共输出了多少“hehe”
#include<stdio.h> int main01() { int i = 0; int j = 0; for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { printf("hehe\n");//共打印9个"hehe" } } return 0; } //拿上面的代码来说:因为已经定义了i和j,所以将for循环里的i=0和j=0省略? int main02() { int i = 0; int j = 0; for (; i < 3; i++) { for (; j < 3; j++) { printf("hehe\n");//共打印3个"hehe" } } //这里当i=0时,在内层循环输出3个“hehe”后;i=1,此时这里的j=3,并没有被重新初始化为0 return 0; }
#include<stdio.h> int main() { int x, y; for (x = 0, y = 0; x < 2 && y < 5; ++x, y++) { printf("hehe\n");//输出2个“hehe” } return 0; }
小试牛刀 - 问循环循环多少次
int main() { int i = 0; int k = 0; for (i = 0, k = 0; k = 0; i++, k++) { k++; } //因为k=0为假,所以不会进入到循环内部 return 0; }
3.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
#include<stdio.h> int main01() { int i = 1; do { if (5 == i) break; printf("%d ", i);//1 2 3 4 i++; } while (i <= 10); return 0; } int main02() { int i = 1; do { if (5 == i) continue; printf("%d ", i);//1 2 3 4...死循环 i++; } while (i <= 10); //当5==5为真时,它会跳过调整部分i++,到判断部分 return 0; }
do…while循环的特点:循环至少执行1次,使用的场景有限,所以不是经常使用
五、跳转语句
1.goto
c语言提供了可以随意滥用的goto语句和标记跳转的标号;从理论上goto语句是没有必要的,但是在某些场合还是有用的着的地方
最常见的用法就是终止程序在某些深度嵌套的结构的处理过程,例如一次跳出两层或多层循环,这种情况break是不适合的。除此之外不建议使用goto
for (…)
{
for (…)
{
for (…)
{
if (disaster)
goto error;
}
}
}
注:goto语句只能在一个函数范围内跳转,不能跨函数
int main() { flag: printf("hehe\n"); printf("haha\n"); goto flag; //结果是死循环 - 这里goto定义了flag;当每次走到goto语句时它都会跳转到与flag匹配的地方 return 0; }