我的C语言学习记录(蓝桥)————五
循环程序设计
循环结构、顺序结构和选择结构是结构化程序设计的 3 种基本结构,它们是包含各种复杂程序的基本构成单元。例如在日常生活中或是在程序所处理的问题中常常遇到需要重复处理的问题:
- 计算 1+2+3......+100 的和 (重复相同的加法操作)
- 统计班级里面所有学生考试成绩在 80 分以上的人 (重复判别操作)
- 计算全班 50 个人的考试平均成绩 (重复的计算操作)
按照我们之前学到的知识,如果计算全班 50 个人的平均成绩,我们会先编写求一个人的平均成绩段。
scanf("%f%f%f%f",&score1,&score2,&score3,&score4); //输入一个学生4门课程的成绩
aver = (score1 + score2 + score3 + score4) / 4; //求该学生的平均成绩
printf("aver=%7.2f",aver); //输出该学生平均成绩
然后再重复写 49 个同样的程序段。这种方法虽然可以实现要求,但是显然不可取的,因为这样工作量大、程序冗长,难以阅读,这是编程中最笨的方法。 在 C 语言中我们可以采取这样的循环语句来处理上述问题:
i=1;
while(i<=50){
scanf("%f%f%f%f",&score1,&score2,&score3,&score4); //输入第i个学生4门课程的成绩
aver = (score1 + score2 + score3 + score4) / 4; //求第i个学生的平均成绩
printf("aver=%7.2f",aver); //输出第 i 个学生的平均成绩
i++; //每执行完一次循环使i的值加 1,直到 i<=50 不成立跳出循环。
}
接下来,我们将通过例子,来熟悉 C 语言的几种不同的循环结构。
用 while 语句实现循环
while
循环的循环特点是先判断表达式后执行循环体语句。 一般语法如下:
while(expression)
statement1;
statement2;
statement1
和 statement2
既可以是单个语句也可以是语法块,其语法结构如下:
我们通过一个例子来学习怎样利用 while 语句进行循环程序设计,求 1+2+3+4+5+6......+100。
这是我们从小学到初中经常看到的一个练习题,我们会用很多简便方法去计算,而对于计算机我们可能需要用最笨的方法计算了。
- 作为一个累加问题,需要重复进行 100 次的加法运算,显然可以用循环结构来实现,重复执行循环体 100 次,每次加一个数。
- 我们会发现每次累加的数是有规律的,后一个数是前一个数加 1,因此不需要每次通过用 scanf 语句从键盘临时输入数据,只需要再加完一个数 i 后,使 i 加 1 就可得到下一个数。
编写源程序 7-1.c:
#include<stdio.h>
int main(){
int i = 1,sum = 0;
while(i<=100)
{
sum = sum + i;
i++;
}
printf("sum=%d\n",sum);
return 0;
}
输入以下命令编译并运行:
gcc -o 7-1 7-1.c
./7-1
运行结果如下:
循环体如果包含一个以上的语句,应该用花括号括起来,作为复合语句出现。如果不加花括号,则 while 语句的范围只到 while 后面第一个分号处。如本例中的 while 语句如果无花括号,则 while 语句范围只到 sum=sum+i;。
用 do...while 语句实现循环
while 循环体是先判断再循环,而 do...while 语句是先循环后判断。 do...while 语句的一般形式如下:
do
statement;
while(expression);
statement 就是循环体。
注意:和 while 语句不同, do...while 语句中的 while(); 后面是有 “;” 的。
我们这次用 do...while 来实现 1 到 100 的累加。
编写源程序 7-2.c:
#include<stdio.h>
int main(){
int i = 1,sum = 0;
do{
sum = sum + i;
i++;
}while(i<=100);
printf("sum=%d\n",sum);
return 0;
}
运行结果如下:
通过 7-1.c 和 7-2.c 可以看到,对同一个问题可以用 while 语句处理,也可以用 do...while 语句处理。 do...while 语句结构可以转换成 while 结构,很多情况两者是等价的。但是如果 while 后面的表达式一开始为假的时候,两者循环结构是不同的。
我们举例说明 while 和 do...while 循环的比较。
用 while 循环编写源程序 7-3.c:
#include<stdio.h>
int main(){
int i,sum = 0;
printf("please enter i:");
scanf("%d",&i);
while(i<=100)
{
sum = sum + i;
i++;
}
printf("sum=%d\n",sum);
return 0;
}
用 do...while 循环编写源程序 7-4.c:
#include<stdio.h>
int main(){
int i,sum = 0;
printf("please enter i:");
scanf("%d",&i);
do
{
sum = sum + i;
i++;
}while(i<=100);
printf("sum=%d\n",sum);
return 0;
}
每个程序运行两次,结果如下:
我们可以得到以下结论:当 while 后面的表达式的第一次值为“真”时,两种循环得到的结果是相同的;否则,二者结果不相同。
用 for 语句实现循环
除了可以用 while 语句和 do...while 语句实现循环外。C 语言还提供 for 语句实现循环,for 语言十分灵活,很多情况下他完全可以替代 while 语句。
for 语句的一般形式如下:
for(表达式 1;表达式 2;表达式 3) 语句
3 个表达式的作用如下:
- 表达式 1:设置初始条件,只执行一次。可以为零个、一个或者多个表达式赋初值。
- 表达式 2:是循环条件表达式,用来判定是否继续循环。在每次执行循环体前先执行此表达式,决定是否继续执行循环。
- 表达式 3:作为循环的调整,例如循环变量的增值,是在执行完循环体后才进行的。
我们依然用 1 到 100 的和这个计算题来理解 for 语句。
编写源程序 7-5.c:
#include<stdio.h>
int main(){
int i,sum = 0;
for(i=1;i<=100;i++)
sum = sum + i;
printf("sum=%d\n",sum);
return 0;
}
运行结果如下:
for 语句的执行过程如下:
- 先求解表达式 1。本例中的表达式 1 就是 i=1,即把整数 1 赋值给 i。
- 求解表达式 2。若此条件表达式的值为真(非 0),则执行 for 语句的循环体,然后执行第三步。若为假(0),则结束循环,转到第(5)步。
- 求解表达式 3。在本例中,执行 i++,使 i 的值加 1,i 的值变成 2。
- 转回步骤 2 继续执行。 由于此时 i=2,表达式 i<=100 的值为真,再次执行循环体中的语句。然后再执行步骤(3)。如此反复,直到 i 的值变到了 101,此时表达式 i<=100 的值为假,不再执行循环体,而转到步骤(5)。
- 循环结束,执行 for 语句下面的一个语句。
上面的 for 语句:
for(i=1;i<=100;i++)
sum = sum + i;
其执行过程和下面语句相当:
i = 1;
while(i<=100){
sum = sum + i;
i++;
}
显然用 for 语句更简单、方便。
关于 for 语句的一些说明:
- for 语句的一般形式:
for(表达式 1;表达式 2;表达式 3)语句
可以改写成为 while 循环的形式:
表达式 1;
while (表达式 2)
{
语句
表达式 3
}
两者是无条件等价的。
- 表达式 1 可以省略,即为不初值。但是表达式 1 后面的分号不能省略。例如:
- i = 1;
- for(;i<=100;i++)
- sum = sum + i;
- 表达式 2 也可以省略。代码如下:
- for(i=1;;i++)
- sum = sum + i;
此时循环将会无终止的进行下去,默认为表达式 2 是真。
- 表达式 3 也可以省略,代码如下:
- for(i=1;i<=100;)
- {
- sum = sum + i;
- i++;
- }
i++操作不放在表达式 3 原本的位置,放到循环体中效果是一样的。
通过以上介绍,我们知道了 C 语言的 for 循环语句变化多端,十分灵活。但是我们应该注意的是不要过分利用这一特点,这样会使的 for 语句显得杂乱,可读性差。
改变循环的执行状态
我们上一章节在 switch
语句中使用过 break
语句。它的作用是终止 switch
块中代码的执行,并继续执行跟在switch
后的第一行语句。break
语句在循环体内的作用和 switch
基本相同。
例:某电商网站某天做促销活动,当天新注册的用户(1000 人)购物全部 9 折,当新注册用户购买商品总金额超过 10 万,停止活动。统计此时购物的新注册用户人数以及平均每人购物的金额。
for
语句本来循环 1000 次。在每一次循环中,输入一个新注册用户的购买金额,然后把它累加到 total 中,如果没有 if
语句,则执行循环体 1000 次。现在设置一个 if 语句,在每一次累加了购买金额 amount 后,立即检查累加和 total 是否达到或者超过 SUM ,当 total>=100000
时,就执行 break 语句,流程跳转到循环体的花括号外,即不再继续执行其余的几次循环,提前结束循环。此时的 i 是什么呢?是已经购买商品的新注册用户。
实现中的核心代码如下:
for (i=0; i < 1000; i++) {
// 初始化购买金额
int money = 0;
// 输入新的购买金额
scanf("%d", &money);
// 增加到总金额里
total += money;
// 判断是否达到停止活动条件
if (total > 100000)
break;
}
continue
语句与 break
语句不同,并不停止循环,而是跳出当前循环的状态继续执行下一轮的循环。求取 100-200 之间所有不可以被 3 整除的数,并打印出来。实现过程中凡是遇到可以被 3 整除的数则跳过循环内的后面所有的代码,继续执行下一轮循环。
编写源程序 7-6.c
#include<stdio.h>
int main(){
int n;
for(n=100;n<=200;n++){
if(n%3==0)
continue;
printf("%d\t",n); //\t表示相当与Tap键,留空位
}
printf("\n");
return 0;
}
运行结果如下:
continue
的作用为结束本次循环,就是跳过循环体中下面尚未执行的语句,然后接着下一次的循环操作。 continue
语句是结束本次循环,而不是终止整个循环的执行。而 break
语句则是结束整个循环过程,不在判断执行循环的条件是否成立。
循环的嵌套
我们可以使用嵌套来处理此问题,用内循环来输出一行数据,用外循环来输出一列数据。要注意设法输出以上矩阵的格式(每行 5 个数据),即每输出完 5 个数据后换行。
编写源程序 7-7.c:
#include<stdio.h>
int main(){
int i,j,n=0;
for(i=1;i<=4;i++)
for(j=1;j<=5;j++,n++){
if(n%5==0) printf("\n");
printf("%d\t",i*j);
}
printf("\n");
return 0;
}
代码 for(j=1;j<=5;j++,n++)
中的 j++,n++
是一个逗号表达式。在这里,我们不关心表达式的值(感兴趣的同学可以自己下来查阅资料)。我们关心的是这个表达式怎么执行,它的流程非常简单:它先执行 j++
(等同于 j=j+1
再执行 n++
(等同于 n=n+1
),这里我们可以就看作是 j
和 n
都步进 1,与之前只有一个变量做步进操作是一样的。
运行结果如下:
该程序包含一个双重循环,是 for
循环的嵌套。外循环变量 i 由 1 变到 4,用来控制输出的 4 行数据,内循环变量 j 由 1 变到 5,用来控制输出中的 5 个数据。输出的值是 i*j。在执行第 1 次外循环体时,i=1,j 由 1 变到 5,因此 i*j 就是 1,2,3,4,5。在执行第二次外循环时,i=2,j 由 1 变到 5,因此 i*j 的值就是 2,4,6,8,10。以此类推。
作业:
输出下面图案: 提示:找到跳出循环的判断条件是关键。
*
***
*****
*******
*****
***
*
解:
#include<stdio.h>
int main(){
int i,j;
//正金字
for (i=1;i<=4;i++){ // 控制金字塔的层数,输出4层,可以改变输出任意层
for (j=1;j<=4-i;j++) // 控制金字塔每层前面输出的空格数
printf(" ");
for (j=1;j<=2*i-1;j++) // 控制金字塔每层需要打印'*'的个数
printf("*");
printf("\n"); // 一层金字塔输出完毕,换行继续输出下一层
}
//倒金字
for(i=3;i>0;i--){ // 控制金字塔的层数,输出3层,可以改变输出任意层
for(j=1;j<=4-i;j++)
printf(" ");
for (j=1;j<=2*i-1;j++)
printf("*");
printf("\n");
}
return 0;
}
挑战:
序列求和
介绍
实现一个 C 语言程序,可以读入若干个整数,然后计算出读入的整数的和并输出。
知识点
- Linux 下 C 语言程序编写
- C 语言基础
- C 程序参数输入与处理
- scanf 和 printf 函数
- C 语言循环
注意输入的序列数字要做为编译后的可执行文件的参数传入,而不是 scanf() 读取,如果使用 scanf() 读取则会导致测试系统等待超时。
程序参数处理的片段如下,可以回忆下上一个挑战中对于参数的处理:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[]){
//...
}
目标
- 在右边的实验楼环境 WebIDE 中新建一个文档,命名为 sum.c;
- 将程序片段复制到文档 sum.c 中,并补充文档;
- sum.c 可以在环境中编译运行,编译后生成的可执行文件接受参数若干个整数,输出为这些整数的和;
- 例如编译后的可执行文件为 sum,则当输入的若干个整数为 2 3 7 8,输出为 20,结果如下:
$./sum 2 3 7 8
20
提示语
完成后请点击文档下方的 提交结果 查看是否通过挑战。
参考答案
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[]){
//判断参数个数是否大于等于2
if(argc < 2)
return 1;
int sum = 0;
//累加
for(int i=0;i<argc;i++){
sum += atoi(argv[i]);
}
printf("%d\n",sum);
return 0;
}
注意:“argc,命令行传递的参数总数。argv,命令行传递的每个参数值。