一、循环结构
1、什么是循环
代码的重复执行,就叫做循环。
2、循环的分类
- 无限循环:程序设计中尽量避免无限循环;(程序中的无限循环必须可控)
- 有限循环:循环限定循环次数或者循环的条件。
3、循环的构成
- 循环体
- 循环条件
4、当型循环的实现
-
while
语法:
while(循环条件)
{
循环语句;
}
说明:
- 循环条件的返回值必须是boolean类型,在C语言中,布尔类型为真使用 非0 来表示,布尔类型为假使用 0 来表示;
- {} 包起来的内容整体称之为循环体;
- 我们要在循环体中控制循环条件的变化,否则会产生死循环
执行过程:
//可控制的无限循环
int i = 0;
while(i < 100)
{
printf("hello");
i++;
}
特点:
先判断,后执行,循环体语句有可能一次都不执行。
举例:计算1-100的累加和
/* 需求:while循环案例:如何编程来计算1+2+3+...+100? */ #include <stdio.h> int main() { //定义一个变量,保存累加和 int sum = 0; //定义一个循环变量 int i = 1; while(i <= 100)//循环条件,这里可以有关系表达式/逻辑表达式,表达式运算结果是boolean(1,0) { //累加计算 //sum = sum + i; sum += i; //给循环变量赋值,用来影响循环条件 i++; } printf("1-100的累加和是:%d\n",sum); return 0; }
举例:计算1-100之间的偶数和
/* 需求:while循环案例_计算1-100之间的偶数和,也就是2+4+6+8+...+100的累加和 */ #include <stdio.h> int main() { //创建一个变量,用来存放累加和 int sum = 0; //创建循环变量,初始值2 int i = 2; while(i <= 100) { //排除奇数 if(i % 2 == 0)//表示能被2整除,说明这个数是偶数 { sum += i; } i++;//改变循环变量的值,此时一定要注意这句代码的位置 } printf("1-100之间的偶数的累加和是:%d\n",sum); return 0; }
注意:
r变量计算式的定义要放在scanf函数的后面!
死循环
while(1);//我们会在死循环进行必要的限制
-
for..
语法:
for(①表达式1;②表达式2;③表达式3)
{
④循环体语句;
}
说明:
- () 中可以只保留两个分号,举例:(;;);
- ①是循环变量,我们需要赋初值,循环变量可以是列表,多个循环变量使用逗号分隔,举例:int i=0;
- ②是循环条件,用来限制循环的次数,循环条件支持关系表达式,如果加入逻辑表达式,会变成复合表达式,举例:i<10 && j<10 ;
- ③改变循环条件,支持列表,这里可以使用赋值表达式,举例:i++,j++;
- 执行顺序:①②④③ --> ②④③ --> ②④③... --> ②,这里①只执行一次;
执行过程:
特点:
先执行,后判断,循环体语句至少要执行一次。
举例:求阶乘
fabs(num) --> 取绝对值;
r、i 声名在外,赋值在for()内;
/* 需求:for案例_用户可通过键盘录入一个整数n,用来作为阶乘的最高位数 */ #include <stdio.h> #include <math.h> int main() { int n = 1;//接受控制台输入,作为阶乘最高位 int r = 1;//用来接受计算结果 printf("请输入一个整数:\n"); scanf("%d",&n); //循环实现阶乘 for(int i = 1;i <= fabs(n);i++) { r *= i; } printf("1-%d之间的阶乘的结果是:%d\n",n,r); return 0; }
举例:for求1-100之间的偶数和
/** *需求:for循环案例_求1-100之间的偶数和 */ #include <stdio.h> //while实现 void while_test() { int sum = 0; int i = 1; while(i <= 100) { if(1 % 2 == 0) { sum += i; } i++; } printf("while实现:1-100之间的偶数和:%d\n",sum); } //for实现 void for_test() { int sum = 0; for(int i = 1;i <= 100;i++)//死循环表示:while(1)、for(;;) { if(i % 2 == 0) { sum += i; } } printf("for实现:1-100之间的偶数和:%d\n",sum); } int main() { while_test(); for_test(); return 0; }
总结:
- for语句使用语法规则上,降低/避免因为忘记循环条件更新操作,而引起的产生无限循环的几率;
- 应用场合:for语句往往应用于循环次数实现可以确定的场景。
死循环
for(表达式1;;表达式3);
for(;;);
循环实现的三要素:
- 循环变量初始化;
- 循环条件;
- 循环变量更新。
举例:for_求Fibonacci数列前20个数
/* 需求:for案例_求Fibonacci数列前20个数 */ #include <stdio.h> int main() { int f1 = 1;//前一个数,默认是1,因为第一个是1; int f2 = 1;//后一个数,默认是1,因为第二个是1: int i = 1;//循环变量 for(;i <= 20;i++) { printf("%12d%12d\n",f1,f2); //一行显示两个数,每两个换一行 if(i % 2 == 0) { printf("\n"); } f1 = f1 + f2;//f1=2=1+1 f2 = f2 + f1;//f2=3=1+2 } return 0; }
5、直到型循环的实现
-
do...while
语法:
do
{
循环体;
}while(循环条件);
说明:
- 循环条件的返回值必须是boolean类型,在C语言中,布尔类型为真使用 非0 来表示,布尔类型为假使用 0 来表示;
- {} 包起来的内容整体称之为循环体;
- 我们要在循环体中控制循环条件的变化,否则会产生死循环
执行过程:
特点:
先执行,后判断,循环体语句至少要执行一次。
举例:求1-100之间奇数的累加和
/* 需求:do...while案例:求1-100之间奇数的累加和 */ #include <stdio.h> int main() { //创建一个变量,用来存储累加和 int sum = 0; //创建循环变量,默认值1 int i = 1; do { //判断i是否是奇数 if(i % 2 != 0) { sum += i; } i++;//改变循环变量的值 }while(i <= 100); printf("1-100之间奇数的累加和是:%d\n",sum); return 0; }
-
goto
语法:
goto 标签(label);
标签:
标明目标代码的位置,是一个不加""的字符串。
举例:求1-100之内的累加和
// 需求:求1~100之内的累加和 #include <stdio.h> int main() { int sum = 0; int i = 1; loop: // 自己定义的 标签 sum += i; i++; if(i <= 100) { goto loop; } printf("1~100之内的累加和是:%d\n",sum); return 0; }
注意:
goto只能在同一个函数中跳转,goto会破坏掉代码的结构,同时会降低代码可读性。在企业开发中, 不建议使用
6、循环的嵌套
3种循环(while、do…while、for)可以互相嵌套。在前一个循环结构的内部又存在一个完整的循环 结构,如:
举例:嵌套for循环案例_求100-200之间的所有素数
/** * 需求:嵌套for循环案例_求100-200之间的所有素数 */ #include <stdio.h> int main() { int num = 100;//存放100-200之间的自然数 int i = 2;//循环变量,默认从2开始,因为自然数除以1没有意义 102,100-102,102%100,102%101 int isPrime = 1;//用来记录1-自身之间能整除的次数 6,2-5,6%2,6%3,6%4,6%5 //第一层for循环:生成100-200之间的自然数 for(;num <= 200;num++) { //默认是素数 isPrime = 1; //第二层循环,生成2-自身-1的自然数,用于和自身校验,是否能够整除,如果有 一个能被整除,就说明不是素数 for(i = 2;i < num -1;i++) { if(num % i == 0) { isPrime = 0;//不是素数 } } if(isPrime)//条件判断:isPrime == 1 缩写 isPrime { printf("%d\n",num); } } printf("\n"); return 0; }
7、循环结构的典型应用场景
- 求累加和:举例 1+2+3+...+100的和;
- 求累乘:举例 1*2*3*...*100的积;
- 求均值:举例 (1+2+3+...+100) / 100的值;
- 求极值:举例 12,34,56,7,23中的最大值或最小值;
- 元素遍历:举例 常用于数组元素的遍历,比如:从数组[1,2,3,4,5]中获取每一个元素;
8、基础算法模型
-
累加和
- 定义一个变量(sum),并赋初值为0;
- 用该变量累加(+=)每一个数据项(i);
- 当访问完每一个数据项,此时该变量的取值就是累加和的结果。
-
累乘
- 定义一个变量,并赋初值为1;
- 用该变量累乘(*=)每一个数据项;
- 当访问完每一个数据项,此时该变量的取值就是累乘积的结果。
-
极值【知识点:数组】
- 定义一个变量,并赋初值为第一个数据项;
- 从第二个数据项开始,一次性与该变量进行比较,如果大于/小于该变量,则将当前数据项的数据赋值给该变量;
- 当访问完每一个数据项,此时该变量的取值就是求极值的结果。
9、break 和 continue
-
break
功能:
- 用在switch中,用来跳出switch的case语句;如果case没有break,可能会产生cse穿透;
- 用在循环中(while、do...while、for...),提前结束循环,也就是跳出整个循环。
说明:
- break不能用于循环语句和switch语句之外的任何其它语句之中;
- break只能终止并跳出最近一层的结构。
图示:
举例:(do...while)一阶段分段考试,考试及格时跳出循环
/** * 需求:break案例_xx参与一阶段分段考试,如果考试及格,就跳出循环,否则一直考 */ #include <stdio.h> int main() { printf("一阶段分段考试\n"); //声明一个变量,用来存放考试成绩 int score = 0; do { //int score = 78;//score的作用域只能作用在{}以内; printf("丽丽开始一阶段分段考试...\n"); scanf("%d",&score); //考试合格,结束循环 if(score >= 60) { break; } }while(1); printf("恭喜丽丽考试通过\n"); }
举例:(for...)输出1-100以内的偶数,只输出前10个
/** * 需求:break案例-输出1~100以内的偶数,只输出前10个 */ #include <stdio.h> int main() { for(int i = 1,count = 1;i <= 100;i++) { if(i % 2 == 0) { if(count > 10){ break; } count++;// 注意位置:只记录偶数 printf("%d\t",i); } } printf("\n"); return 0; }
-
continue
功能:
结束本次循环的执行,但不退出循环结构。即跳过循环体中下面尚未执行的语句,接着进行下一次是否执行循环的判定。
说明:
- 仅用于循环语句中;
- 在嵌套循环的情况下,continue语句只对包含它的最内层的循环体语句起作用。
图示:
举例:求1-100之内的偶数和
/** * 需求:continue案例-求1~100之内的偶数和 */ #include <stdio.h> // 不使用continue void fun01() { int sum = 0; for(int i = 1; i <= 100; i++) { // 判断偶数 if(i % 2 == 0) { sum += i; } } printf("1~100之内的偶数和是:%d\n",sum); } // 使用continue void fun02() { int sum = 0; for(int i = 1; i <= 100; i++) { // 判断奇数 if(i % 2 != 0) { continue;// 跳出所有的奇数 } sum += i; } printf("1~100之内的偶数和是:%d\n",sum); } int main() { fun01(); fun02(); }
-
跳出多层循环
跳出多层循环是不能使用break和continue的,因为他们只能跳出单层循环,跳出多层循环,需要 我们自己定义标志位进行跳出。
举例:
#include <stdio.h>
// 定义一个标志位
int isFlag = 1;// 默认循环成立
char fu;
while(isFlag)
{
printf("第一层循环执行的内容...\n");
while(isFlag)
{
printf("第二层循环执行的内容...\n");
printf("是否跳出循环?(y/n)");
scanf("%c",&fu);
if(fu == 'Y' || fu == 'y')
{
isFlag = 0;
}
}
}
注意:
如果是多层循环,进的时候是从外到内,跳出的时候是从内到外
10、消除回车函数
getchar();//消除回车 /*用于提示重复两遍出现时想消除一条提示*/
11、综合案例:猜拳游戏
/*
需求:猜拳游戏
步骤:
1. 选择对手
2. 自己出拳
3. 对手出拳
4. 双方比较
*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
int main()
{
// 管理变量
int isStop = 1;// 退出状态,默认是连续
char stop;// 退出游戏
int computer_no; // 玩家编号
char computer_name[6];// 玩家姓名 c语言不支持 char[6] computer_name 样的写法
int is_select_ct = 1;// 默认,选择对手操作是不重复的
int is_select_own = 1;// 默认,自己出拳操作是不重复的
int own_no; // 自己出拳的序号
char own_name[6];// 自己出拳的名称
int player_no;// 对手出拳的序号
char player_name[6];// 对手出拳的名称
// 游戏头部
printf("*******************************************\n");
printf("************ 猜拳游戏 v1.0版 **************\n");
printf("*******************************************\n");
while(isStop)
{
// 选择对手
while(is_select_ct)
{
printf("请选择您的对战玩家:\n[1].李白 [2].唐三 [3].萧炎\n");
scanf("%d",&computer_no);
switch(computer_no)
{
case 1:
// c语言中,对char数组直接赋值
strcpy(computer_name,"李白");
is_select_ct = 0;
break;
case 2:
strcpy(computer_name,"唐三");
is_select_ct = 0;
break;
case 3:
strcpy(computer_name,"萧炎");
is_select_ct = 0;
break;
default:
strcpy(computer_name,"无效玩家");
is_select_ct = 1;
}
printf("您选择的对手是:%s\n",computer_name);
}
// 自己出拳
while(is_select_own)
{
printf("\n请选择您出拳方式:\n[1].石头 [2].剪刀 [3].布\n");
scanf("%d",&own_no);
switch(own_no)
{
case 1:
// c语言中,对char数组直接赋值
strcpy(own_name,"石头");
is_select_own = 0;
break;
case 2:
strcpy(own_name,"剪刀");
is_select_own = 0;
break;
case 3:
strcpy(own_name,"布");
is_select_own = 0;
break;
default:
strcpy(own_name,"无效的出拳");
is_select_own = 1;
}
printf("您的出拳方式是:%s\n",own_name);
}
// 对手出拳(随机生成0~2)
srand((unsigned)time(NULL));// 以时间作为随机种子
// 随机生成对手出拳的序号(0~2)
player_no = rand()%3+1;
switch(player_no)
{
case 1:
// c语言中,对char数组直接赋值
strcpy(player_name,"石头");
break;
case 2:
strcpy(player_name,"剪刀");
break;
case 3:
strcpy(player_name,"布");
break;
}
printf("\n%s的出拳方式是:%s\n",computer_name,player_name);
// 双方比较
if((own_no == 1 && player_no == 2)||(own_no == 2 && player_no == 3)||(own_no == 3 && player_no == 1))
{
printf("\n恭喜,您获胜!\n");
}
else if(own_no == player_no){
printf("\n平局!\n");
}
else
{
printf("\n很遗憾,您输了!\n");
}
// 退出游戏
printf("\n是否退出游戏?[Y/N]\n");
getchar();// 消除回车
scanf("%c",&stop);
if(stop == 'Y' || stop == 'y')
{
is_select_ct = 0;// 默认,选择对手操作是不重复的
is_select_own = 0;// 默认,自己出拳操作是不重复的
isStop = 0;
printf("\n游戏结束!\n");
}
else
{
// 还原状态
is_select_ct = 1;// 默认,选择对手操作是不重复的
is_select_own = 1;// 默认,自己出拳操作是不重复的
isStop = 1;
}
}
return 0;
}
二、补充
- 什么是素数?
素数也被称作质数,只能被1和自身整除的数就叫做素数。
三、作业
上机题
-
计算n以内所有正奇数的和 ? n值通过键盘输入
代码:
/* 输入n值,计算1-n以内所有正奇数的累加和 */ #include <stdio.h> int main() { int sum = 0;//累加和 int i = 0;//循环变量 int n; printf("请输入一个整数:%d\n",n); scanf("%d",&n); do { if(i % 2 != 0)//奇数 { sum += i; } i++; }while(i <= n); printf("1-n之间所有正奇数的累加和是:%d\n",sum); return 0; }
运行效果:
-
计算 1 + 1/(2 * 3) + 1/(3 * 4) + ...+ 1/(n * (n + 1)) = ?直到最后一相值小于0.00001为止
代码:
/* 计算1+1/(2*3)+1/(3*4)+...+1/(n*(n+1))=?直到最后一项的值小于0.00001为止 */ #include <stdio.h> #include <math.h> int main() { int n = 2; //int n2 = 3; double sum = 1; double y; // double y = 1 / (n * (n + 1)); // int sum += y; // double sum1 = sum + 1; do { y = 1.0/(n*(n+1)); // n++; // sum += y; if(y < 1.0e-5) { break; } sum += y; n++; }while(1); printf("此时计算式的值为:%lf\n",sum); return 0; }
运行效果:
-
计算1+1/2 - 1/3 + 1/4 - 1/5 ...+1/n= ? n通过键盘输入
代码:
/* 计算1+1/2-1/3+1/4-1/5+...+1/n=?,n通过键盘输入; */ #include <stdio.h> int main() { double sum = 1;//保存累加和 double b = 1;//分子 // double sum2=0;//偶数项和奇数项 int a = 2;//分母 int n;//输入的整数 // double i = (1/a);//单个分式 //输入整数 printf("请输入一个整数:%d\n",n); scanf("%d",&n); while(a <= n) { sum += b/a; a = a+1; b = -b; } printf("表达式的值为:%.2lf\n",sum); //sum = sum1 - sum2; // printf("表达式的值为:%.2lf=%.2lf-%.2lf\n",sum,sum1,sum2); return 0; }
运行效果:
-
计算n的阶乘 ? n! = 123.....*n n值通过键盘输入
代码:
/* 计算n的阶乘?n! = 123...*n n值通过键盘键入; */ #include <stdio.h> int main() { int n;//键盘输入n值 int pro = 1;//阶乘值 printf("请输入您要计算的阶乘值:%d\n",n); scanf("%d",&n); for(int a = 1;a <= n;a++) { pro *= a; } printf("您所计算的阶乘值为:%d\n",pro); return 0; }
运行效果:
-
输出半径为1~10的圆面积,面积大于100时停止
代码:
/* 输出半径为1-10的圆面积,面积大于100时停止; */ #include <stdio.h> #define PI 3.1415926 int main() { int r;//半径 double s;//圆面积 for(r = 1;r >= 1 && r <= 10;r++) { s = PI * (r * r);//面积 printf("\n当r=%d时,s=%.2lf\n",r,s); if(s > 100) { break; } } //printf("当r=%d时,s=%.2lf",r,s); return 0; }
运行效果:
-
求输入的十个整数中正数的个数及其平均值
代码:
/* 求输入的十个整数中正数的个数及其平均值; */ #include <stdio.h> int main() { int a,b=0,c=0,sum;//总数,累加和,个数,和 printf("请随意输入十个整数:\n"); // scanf("%d",&a); for(a = 0;a <= 10;a++) { scanf("%d",&sum); if(sum > 0) { b += sum;//整数累加和 c++;//个数 } } printf("在您输入的十个整数中,有%d个正数,且平均值为%d\n",c,b/c); return 0; }
运行效果:
-
打印出100以内能整除7之外的的自然数
代码:
/* 打印出100以内的能够整除7之外的自然数 */ #include <stdio.h> int main() { int i; for(i = 1;i <= 100;i++) { if(i % 7 == 0) { printf("%d\n",i); } } printf("\n"); return 0; }
运行效果:
-
打印乘法表
代码:
/** * 嵌套循环案例:九九乘法表 */ #include <stdio.h> int main() { // 分析 // 九九乘法表本质上行列构成三角形 // 九九乘法表 总共9行 // 九九乘法表 列受到行的影响:列数 <= 行数 // 如果涉及到行列,我们首选双重嵌套for循环,外层循环控制行数,内层循环控制列数 // 外层循环控制行:9行 for(int i = 1;i <= 9;i++) { // 内层循环控制列:列 <= 当前行 for(int j = 1;j <= i;j++) { // 生成当前行中的所有乘法序列 printf("%d×%d=%d\t",j,i,i*j); } // 一行中所有列输出完毕,需要换行 printf("\n"); } printf("\n"); return 0; }
运行效果:
-
我国古代数学家张丘建在《算经》一书中提出的数学问题:鸡翁一值钱五,鸡母一值钱三,鸡雏三 值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?
代码:
/** 我国古代数学家张丘建在《算经》一书中提出的数学问题: 鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、>鸡母、鸡雏各几何? **/ #include <stdio.h> int main(void) { int x,y,z;//鸡翁x只,鸡母y只,鸡雏z只 for(x = 1;x <= 20;x++)//百钱最多买20只鸡翁 { for(y = 1;y <= 33;y++)//百钱最多买33只鸡母 { for(z = 3;z <= 300;z+=3)//百钱最多买300只鸡雏 { if((x + y + z)==100 && (5 * x + 3 * y + z / 3 == 100)) { printf("鸡翁有%d只,鸡母有%d只,鸡雏有%d只\n",x,y,z); } } } } return 0; }
运行效果:
-
从键盘上输入多个无符号整型数据,直到 0 结束 ,输出所输入数据中的最大值
代码:
/* 键盘上输入多个无符号整型数据,直到0结束,输出所输入数据中的最大>值; */ #include <stdio.h> int main() { unsigned int i,max; printf("请输入任意几个无符号整型数据:"); scanf("%d",&i); max = i; while(i != 0) { if(max < i) { max = i; } scanf("%d",&i); } printf("输入数据中的最大值为:%d\n",max); return 0; }
运行效果:
思考题
-
判断一个数是不是回文数。(回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整 数。如:12321