C语言程序设计
chapter 3 循环结构
1. for
for( 预定义条件; 判断条件; 条件增量 ){
循环体
}
程序执行的时候会先执行初始化条件,再判断条件是否成立;
如果条件成立就执行 {}中的循环体,如果条件不成立就退出循环;
{}执行完后再执行条件增量;
条件增量执行完后,再判断条件是否成立,如果成立继续循环执行{}中的语句,直到条件不成立退出。
总结就是其执行顺序为:
for( 1; 2; 4){
3
}
这里其实我们已经发现:初始条件(1)仅执行了一次,之后都是在 (2,3,4)中循环执行。
其实对于 for(1;2;4)中的 (1,2,4)三部分可以部分或者全部省略,
这样也不会有语法上面的问题,但是 ';' 不可省略。
//预定义条件, 判断条件,条件增量都可以不写,如下
for( ; ; ){
// 循环体
}
但是这样就是一个死循环(一直循环,没有结束)
所以我们需要另外使用一个退出:break
break 是指退出当前一层循环,比如
for(int i=1; i<=10; i++){
if(i==5) break;
printf("%d ", i);
}
当 i==5 的时候,就break(退出),这样输出的结果就是:1 2 3 4
后面的就不会输出了。
continue 退出本次循环,继续下次循环
for(int i=1; i<=10; i++){
if(i==5) continue;
printf("%d ", i);
}
当 i==5 的时候,就 continue(退出本次循环,继续下次循环),
这样输出的结果就是:1 2 3 4 6 7 8 9 10
会发现只有 5 没有输出,其余元素都输出了。
这就是 break 和 continue 的作用和不同。
注明:细心的读者已经发现问题了,没错,对于程序的写法我并未完全按照 C 标准的格式
比如:在 C 语言中使用 for 循环的写法应当是:
int i;
for(i=1; i<=10; i++){
//...
}
当然,如果我们使用 Dev-C++ 编译运行程序时会默认保存为 .cpp 格式,也就是 C++ 格式,那么这时候时不会报错的,但是一旦使用 .c 就会出现问题了,在后文中,为了节省这一点点篇幅,我还是会使用C++的写法 for(int i=1; i<=10; i++){...}
,但是读者应当明白这样会导致的问题,以及如何解决。
2. for循环案例练习
【题目描述】输入n,输出1~n。
输入样例:10
输出样例:1 2 3 4 5 6 7 8 9 10
#include<stdio.h>
int main(){
int n; scanf("%d", &n);
for(int i=1; i<=n; i++){//循环 1-n,次数:n
printf("%d ", i);
}
return 0;
}
【题目描述】输入n,输出1~n的所有偶数。
#include<stdio.h>
int main(){
int n; scanf("%d", &n);
for(int i=1; i<=n; i++){
if(i%2==0) printf("%d ", i);
}
return 0;
}
#include<stdio.h>
int main(){
int n; scanf("%d", &n);
for(int i=2; i<=n; i+=2){
printf("%d ", i);
}
return 0;
}
【题目描述】输入n,输出1~n的所有奇数之和与偶数之和。
#include<stdio.h>
int main(){
int sum1=0, sum2=0; //初始化为0,否则会随机化一个值
int n; scanf("%d", &n);
for(int i=1; i<=n; i++){ //1 2 3 ...
if(i%2==0) sum2=sum2+i;
else sum1=sum1+i;
}
printf("奇数和:%d 偶数和:%d", sum1, sum2);
return 0;
}
【题目描述】输入n,以及n个人的身高值,求出其中的最大值。
#include<stdio.h>
int main() {
int n, max = -1; scanf("%d", &n);
for(int i=1; i<=n; i++) {
int a; scanf("%d", &a);
if(max<a) max=a;
}
printf("%d", max);
return 0;
}
【题目描述】斐波那契数列 Fibonacci(又称为黄金数列)指的是这样一个数列:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,……
请你输出斐波那契数列的前 40 项。
#include<stdio.h>
int main(){
int i,a=1,b=1,c;
printf("第1项:%d",a);
printf("第2项:%d",b);
for(i=3; i<=40;i++){
c=a+b;
printf("第%d项:%d",i,c);
a=b;
b=c;
}
return 0;
}
3. while
while 循环分为两种直到型循环 和 当型循环
//当型循环:先判断满足条件,再执行循环体
while( 循环条件 ){
循环体
}
举例:输出 1~n
int i=1;
while( i<=n ){
printf("%d ", i);
i++;
}
当然它的写法有很多种,比如下面这样的:
int i=1;
while( 1 ){ //这样貌似好像是死循环了呢!那么怎么退出呢?
if(i>n) break;//退出当前一层循环
printf("%d ", i);
i++;
}
//直到型循环:先执行一次循环体,再判断是否满足条件,满足就继续执行,否则退出。
do{
循环体
}while(flag);
4. while循环案例练习
【题目描述】输入n,输出1~n。
【题目描述】输入n,输出1~n的所有偶数。
【题目描述】输入n,输出1~n的所有奇数之和与偶数之和。
【题目描述】输入n,以及n个人的身高值,求出其中的最大值。
【题目描述】斐波那契数列 Fibonacci(又称为黄金数列)指的是这样一个数列:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,……
请你输出斐波那契数列的前 40 项。
哈哈,你没看错,这就是上面for循环的那几个题,只是让你用 while 循环来实现一下。
但是我们又要思考,为什么有了 for循环,还有 while 循环呢?
其实你会发现,对于已经知道循环次数的题目,用 for 更方便一点;
但是如果不知道循环次数,但是知道结束条件,那么用 while 会更好一点。
5. 单层循环实例练习
需要给解析吗?貌似不需要......,思考了一下,还是给一点吧!
B2057 最高的分数
解析:数据抽象为在多个数据中寻找最大值,没说的。
#include<stdio.h>
int main(){
int n,maxn=0; scanf("%d", &n);
for(int i=1; i<=n; i++){//循环次数 n
int x; scanf("%d", &x);
if(maxn<x) maxn=x;
}
printf("%d", maxn);
return 0;
}
B2072 分苹果
解析:主要想到如何才能最少,那不就是从小到大递增嘛,所以对 1~n 累加即可。
#include<stdio.h>
int main(){
int n; scanf("%d", &n);
int sum=0;
for(int i=1; i<=n; i++){
sum += i;// sum = sum+i;
}
printf("%d", sum);
return 0;
}
B2060 满足条件的数累加
解析:给了左右边界,枚举一下,再判断所枚举的数据是否满足累加条件即可。
#include<stdio.h>
int main(){
int m,n; scanf("%d%d", &m, &n);
int sum=0;
for(int i=m; i<=n; i++){
if(i%17==0){
sum += i;
}
}
printf("%d", sum);
return 0;
}
B2055 均值
解析:就是求平均数,那么将数据累加后, ans=sum/n;
#include<stdio.h>
int main(){
int n; scanf("%d", &n);
double sum=0;
for(int i=0; i<n; i++){
double x; scanf("%lf", &x);
sum += x;
}
printf("%.4lf", sum/n);
return 0;
}
U169811 水仙花数
解析:水仙花数是一个三位数,那么枚举 [100, 999],再按照 水仙花数的特点进行判断是不是满足条件即可。
#include<stdio.h>
int main(){
for(int i=100; i<1000; i++){
int a = i/100;
int b = i/10%10;
int c = i%10;
if(i==a*a*a+b*b*b+c*c*c){
printf("%d\n", i);
}
}
return 0;
}
P1151 子数整数
解析:说了是一个五位数,那么枚举 [10000, 99999] ,并按照题目分割得到子数,最后判断子数是不是满足条件即可。
#include<stdio.h>
int main(){
int k,cnt=0; scanf("%d", &k);
for(int i=10000; i<=30000; i++){
int a = i/100;
int b = i/10%1000;
int c = i%1000;
if(a%k==0 && b%k==0 && c%k==0){
printf("%d\n", i); cnt=1;
}
}
if(cnt==0) printf("No\n");
return 0;
}
P1424 小鱼的航程(改进版)
解析:就是将整个过程模拟一遍就行,要注意就是:周天之后是周一。
模拟过程:天数 <=n, 就一直执行:周 x 递增,天数递增;
如果 周 x>7,则 x=1;
如果 周 x 属于 1~5,则小鱼泳一次 ans += 250;
最后输出结果 ans 即可。
#include<stdio.h>
int main(){
int x, n; scanf("%d%d", &x, &n);
int i=1, ans=0;
while(i<=n){
if(x>7) x=1;
if(x>=1 && x<=5) ans+=250;
i++; x++;
}
printf("%d", ans);
return 0;
}
6. 嵌套循环
所谓嵌套,就是一层套一层,类似套娃游戏;
#include<stdio.h>
int main(){
int n=5;
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
printf("%d:%d \t",i,j);
}
printf("\n");
}
return 0;;
}
输出结果:
1:1 1:2 1:3 1:4 1:5
2:1 2:2 2:3 2:4 2:5
3:1 3:2 3:3 3:4 3:5
4:1 4:2 4:3 4:4 4:5
5:1 5:2 5:3 5:4 5:5
对于双重循环,我们一般使用外层循环 i 来控制行数,内层循环 j 来控制列数。
除了上述 for-for的嵌套,还有 for-while, while-for, ..., for-for-for, ..., 很多格式都是可以的。
本质上循环的主要目的是控制执行次数,所以我们也可以将循环次数 与 问题本身相分割,但是习惯上,还是会将循环条件作为问题中的某些因素来使用, 如 for循环时的 i ,可以用来作为数组下标,奇偶次数判断等。
【题目描述】输出九九乘法表,样例如下:
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=12 4*4=16
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
解析:开始直接输出矩阵形态的样例,最后对样例寻找行列特性,发现 i>=j 才输出,否则不输出。
#include<stdio.h>
int main(){
int n=9;
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
if(i>=j) printf("%d*%d=%d\t", i,j,i*j);
}
printf("\n");
}
return 0;
}
7. 嵌套循环案例巩固
- B2083 画矩形
- B2101 计算矩阵边缘元素之和
- B2100 同行列对角线的格
- P5721 【深基4.例6】数字直角三角形
- P1980 [NOIP2013 普及组] 计数问题
- P2669 [NOIP2015 普及组] 金币
- P5725 【深基4.习8】求三角形
- P1035 [NOIP2002 普及组] 级数求和
- P5723 【深基4.例13】质数口袋
- P1307 [NOIP2011 普及组] 数字反转
- P1423 小玉在游泳
提升巩固解析
#include<stdio.h>
/*B2083 画矩形
1. 题目数据有问题,要求能过样例即可
2. 直接输出实心80score
3. 测试发现f需要初始为0,方可ac,怀疑数据最后的f=0赋值失败 */
int main(){
int a,b,f=0; char c;
scanf("%d%d %c%d", &a, &b, &c, &f);
for(int i=1; i<=a; i++){
for(int j=1; j<=b; j++){
if(i==1 || i==a) printf("%c", c);
else if(j==1||j==b) printf("%c", c);
else if(f==0) printf(" ");
else printf("%c",c);
}
printf("\n");
}
return 0;
}
- B2101 计算矩阵边缘元素之和
和上一个题目一样,设定行列的表示变量,如果是首尾行首尾列那么累加即可。
注意:这里很多同学在思考会不会重复累加的情况,其实不会的!因为我们只对每个数遍历一次,那么要么加,要么不加,不会出现第二次选择的机会。
#include<stdio.h>
int main(){
int m, n, sum=0; scanf("%d%d", &m, &n);
for(int i=1; i<=m; i++){
for(int j=1; j<=n; j++){
int x; scanf("%d", &x);
if(i==1||i==m || j==1 || j==n) sum+=x;
}
}
printf("%d", sum);
return 0;
}
- B2100 同行列对角线的格
读懂题目是关键,实现还需要找到一些规律,这里具体规律在程序中已经体现了。
另外本题较为隐秘的一个点:空格,需要多看样例,虽然题目也有说明,但是还是很容易犯错。
#include<stdio.h>
int main() {
int n,x,y; scanf("%d%d%d", &n, &x, &y);
for(int j=1; j<=n; j++){
printf("(%d,%d) ", x,j);//同行
}printf("\n");
for(int i=1; i<=n; i++){
printf("(%d,%d) ", i,y);//同列
}printf("\n");
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
if(j-i==y-x){
printf("(%d,%d) ", i,j);//左上到右下
}
}
}printf("\n");
for(int i=n; i>=1; i--){
for(int j=1; j<=n; j++){
if(i+j==x+y){
printf("(%d,%d) ", i,j);//左下到右上
}
}
}printf("\n");
return 0;
}
- P5721 【深基4.例6】数字直角三角形
题目很简单,主要是自己的思维逻辑,对于%02格式如果不清楚也可以通过 if(cnt<10)完成。
#include<stdio.h>
int main(){
int n,cnt=0; scanf("%d",&n);
for(int i=1; i<=n; i++){
for(int j=1; j<=n-i+1; j++){
printf("%02d", ++cnt);
}printf("\n");
}
return 0;
}
- P1980 [NOIP2013 普及组] 计数问题
如何循环提取一个数据中的某些数,但是对于原数不能改变,故而我们定义了一个临时变量temp, 检查一位删除一位,排好队一个一个来。
#include<stdio.h>
int main() {
int n,x; scanf("%d%d",&n,&x);
int cnt=0;
for(int i=1; i<=n; i++) {
int temp=i;
while(temp!=0) {
if(temp%10==x) cnt++;
temp=temp/10;
}
}
printf("%d",cnt);
return 0;
}
#include<stdio.h>
int main(){
int k; scanf("%d", &k);
int day=1,cnt=1, sum=0;//day表示天数,cnt表示每天发放金币数量
while(day<=k){
for(int i=1; i<=cnt && day<=k; i++){
sum += cnt; day++;
}
cnt++;
}
printf("%d", sum);
return 0;
}
- P5725 【深基4.习8】求三角形
有趣的题目,充满了暴力美学
#include<stdio.h>
int main(){
int n, cnt=0; scanf("%d", &n);
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
printf("%02d", ++cnt);
}printf("\n");
}printf("\n");
cnt=0;
for(int i=1; i<=n; i++){
for(int j=1; j<=n-i; j++) printf(" ");
for(int j=1; j<=i; j++) printf("%02d",++cnt);
printf("\n");
}
return 0;
}
- P1035 [NOIP2002 普及组] 级数求和
突然来这么简单的题目,这是看不起谁呢?
#include<stdio.h>
int main_1(){
int k, n=0; scanf("%d", &k);
double sum=0;
while(sum<=k){
n++;
sum += 1.0/n;
}
printf("%d", n);
return 0;
}
int main(){
int k, n=0; scanf("%d", &k);
double sum=0;
while(1){
n++;
sum += 1.0/n;
if(sum>k) break;
}
printf("%d", n);
return 0;
}
#include<stdio.h>
int main(){
int l, cnt=0; scanf("%d", &l);
for(int i=2; l>i; i++){
int flag=1;//1表示 i是质数,0表示不是质数
for(int j=2; j*j<=i; j++){
if(i%j==0) {
flag=0; break;
}
}
if(flag && l>=i){
l -= i; cnt++;
printf("%d\n", i);
}
}
printf("%d\n", cnt);
return 0;
}
#include<stdio.h>
int main(){
int n; scanf("%d", &n);
if(n<0) {
printf("-");
n = -n;
}
int ans=0;
while(n){
ans = ans*10+n%10;
n /= 10;
}
printf("%d", ans);
return 0;
}
- P1423 小玉在游泳
也就是一个模拟题目,理清游戏规则,梳理流程,一步一步实现即可。
注意输出结果为整数,如果定义为浮点数,记得强制转换
#include<stdio.h>
int main(){
double x, cnt=0, step=2, sum=0;
scanf("%lf", &x);
while(sum<x){
sum += step;
cnt++;
step = step*0.98;
}
printf("%d", (int)cnt);
return 0;
}