@toc
一、概述
循环结构是程序中一种很重要的结构。 其特点是:在给定条件成立时,反复执行某程序段,直到条件不成立为止。 给定的条件称为循环条件,反复执行的程序段称为循环体。 C语言提供了多种循环语句,可以组成各种不同形式的循环结构:
- goto语句和if语句构成循环;
- while语句;
- do-while语句;
- for语句。
二、goto语句和用goto语句构成循环
goto语句是一种无条件转移语句,与BASIC中的goto语句相似。 goto语句的使用格式为:
goto 语句标号;
其中标号是一个有效的标识符,这个标识符加上一个冒号:一起出现在函数内某处, 执行goto语句后,程序将跳转到该标号处并执行其后的语句。 标号必须与goto语句同处于一个函数中,但可以不在一个循环层中。 通常goto语句与if条件语句连用, 当满足某一条件时,程序跳到标号处运行。 要注意,通常不用goto语句,主要因为它将使程序层次不清,且不易读,但在多层嵌套退出时, 用goto语句则比较合理。
练习: 用goto语句和if语句构成循环求1-100所有数之和。 代码如下:
#include <stdio.h>
int main(){
int i = 1, sum = 0;
loop: if(i <= 100){
sum += i;
i++;
goto loop;
}
printf("Sum=%d", sum);
return 0;
}
打印:
Sum=5050
显然,此时求出了1-100的和。
三、while语句
1.基本使用
while语句的一般形式为:
while(表达式)语句
其中表达式是循环条件,语句为循环体。 while语句的语义是: 计算表达式的值,当值为真(非0)时, 执行循环体语句。 其执行过程如下: 显然可以得到,如果表达式的值一开始就为0,则语句一次也不会被执行。
练习: 用while语句求和1-100。 代码如下:
#include <stdio.h>
int main(){
int i = 1, sum = 0;
while(i <= 100){
sum += i;
i++;
}
printf("Sum=%d", sum);
return 0;
}
打印:
Sum=5050
显然,结果与之前的相同。
可能会出现死循环,示例如下:
#include <stdio.h>
int main(){
int i = 1, sum = 0;
while(i <= 100)
sum += i;
i++;
printf("Sum=%d", sum);
return 0;
}
只是在前面的基础上去掉了大括号,再运行会发现程序堵塞,一直不输出结果,查看CPU占用情况会发现编译器占用了大量的CPU,此时产生了死循环,因为去掉大括号后,while循环默认只包括赶紧跟在其后的第一条语句,即sum += i;
,而不再执行i自增,所以i一直为1,while循环的条件i <= 100
的条件恒成立,所以循环一直进行下去,永不结束,此时只能强制关闭程序才能终止运行。
再做一个练习: 统计从键盘输入一行字符的个数。 代码如下:
#include <stdio.h>
int main(){
int n = 0;
printf("Input a string:\n");
while(getchar() != '\n'){
n++;
}
printf("count=%d", n);
return 0;
}
打印:
Input a string:
123abc@#$,.?
count=12
本程序中的循环条件为getchar()!='\n'
,其意义是, 只要从键盘输入的字符不是回车就继续循环,循环体n++
完成对输入字符个数计数,从而实现了对输入字符的计数。
2.注意事项
(1)while语句中的表达式一般是关系表达式或逻辑表达式,只要表达式的值为真(非0)即可继续循环。 练习如下:
#include <stdio.h>
int main(){
int a = 0, n;
printf("Input a number:\n");
scanf("%d", &n);
while(n--){
printf("%d ", a++*2);
}
return 0;
}
打印:
Input a number:
10
0 2 4 6 8 10 12 14 16 18
此时,只要n不等于0,循环会一直进行。
(2)循环体如包括有一个以上的语句,则必须用{}括起来,组成复合语句,建议只有一条语句时也用大括号括起来。
四、do-while语句
do-while语句的一般形式为:
do
语句
while (表达式);
其执行过程如下:
这个循环与while循环的不同在于: 它先执行循环中的语句,然后再判断表达式是否为真,如果为真则继续循环;如果为假,则终止循环。 显然,do-while循环至少要执行一次循环语句。
用do-while循环求和测试如下:
#include <stdio.h>
int main(){
int i = 1, sum = 0;
do{
sum += i;
i++;
}
while(i <= 100);
printf("Sum=%d", sum);
return 0;
}
运行结果与之前相同。
如果最开始的条件就为假,则while循环一次都不会执行,do-while循环会执行一次,这是while循环和do-while循环的区别之一。
五、for语句
1.基本使用
在C语言中,for语句使用最为灵活,它完全可以取代while语句。 它的一般形式为:
for(表达式1; 表达式2; 表达式3) 语句
其执行过程如下:
- (1)先求解表达式1。
- (2)求解表达式2,若其值为真(非0),则执行for语句中指定的内嵌语句,然后执行下面第(3)步;若其值为假(为0),则结束循环,转到第(5)步。
- (3)求解表达式3。
- (4)转回上面第(2)步继续执行。
- (5)循环结束,执行for语句下面的一个语句。
for语句最简单也是最容易理解的形式如下:
for(循环变量赋初值; 循环条件; 循环变量增量) 语句
循环变量赋初值总是一个赋值语句,它用来给循环控制变量赋初值; 循环条件是一个关系表达式,它决定什么时候退出循环; 循环变量增量,定义循环控制变量每循环一次后按什么方式变化。 这三个部分之间用;分开。
求和用for循环改变如下:
#include <stdio.h>
int main(){
int i, sum = 0;
for(i = 1; i <= 100; i++){
sum += i;
}
printf("Sum=%d", sum);
return 0;
}
运算结果与前面相同。 先给i赋初值1,判断i是否小于等于100,若是则执行语句,之后值增加1,再重新判断, 直到条件为假,即i>100时,结束循环。
2.注意事项
(1)for循环中的表达式1(循环变量赋初值)、表达式2(循环条件)和表达式3(循环变量增量) 都是选择项, 即可以缺省,但;不能缺省。
(2)省略了表达式1(循环变量赋初值),表示不对循环控制变量赋初值。
上面代码也可以写成:
#include <stdio.h>
int main(){
int i = 1, sum = 0;
for( ; i <= 100; i++){
sum += i;
}
printf("Sum=%d", sum);
return 0;
}
效果一样。
(3)省略了表达式2(循环条件),则不做其他处理时便成为死循环。 例如
for(i=1;;i++)
{
sum=sum+i;
}
即是一个死循环。
(4)省略了表达式3(循环变量增量), 则不对循环控制变量进行操作,这时可在语句体中加入修改循环控制变量的语句。
代码还可以写成:
#include <stdio.h>
int main(){
int i, sum = 0;
for(i = 1; i <= 100; ){
sum += i;
i++;
}
printf("Sum=%d", sum);
return 0;
}
(5)还可以省略表达式1(循环变量赋初值)和表达式3(循环变量增量)。
代码还可以改成:
#include <stdio.h>
int main(){
int i = 1, sum = 0;
for( ; i <= 100; ){
sum += i;
i++;
}
printf("Sum=%d", sum);
return 0;
}
(6)3个表达式都可以省略。
例如for( ; ; )
语句相当于while(1)
语句。
(7)表达式1可以是设置循环变量的初值的赋值表达式,也可以是其他表达式。
代码还可以写为:
#include <stdio.h>
int main(){
int i = 1,sum;
for(sum = 0; i <= 100; ){
sum += i;
i++;
}
printf("Sum=%d", sum);
return 0;
}
(8)表达式1和表达式3可以是一个简单表达式也可以是逗号表达式。 例如:
for(i=0, j=100; i<=100; i++, j--)
k=i+j;
求和代码还可以写为:
#include <stdio.h>
int main(){
int i, sum;
for(i = 1, sum = 0 ; i <= 100; ){
sum += i;
i++;
}
printf("Sum=%d", sum);
return 0;
}
(9)表达式2一般是关系表达式或逻辑表达式,但也可是数值表达式或字符表达式,只要其值非零,就执行循环体。
例如for(i=0; (c=getchar())!='\n'; i+=c);
。
3.循环的嵌套
循环的嵌套是指循环中的语句又是一个循环。
练习如下:
#include <stdio.h>
int main(){
int i, j, k;
for(i = 1; i <= 3; i++){
for(j = 1; j <= 4; j++){
for(k = 1; k <= 5; k++){
printf("%d, %d, %d\n", i, j, k);
}
}
}
return 0;
}
打印:
1, 1, 1
1, 1, 2
1, 1, 3
1, 1, 4
1, 1, 5
1, 2, 1
1, 2, 2
1, 2, 3
1, 2, 4
1, 2, 5
1, 3, 1
1, 3, 2
1, 3, 3
1, 3, 4
1, 3, 5
1, 4, 1
1, 4, 2
1, 4, 3
1, 4, 4
1, 4, 5
2, 1, 1
2, 1, 2
2, 1, 3
2, 1, 4
2, 1, 5
2, 2, 1
2, 2, 2
2, 2, 3
2, 2, 4
2, 2, 5
2, 3, 1
2, 3, 2
2, 3, 3
2, 3, 4
2, 3, 5
2, 4, 1
2, 4, 2
2, 4, 3
2, 4, 4
2, 4, 5
3, 1, 1
3, 1, 2
3, 1, 3
3, 1, 4
3, 1, 5
3, 2, 1
3, 2, 2
3, 2, 3
3, 2, 4
3, 2, 5
3, 3, 1
3, 3, 2
3, 3, 3
3, 3, 4
3, 3, 5
3, 4, 1
3, 4, 2
3, 4, 3
3, 4, 4
3, 4, 5
练习: 输出以下图形:
代码如下:
#include <stdio.h>
int main(){
int i, j;
for(i = 1; i <= 6; i++){
for(j = 1; j <= i; j++){
putchar('*');
}
printf("\n");
}
return 0;
}
打印:
*
**
***
****
*****
******
显然,得到了想要的结果。
六、几种循环方式的比较
四种循环都可以用来处理同一问题,一般情况下它们可以互相代替。 一般不提倡用goto型循环。
在while循环和do-while循环中,只在while后面的括号内指定循环条件,因此为了使循环能正常结束,应在循环体中加入使循环趋于结束的语句(如i++,或i=i+1等)。 for循环可以在表达式3中包含使循环趋于结束的操作,甚至可以将循环体中的操作全部放到表达式3中。 因此for语句的功能更强,凡是用while循环能完成的,用for循环都能实现。
用while和do-while循环时,循环变量初始化的操作应在while和do-while语句之前完成,而for语句可以在表达式1中实现循环变量的初始化。
while循环、do-while循环和for循环,可以用break语句跳出循环,用continue语句结束本次循环,而对用goto语句和if语句构成的循环,不能用break语句和continue语句进行控制。
练习: 有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 实现原理: 可填在百位、十位、个位的数字都是1、2、3、4,组成所有的排列后再去掉不满足条件的排列。
代码如下:
#include <stdio.h>
int main(){
int i, j, k;
for(i = 1; i <= 4; i++){
for(j = 1; j <= 4; j++){
for(k = 1; k <= 4; k++){
if(i != j && i != k && j != k){ // 确保i、j、k三位互不相同
printf("%d%d%d\n", i, j, k);
}
}
}
}
return 0;
}
打印:
123
124
132
134
142
143
213
214
231
234
241
243
312
314
321
324
341
342
412
413
421
423
431
432
七、break和continue语句
1.break语句
break语句用来从循环体内跳出循环体,即提前结束循环,接着执行循环下面的语句。 一般形式:
break;
break语句不能用于循环语句和switch语句之外的任何其他语句中。 注意:
- break语句对if-else的条件语句不起作用。
- 在多层循环中,一个break语句只向外跳一层。
练习如下:
#include <stdio.h>
int main(){
double pi = 3.14159, area;
int r;
for(r = 1; r <= 10; r++){
area = pi * r * r;
if(area > 100){
break;
}
printf("r=%d, area=%g\n", r, area);
}
return 0;
}
打印:
r=1, area=3.14159
r=2, area=12.5664
r=3, area=28.2743
r=4, area=50.2654
r=5, area=78.5397
显然,虽然理论上可以循环10次,但是由于r=6时面积已经大于100,所以执行break语句,提前结束循环,即不再继续执行其余的几次循环。
再来一个稍复杂的练习:
#include <stdio.h>
#include <conio.h>
int main(){
int i = 0;
char c;
while(1){
c = '\0';
while(c!=13 && c!=27){ // 键盘接收字符直到按回车或Esc键
c = getch();
printf("%c\n", c);
}
if(c==27){ // 判断,若按Esc键则退出循环
break;
}
i++;
printf("The number is %d\n", i);
}
printf("End");
return 0;
}
打印:
a
s
d
f
g
The number is 1
q
w
e
r
t
The number is 2
1
2
3
4
5
The number is 3
End
显然,内层循环按回车或Esc退出,外层循环按Esc退出;+ -+ + + + + + + + + + + + +
其中getch()
适用于从控制台读取一个字符、但不显示在屏幕上,需要引入头文件conio.h
。
2.continue语句
作用为结束本次循环,即跳过循环体中下面尚未执行的语句,接着进行下一次是否执行循环的判定。 一般形式:
continue;
练习如下:
#include <stdio.h>
int main(){
double pi = 3.14159, area;
int r;
for(r = 1; r <= 10; r++){
area = pi * r * r;
if(area > 100 && area < 120){
continue;
}
printf("r=%d, area=%g\n", r, area);
}
return 0;
}
打印:
r=1, area=3.14159
r=2, area=12.5664
r=3, area=28.2743
r=4, area=50.2654
r=5, area=78.5397
r=7, area=153.938
r=8, area=201.062
r=9, area=254.469
r=10, area=314.159
显然,此时只是跳过了第6次循环,后面的迭代继续进行。
3.continue和break的对比
continue语句只结束本次循环,而不是终止整个循环的执行; break语句则是结束整个循环过程,不再判断执行循环的条件是否成立。
练习: 显示输入的字符,如果按的是Esc键,则退出循环;如果按的是Enter键,则不做任何处理,继续输入下一个字符。 代码如下:
#include <conio.h>
int main(){
char c;
for( ; ; ){
c = getch(); // 字符输入函数
if(c==27){
break;
}
if(c==13){
continue;
}
putch(c); // 显示输入的字符
}
getch(); // 让程序停一下,按任意键继续
return 0;
}
打印:
abcdef123
此时输入普通字符会显示,输入回车会跳过、不换行,输入Esc会跳出循环,再输入即退出。
其中,getch()
和putch()
需要引入conio.h头文件。
练习: 把100~200之间的不能被3整除的数输出。 实现原理: 当n能被3整除时,执行continue语句,结束本次循环(即跳过printf函数语句),只有n不能被3整除时才执行printf函数。 代码如下:
#include <stdio.h>
int main(){
int i;
for(i = 100; i <= 200; i++){
if(i % 3 == 0){
continue;
}
printf("%d\n", i);
}
return 0;
}
打印:
100
101
103
104
106
107
109
110
112
113
115
116
118
119
121
122
124
125
127
128
130
131
133
134
136
137
139
140
142
143
145
146
148
149
151
152
154
155
157
158
160
161
163
164
166
167
169
170
172
173
175
176
178
179
181
182
184
185
187
188
190
191
193
194
196
197
199
200
练习:
用π/4 ≈ 1-1/3+1/5-1/7+…
公式求π的近似值,直到某一项的绝对值小于为止。
实现原理:
要确定计算的精度,可以配合while循环语句用fabs()
函数确定精度来退出;
据观察,分子不变,分母却每次递增2,且正负切换;
结果乘以4。
代码如下:
#include <stdio.h>
#include <math.h>
int main(){
int i = 1;
double s = 1.0;
double pt = 0, pi;
while(fabs(s/i) > 1e-8){
pt += s / i;
s = -s;
i += 2;
}
pi = pt * 4;
printf("PI=%10.8f", pi);
return 0;
}
打印:
PI=3.14159263
显然,得到了π的估计值。
练习: 求Fibonacci数列前40个数。 这个数列有如下特点:第1,2两个数为1,1;从第3个数开始,该数是其前面两个数之和。 即
F(1) = 1 (n=1) F(2) = 1 (n=2) F(n) = F(n-1)+F(n-2) (n≥3)
代码如下:
#include <stdio.h>
int main(){
long i, f1 = 1, f2 = 1;
for(i = 1; i <= 20; i++){
printf("%10ld %10ld ", f1, f2);
f1 += f2;
f2 += f1;
if(i % 2 == 0){
printf("\n");
}
}
return 0;
}
打印:
1 1 2 3
5 8 13 21
34 55 89 144
233 377 610 987
1597 2584 4181 6765
10946 17711 28657 46368
75025 121393 196418 317811
514229 832040 1346269 2178309
3524578 5702887 9227465 14930352
24157817 39088169 63245986 102334155
练习: 写一个程序,允许输入一个数,并判断这个数是否为素数。 其中,素数又称质数,指在一个大于1的自然数中,除了1和此整数自身外,没法被其他自然数整除的数。 换句话说,只有两个正因数(1和自己)的自然数即为素数。
代码如下:
#include <stdio.h>
#include <math.h>
int main(){
int n, i, prime = 1;
printf("Input a number:\n");
scanf("%d", &n);
for(i = 2; i <= sqrt(n); i++){
if(n % i == 0){
prime = 0;
break;
}
}
if(prime){
printf("%d is a prime number\n", n);
}
else{
printf("%d is not a prime number\n", n);
}
return 0;
}
打印:
Input a number:
23
23 is a prime number
其中,sqrt()
函数用来求一个数的算术平方根,返回double型的值。
练习: 求100~200间的全部素数并打印出来。 代码如下:
#include <stdio.h>
#include <math.h>
int main(){
int n, i, c = 1;
for(n = 100; n <= 200; n++){
int prime = 1;
for(i = 2; i <= sqrt(n); i++){
if(n % i == 0){
prime = 0;
break;
}
}
if(prime){
printf("% 4d", n);
if(c % 5 == 0){
printf("\n");
}
c++;
}
}
return 0;
}
打印:
101 103 107 109 113
127 131 137 139 149
151 157 163 167 173
179 181 191 193 197
199
练习: 为使电文保密,往往按一定规律将其转换成密码,收报人再按约定的规律将其译回原文。 例如,可以按以下规律将电文变成密码:
将字母A变成字母E,a变成e,即变成其后的第4个字母,W变成A,X变成B,Y变成C,Z变成D。 如输入
China!
得到Glmre!
。
代码如下:
#include <stdio.h>
int main(){
char c = getchar();
while(c != '\n'){
if(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'){
if(c >= 'w' && c <= 'z' || c >= 'W' && c <= 'Z'){
c = c - 22;
}
else{
c = c + 4;
}
}
putchar(c);
c = getchar();
}
printf("\n");
return 0;
}
打印:
zxcvb12345ASDFGqweRT
dbgzf12345EWHJKuaiVX
本文原文首发来自博客专栏C语言学习,由本人转发至https://www.helloworld.net/p/75QH9YtZwfjG,其他平台均属侵权,可点击https://blog.csdn.net/CUFEECR/article/details/105724161查看原文,也可点击https://blog.csdn.net/CUFEECR浏览更多优质原创内容。