第六章 循环控制结构
1.循环:包括计数控制的循环和条件控制的循环
2.结构化程序设计的三种基本结构:顺序结构、选择结构、循环结构
3.循环结构的类型:
1)当型循环结构:for语句(适合循环次数已知,计数控制的循环)
2)直到型循环结构:while语句、do-while语句(适合循环次数未知,条件控制的循环)
4.while语句
1)一般形式为:
while(循环控制表达式)
{ |
语句系列 |循环体
} |
2)循环控制表达式在执行循环体之前测试
3)执行过程:
计算循环控制表达式的值
如果循环控制表达式的值为真,那么执行循环体中的语句,并返回步骤1
如果循环控制表达式的值为假,就退出循环,执行循环体后面的语句
5.do-while语句
1)一般形式为:
do
{ |
语句系列 |循环体
}while(循环控制表达式);
2)循环控制表达式在执行循环体之后测试
3)执行过程:
执行循环体中的语句
计算循环控制表达式的值
如果循环控制表达式的值为真,那么返回步骤1
如果循环控制表达式的值为假,就退出循环,执行循环体后面的语句
6.for语句
1)一般形式为:
for(初始化表达式;循环控制表达式;增值表达式)
{ |
语句系列 |循环体
} |
2) 在每次循环体被执行之前,都要对循环控制条件测试一次,每次循环体执行完以后都要执行一次增值表达式
3)初始化表达式作用:循环变量初始化,即赋初值
4)循环控制表达式:是控制继续执行的条件,当表达式的值为非0时重复执行循环
5)增值表达式作用:每执行一次循环,循环控制变量增值
6)for语句三个表达式之间用分号分隔,有且只能有两个分号
7)循环控制表达式若省略,表示循环条件为永真
8)初始化表达式和增值表达式都可省略,但是必须有其他语句反应其作用
7.例:从键盘输入n,然后计算输出1+2+3+……n的值
1)while语句编程实现
#include<stdio.h>
void main()
{
int i=1,n,sum=0;//sum一定要初始化,不然会是随机值
printf("Enter n:");
scanf("%d",&n);
while(i<=n)
{
sum+=i;
i++;
}
printf("1+2+3+……+%d=%d\n",n,sum);
}
2)do-while语句编程实现
#include<stdio.h>
void main()
{
int i=0,n,sum=0;
printf("Enter n:");
scanf("%d",&n);
do
{
sum+=i;
i++;
}while(i<=n);
printf("1+2+3+……+%d=%d\n",n,sum);
}
3)for语句编程实现
#include<stdio.h>
void main()
{
int i=1,n,sum=0;
printf("Enter n:");
scanf("%d",&n);
for(i=1;i<=n;i++)
{
sum+=i;
}
printf("1+2+3+……+%d=%d\n",n,sum);
}
8.逗号运算符
1)所有运算符中优先级最低,左结合
2)作用:可实现对各个表达式的顺序求值
3)结果:将最后一个表达式的值作为整个逗号表达式的值
4)例:从键盘输入n,然后计算输出1+2+3+……n的值
#include<stdio.h>
void main()
{
int i,j,n,sum=0;
printf("Enter n:");
scanf("%d",&n);
for(i=1,j=n;i<=j;i++,j--)
{
sum+=i+j;
}
printf("1+2+3+……+%d=%d\n",n,sum);
}
9.空语句
1)仅由一个分号构成的语句
2)作用:什么也不做,只起延时作用
3)例:for(i=1;i<50000000;i++)
{
;
}
或for(i=1;i<50000000;i++)
{
}
或for(i=1;i<50000000;i++);
for(i=1;i<=n;i++);
{
sum+=i;
}
等价于
for(i=1;i<=n;i++)
{
;
}
sum+=i;
4) 例:从键盘输入n,然后计算输出1+2+3+……n的值
#include<stdio.h>
void main()
{
int i,j,n,sum=0;
printf("Enter n:");
scanf("%d",&n);
for(i=1,j=n;i<=j;i++,j--);
{
sum+=i+j;
}
printf("1+2+3+……+%d=%d\n",n,sum);
}//输出结果:101
10.死循环
1)while语句行末加分号将导致死循环
2)例:i=1;
while(i<=n);//行末加分号导致死循环
{
sum+=i;
i++;
}
相当于
i=1;
while(i<=n)//当输入大于1的n值,循环体中没有语句可以改变控制变量i
{ //使得循环条件为永真,导致死循环
;
}
sum+=i;
i++;
11.while语句和do-while语句的区别
1)while先判断后执行,有可能一次都不执行,do-while先执行后判断,至少执行一次
2)例:n=101; n=101;
while(n<100) do
{ {
printf("n=%d\n",n); printf("n=%d\n",n);
n++; n++;
} }while(n<100);
//循环一次也不执行 //结果:输出n=101,循环执行一次
3)例:分别用while和do-while语句编程,输入一组数据,然后显示每次输入数据进行累加运算的结果,输入0结束
do-while语句实现:
#include<stdio.h>
void main()
{
int num,sum=0;
do{
printf("Enter num:");
scanf("%d",&num);
sum+=num;
printf("sum=%d\n",sum);
}while(num!=0);
}
while语句实现
#include<stdio.h>
void main()
{
int num=1,sum=0;//给num赋任意非0值都可以
while(num!=0)
{
printf("Enter num:");
scanf("%d",&num);
sum+=num;
printf("sum=%d\n",sum);
}
}
12.计数控制的循环:循环次数事先已知的循环
1)例1:编写一个程序,从键盘输入n,计算输出n!
#include<stdio.h>
void main()
{
int i,n,sum=1;
printf("Enter n:");
scanf("%d",&n);
for(i=1;i<=n;i++)
{
sum*=i;
}
printf("%d!=%ld\n",n,sum);
}
2)例2:编写一个程序,从键盘输入n,计算输出1!,2!……n!
#include<stdio.h>
void main()
{
int i,n,sum=1;
printf("Enter n:");
scanf("%d",&n);
for(i=1;i<=n;i++)
{
sum*=i;
printf("%2d!=%ld\n",i,sum);
}
}
3)例:键盘输入n,编程计算1!+2!+3!+……+n!
#include<stdio.h>
void main()
{
int term=1,sum=0,i,n;
printf("Enter n:");
scanf("%d",&n);
for(i=1;i<=n;i++)
{
term*=i;
sum+=term;
}
printf("1!+2!+3!+……+%d!=%ld\n",n,sum);
}
13.条件控制的循环:循环次数事先未知,由条件控制
1)例1:输入两个整型数,计算并输出两个整型数的最大值,如若输入非法字符,提示错误并重新输入
//解释:非法字符,需要输入数字时,字符相对它来说就是非法字符,而需要输入字符型,数字对它不是非法字符,所有都是合法
#include<stdio.h>
void main()
{
int a,b,max,ret;
printf("Enter a,b:");
ret=scanf("%d %d",&a,&b);
while(ret!=2)//判断数据个数或格式是否错误
{
while(getchar()!='\n');//清除缓冲区中的错误数据
printf("Enter a,b:");
ret=scanf("%d %d",&a,&b);
}
max=a>b?a:b;
printf("max=%d\n",max);
}
//注意:scanf()函数不做参数类型匹配检查,当输入1 3.2时,scanf返回2,不会导致重新输入
但是,此后的小数点仍留在缓冲区,如果此后还需输入内容,就要先清除缓冲区内容
2)例2:先由计算机想一个1-100之间的数请人猜,若猜对,则计算机提示Right!结束
游戏,否则提示Wrong!,并告诉人是大是小,直到猜对为止,记录人猜的次数,反应猜数的水平
#include<stdio.h>
#include<stdlib.h>
void main()
{
int magic;
int guess;
int counter=0;
magic=rand()%100+1;
do{
printf("Please guess a magic number:");
scanf("%d",&guess);
counter++;
if(guess>magic)
{
printf("Wrong!Too big!\n");
}
else if(guess<magic)
{
printf("Wrong!Too small!\n");
}
else{
printf("Right!\n");
}
}while(guess!=magic);
printf("counter=%d\n",counter);
}
14.随机数的使用
a.随机数的产生: rand()
1) 符号常量RAND_MAX在头文件#include<stdlib.h>中定义,标准C规定RAND_MAX不大于双字节整数的最大值32767
2)随机函数rand()产生的是一个在0~RAND_MAX之间的整数,即[0,32767]之间的整数
3) 利用求余运算rand()%b可将函数rand()生成的随机数变化到[0,b-1]
4) 利用rand()%b+a可将随机数的取值范围平移到[a,a+b-1]
b.随机数的产生: srand(time(NULL))
1)用rand()直接产生的随机数只是一个伪随机数,反复调用产生的随机数序列是一样的,而且每次都只用第一个
2)随机化:使程序每次运行时产生不同的随机数序列的过程
3)随机化的实现:通过调用标准库函数srand()为函数rand()设置随机数种子来实现
4)随机数种子的设置:
法1:每次通过用户输入来完成随机化,srand(1),srand(2),srand(seed),输入seed
法2:的通过函数time()读取计算机的时钟值,并把该值设置为随机数种子srand(time(NULL))
5)函数time()返回以秒计算的当前时间值,即一个代表时间的字符串,使用NULL作为time()的参数时,
time(NULL)的返回值被转换成一个无符号整数,可作为随机数发生器的种子
6)使用time()函数时,必须在程序开头将头文件<time.h>包含到程序中
15.例:先由计算机想一个1-100之间的数请人猜,若猜对,则计算机提示Right!结束
游戏,否则提示Wrong!,并告诉人是大是小,直到猜对为止,记录人猜的次数,反应猜数的水平
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void main()
{
int magic;
int guess;
int counter=0;
srand(time(NULL));
magic=rand()%100+1;
do{
printf("Please guess a magic number:");
scanf("%d",&guess);
counter++;
if(guess>magic)
{
printf("Wrong!Too big!\n");
}
else if(guess<magic)
{
printf("Wrong!Too small!\n");
}
else{
printf("Right!\n");
}
}while(guess!=magic);
printf("counter=%d\n",counter);
}
16.例:先由计算机想一个1-100之间的数请人猜,若猜对,则计算机提示Right!屏幕输出多少次成功,
结束游戏,否则提示Wrong!,并告诉人是大是小,最多猜10次,超过就结束,要避免非法字符的输入
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void main()
{
int magic;
int guess;
int counter=0;
int ret;//保存scanf()函数的返回值
srand(time(NULL));
magic=rand()%100+1;
do{
printf("Please guess a magic number:");
ret=scanf("%d",&guess);
while(ret!=1)//若存在输入错误,则重新输入
{
while(getchar()!='\n');//清楚缓冲区中的内容
printf("Please guess a magic number:");
ret=scanf("%d",&guess);
} //若存在非法字符,则重新输入
counter++;
if(guess>magic)
{
printf("Wrong!Too big!\n");
}
else if(guess<magic)
{
printf("Wrong!Too small!\n");
}
else{
printf("Right!\n");
}
}while(guess!=magic&&counter<10);
printf("counter=%d\n",counter);
}
延伸拓展:先由计算机想一个1-100之间的数请人猜,若猜对,则计算机提示Right!屏幕输出多少次成功,
结束游戏,否则提示Wrong!,并告诉人是大是小,最多猜10次,超过就继续猜下一个数,每次运行程序,可
反复猜多个数,直到操作者想停时结束,要注意避免非法字符输入的问题
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void main()
{
int magic;
int guess;
int counter;
char reply;//保存用户输入的答案
int ret;//保存scanf()函数的返回值
srand(time(NULL));
do{
magic=rand()%100+1;
counter=0;
do{
printf("Please guess a magic number:");
ret=scanf("%d",&guess);
while(ret!=1)//若存在输入错误,则重新输入
{
while(getchar()!='\n');//清楚缓冲区中的内容
printf("Please guess a magic number:");
ret=scanf("%d",&guess);
} //若存在非法字符,则重新输入
counter++;
if(guess>magic)
{
printf("Wrong!Too big!\n");
}
else if(guess<magic)
{
printf("Wrong!Too small!\n");
}
else{
printf("Right!\n");
}
}while(guess!=magic&&counter<10);
printf("counter=%d\n",counter);
printf("Do you want to continue(Y/N or y/n)?");
scanf(" %c",&reply);//%c前有一个空格,读取缓冲区中的回车符
}while(reply=='Y'||reply=='y');
}
17.设计一个简单计算器,允许连续做多次算术运算
#include<stdio.h>
#include<math.h>
void main()
{
float data1,data2;
char op;
char reply;
do{
printf("Please enter your expression:\n");
scanf("%f %c%f",&data1,&op,&data2);//加空格可在操作数和运算符之间加任意多个空白符
switch(op)
{
case '+':
printf("%f+%f=%f\n",data1,data2,data1+data2);
break;
case '-':
printf("%f-%f=%f\n",data1,data2,data1-data2);
break;
case '*':
case 'X':
case 'x':
printf("%f*%f=%f\n",data1,data2,data1*data2);
break;
case '/':
if(fabs(data2)<=1e-7)
{
printf("Division by zero!\n");
}
else{
printf("%f/%f=%f\n",data1,data2,data1/data2);
}
break;
default:
printf("Invalid operator!\n");
}
printf("Do you want to continue(Y/y or N/n)?");
scanf(" %c",&reply);//加空格清除缓冲区中的回车符
}
while(reply=='Y'||reply=='y');
}
18.嵌套循环
一个循环语句放在另一个循环语句中构成的循环称为嵌套循环
1) 嵌套循环的总循环次数等于外层循环次数和内层循环次数的乘积
2)为避免造成混乱,嵌套循环的内层和外层的循环控制变量不要同名
3)例:键盘输入n,编程计算1!+2!+3!+……+n!
#include<stdio.h>
void main()
{
int term,sum=0,i,j,n;
printf("Enter n:");
scanf("%d",&n);
for(i=1;i<=n;i++)
{
term=1;
for(j=1;j<=i;j++)
{
term*=j;
}
sum+=term;
}
printf("1!+2!+3!+……+%d!=%ld\n",n,sum);
}
19累加求和构成规律:
1)当累加项较为复杂或者前后项之间无关时,需要单独计算每个累加项
2)当累加项前项与后项之间有关时,根据前项计算后项
#include<stdio.h>
void main()
{
int i,n;
long term=1,sum=0;
printf("Enter n:");
scanf("%d",&n);
for(i=1;i<=n;i++)
{
term=term*i;
sum=sum+term;
}
printf("1!+2!+3!+……%d=%ld\n",n,sum);
}
20.goto语句
1)功能:使程序无条件跳转到语句标号所标识的语句去执行,所跳过的语句不再执行
2)一般形式:
①向前跳转 ②向后跳转
goto 语句标号; 语句标号:……(后)
…… ……
语句标号:…… (前) goto 语句标号;
3)应用:通常情况,goto语句与if语句联合使用
if(表达式) goto语句标号; 语句标号:……
…… ……
语句标号:…… if(表达式) goto语句标号;
21.break语句
1)功能:①用于退出switch结构
②用于退出由while,do-while和for语句构成的循环体
2)原理:当执行循环体遇到break语句时,循环体将立即终止,从循环语句后的第一条语句开始继续执行
3)应用:break语句通常与if联合使用,表明在任何条件下跳转到紧接循环语句后的第一条语句
22.continue语句
1)功能:跳过continue后面尚未执行的语句,开始下一次循环,只结束本次循环,不终止整个循环
2)例题:
#include<stdio.h>
void main()
{
int i,n;
for(i=1;i<=5;i++)
{
printf("Please enter n:");
scanf("%d",&n);
if(n<0) continue;
printf("n=%d\n",n);
}
printf("Program is over!\n");
}
23.函数exit()
1) 标准库函数exit()用于控制程序的流程,调用时,需要加头文件<stdlib.h>
2)一般形式:exit(code);
3)功能:终止整个程序的执行,强制返回操作系统,并将int型参数code的值传给调用进程
(一般为操作系统),当code的值为0或宏常量EXIT_FAILURE,表示程序出现某种错误后退出
24.goto,break,continue,exit()的比较
1)goto,break,continue,exit()都用于控制程序的流程,前三个是流程控制语言,exit()是C标准函数
1)功能:goto语句可以向任意方向跳转,break语句只限定流程跳转到循环语句之后
的第一条语句,continue语句结束本次循环,exit()直接终止所有程序
2)break,goto语句和exit()函数都可用于终止整个循环的执行,continue不能终止整个循环
3)在嵌套循环下,break语句和continue语句只对包含他们的最内层循环语句起作用,
不能用break语句跳出多重循环,只能一层一层的跳出
4)使用goto语句的两种特定情形:
①快速跳出多重循环
②跳向共同的出口位置,进行退出前的错误处理工作
25.例题:韩信点兵:x%5==1&&x%6==5&&x%7==4&&x%11==10
①穷举法(循环条件自定义,不具实际意义)
②break退出循环(循环条件省略,满足条件结束循环)
③exit(0)结束程序(循环条件省略,满足条件结束整个程序)
④使用标志变量(循环条件为标识变量为0,最佳方法)
#include<stdio.h>
void main()
{
int x;
int find=0;
for(x=1;!find;x++)
{
if(x%5==1&&x%6==5&&x%7==4&&x%11==10)
{
printf("x=%d\n",x);
find=1;
}
}
}
26.类型溢出
1)原因:当运算的结果超出了类型所能表示的数的上界,导致进位到达了最前面的符号
位或者更多进位的丢失,就会发生类型溢出
2)解决办法:采用取值范围更大的数据类型来定义变量
27.结构化程序设计的基本思想
1)采用顺序、选择和循环三种基本结构作为程序设计的基本单元,语法结构具有4个特性
①只有一个入口
②只有一个出口
③无不可达语句,即不存在永远执行不到的语句
④无死循环,即不存在永远都执行不完的循环
2)尽量避免使用goto语句,因为它破坏了结构化设计风格,并且容易带来错误的隐患
3)采用自顶向下、逐步求精的模块化程序设计方法进行结构化程序设计