C_Primer_Plus06.Control-Looping
控制语句:循环
- 要点
for, while, do while
<, >, >=, <=, !=, ==, +=, -+, *=, /=, %=
fabs()
使用关系运算符构建控制循环表达式
其他运算符
循环常用的数组
编写有返回值的函数
while 循环
#include <stdio.h>
int main(void){
long num;
long sum = 0L;
int status;
printf("Enter an integer to be summed (q to quit): ");
status = scanf("%ld", &num);
while (status == 1){
sum += num;
printf("Enter next integer (q to quit): ");
status = scanf("%ld", &num);
}
printf("Total sum is: %ld\n", sum);
return 0;
}
output:
Enter an integer to be summed (q to quit): 5
Enter next integer (q to quit): 4564365
Enter next integer (q to quit):
q
Total sum is: 4564370
上面 while 循环部分可以替换为:
#include <stdio.h>
int main(void){
long num;
long sum = 0L;
printf("Enter an integer to be summed (q to quit): ");
while (scanf("%ld", &num) == 1){
sum += num;
printf("Enter next integer (q to quit): ");
}
printf("Total sum is: %ld\n", sum);
return 0;
}
有时 while 的测试条件中已经完成了要执行的任务,此时循环体是空语句,则只需要一个分号即可,并应让分号独占一行,这样提高了代码可读性,也提醒了自己和读者空语句是有意为之:
while (scanf("%d", &num) != 1)
;
注意,while 条件中,为防止双等号错写成等号而陷入死循环,可以将数字写在左侧:
while (1 == status)
, 这样写成单等号时,会编译不过去,而不会陷入死循环
fabs()
常用于浮点数的比较。浮点数的比较尽量只用大于小于,不用等于号,因为浮点数存在舍入误差。
#include <stdio.h>
#include <math.h>
int main(void){
const double pi = 3.1415926;
double input;
printf("Input pi:\n");
scanf("%lf", &input);
while (fabs(input - pi) > 0.0001){
printf("Try again!\n");
scanf("%lf", &input);
}
printf("Close enough!\n");
return 0;
}
output:
Input pi:
3
Try again!
3.14
Try again!
3.1415
Close enough!
for 循环
example0:
#include <stdio.h>
int main(void){
int num = 0;
for (printf("Keep entering number!\n"); num != 6;)
scanf("%d", &num);
printf("That's the one I want!\n");
return 0;
}
output:
Keep entering number!
4
1
6
That's the one I want!
example1:
/* 等比数列求和 */
#include <stdio.h>
int main(void){
int n, limit;
double item;
double sum;
printf("Enter a number you want to loop: ");
scanf("%d", &limit);
for (n = 0, item = 1., sum = item;
n < limit; n++, item /= 2., sum += item)
printf("sum = %.4f when n = %d.\n", sum, n);
printf("Sum is %.4lf\n", sum);
return 0;
}
output:
Enter a number you want to loop: 10
sum = 1.0000 when n = 0.
sum = 1.5000 when n = 1.
sum = 1.7500 when n = 2.
sum = 1.8750 when n = 3.
sum = 1.9375 when n = 4.
sum = 1.9688 when n = 5.
sum = 1.9844 when n = 6.
sum = 1.9922 when n = 7.
sum = 1.9961 when n = 8.
sum = 1.9980 when n = 9.
Sum is 1.9990
逗号运算符保证从左到右依次执行
do while
略
如何选择循环:
- 入口条件循环用的多
- 可读性好
- 在许多应用中,要求在一开始不满足测试条件时就直接跳过整个循环
- 当循环时涉及初始化和更新变量时,用for更合适
- 涉及计数的用for更合适
for(ch = 'A'; ch < 'Z'; ch++)
- 涉及循环输入,判断输入满足条件的,用while合适
while (1 == scanf("%ld", &num))
数组
一般来说,数组中的元素都属于同一类型。
float debts[20];
debts[5] = 32.54;
scanf("%lf", &debts[4]);
debts[20] = 88.1; // 该元素不存在
考虑到影响执行的速度,C 编译器不会检查数组的下标是否正确。给越界的下标赋值可能会使数据放置在被其他数据占用的地方,可能会破坏程序的结果甚至导致程序异常中断。
对于 char 类型的数组,如果数组末尾包含一个表示字符串末尾的空字符 \0
,则该数组中的内容就构成了一个字符串。
ex05:
编写一个程序,提示用户输入大写字母。使用嵌套循环以下面金字塔型的格式打印字母:
A
ABA
ABCBA
ABCDCBA
ABCDEDCBA
打印这样的图形,要根据用户输入的字母来决定。例如,上面的图形是在用户输入E后的打印结果。
提示:用外层循环处理行,每行使用3个内层循环,分别处理空格、以403升序打印字母、以降序打印字母。如果系统不使用ASCII或其他以数字顺序编码的代码,请参照练习3的解决方案。
#include <stdio.h>
int main(void){
int num = 5;
char ch_begin = 'A';
for (int i = 0; i < num; i++){
for (int j = 0; j < num-i-1; j++)
printf(" ");
for (int k = 0; k <= i; k++)
printf("%c", ch_begin+k);
for (int k = i-1; k >= 0; k--)
printf("%c", ch_begin+k);
printf("\n");
}
}
output:
A
ABA
ABCBA
ABCDCBA
ABCDEDCBA
ex12:
考虑下面两个无限序列:
1.0 + 1.0/2.0 + 1.0/3.0 + 1.0/4.0 + ...
1.0 - 1.0/2.0 + 1.0/3.0 - 1.0/4.0 + ...
编写一个程序计算这两个无限序列的总和,直到到达某次数。提示:奇数个-1 相乘得-1,偶数个-1相乘得1。让用户交互地输入指定的次数,当用户输入0或负值时结束输入。查看运行100项、1000项、10000项后的总和,是否发现每个序列都收敛于某值?
#include <stdio.h>
int main(void){
int num;
float sum0, sum1;
int i, j;
printf("Please enter an integer (0 or minus or non-number to quit): ");
while (1 == scanf("%d", &num)){
if (num <= 0){
printf("quit.\n");
break;
}
sum0 = 0.;
sum1 = 0.;
j = 1;
for (i = 1; i <= num; i++){
sum0 += 1./i;
sum1 += j*1./i;
j = -j;
}
printf("sum0: %.3f, sum1: %.3f\n", sum0, sum1);
printf("Enter another integer (0 or minus or non-number to quit): ");
}
return 0;
}
output:
Please enter an integer (0 or minus or non-number to quit): 9
sum0: 2.829, sum1: 0.746
Enter another integer (0 or minus or non-number to quit): 10
sum0: 2.929, sum1: 0.646
Enter another integer (0 or minus or non-number to quit): 100
sum0: 5.187, sum1: 0.688
Enter another integer (0 or minus or non-number to quit): 1000
sum0: 7.485, sum1: 0.693
Enter another integer (0 or minus or non-number to quit): 10000
sum0: 9.788, sum1: 0.693
Enter another integer (0 or minus or non-number to quit): 100000000000
sum0: 15.404, sum1: 0.693
Enter another integer (0 or minus or non-number to quit): q
ex14:
编写一个程序,创建两个包含8个元素的double类型数组,使用循环提示用户为第一个数组输入8 个值。第二个数组元素的值设置为第一个数组对应元素的累积之和。例如,第二个数组的第 4个元素的值是第一个数组前4个元素之和,第二个数组的第5个元素的值是第一个数组前5个元素之和(用嵌套循环可以完成,但是利用第二个数组的第5个元素是第二个数组的第4个元素与第一个数组的第5个元素之和,只用一个循环就能完成任务,不需要使用嵌套循环)。最后,使用循环显示两个数组的内容,第一个数组显示成一行,第二个数组显示在第一个数组的下一行,而且每个元素都与第一个数组各元素相对应。
#include <stdio.h>
int main(void){
int size = 8;
double a[size];
double b[size];
printf("Enter eight number sequentially:\n");
for (int i = 0; i < size; i++){
scanf("%lf", &a[i]);
if (i == 0) {
b[i] = a[i];
}else{
b[i] = b[i-1] + a[i];
}
}
printf("a: ");
for (int i = 0; i < size; i++){
printf("%10.3lf", a[i]);
}
printf("\n"
"b: ");
for (int i = 0; i < size; i++){
printf("%10.3lf", b[i]);
}
printf("\n");
return 0;
}
output:
Enter eight number sequentially:
1
3
5
6
7
3
1
4
a: 1.000 3.000 5.000 6.000 7.000 3.000 1.000 4.000
b: 1.000 4.000 9.000 15.000 22.000 25.000 26.000 30.000
ex15:
编写一个程序,读取一行输入,然后把输入的内容倒序打印出来。可以把输入储存在char类型的数组中,假设每行字符不超过255。回忆一下,根据%c转换说明,scanf()函数一次只能从输入中读取一个字符,而且在用户按下Enter键时scanf()函数会生成一个换行字符(\n)。
#include <stdio.h>
int main(void){
int size = 255;
char chs[size];
char ch;
int idx = 0;
while (1){
printf("Enter a string (no longer than %d): ", size);
idx = 0;
scanf("%c", &ch);
while ('\n' != ch){
if (idx < size){
chs[idx++] = ch;
}
scanf("%c", &ch);
}
printf("Reverse: ");
for (; idx > 0; idx--){
printf("%c", chs[idx-1]);
}
printf("\n");
}
return 0;
}
output:
Enter a string (no longer than 255): l;asdfjlkdsafkl;dsahf
Reverse: fhasd;lkfasdkljfdsa;l
Enter a string (no longer than 255): lasdfj;a
Reverse: a;jfdsal
Enter a string (no longer than 255): ^C
ex16:
Daphne以10%的单利息投资了100美元(也就是说,每年投资获利相当于原始投资的10%)。Deirdre以 5%的复合利息投资了 100 美元(也就是说,利息是当前余额的 5%,包含之前的利息)。编写一个程序,计算需要多少年Deirdre的投资额才会超过Daphne,并显示那时两人的投资额。
/* calculate interest */
#include <stdio.h>
int main(void){
double a = 100.;
double b = 100.;
double aa = a, bb = b;
double ai = .1;
double bi = .05;
int year = 0;
printf("Init: a=%.1lf, b=%.1lf\n", a, b);
while (bb <= aa){
aa += a * ai;
bb += bb * bi;
year++;
printf("After %2d year, a=%.3lf, b=%.3lf\n", year, aa, bb);
}
printf("%d years later, a grows more than b.\n"
"a=%.3lf, b=%.3lf\n", year, aa, bb);
return 0;
}
output:
Init: a=100.0, b=100.0
After 1 year, a=110.000, b=105.000
After 2 year, a=120.000, b=110.250
After 3 year, a=130.000, b=115.763
After 4 year, a=140.000, b=121.551
After 5 year, a=150.000, b=127.628
After 6 year, a=160.000, b=134.010
After 7 year, a=170.000, b=140.710
After 8 year, a=180.000, b=147.746
After 9 year, a=190.000, b=155.133
After 10 year, a=200.000, b=162.889
After 11 year, a=210.000, b=171.034
After 12 year, a=220.000, b=179.586
After 13 year, a=230.000, b=188.565
After 14 year, a=240.000, b=197.993
After 15 year, a=250.000, b=207.893
After 16 year, a=260.000, b=218.287
After 17 year, a=270.000, b=229.202
After 18 year, a=280.000, b=240.662
After 19 year, a=290.000, b=252.695
After 20 year, a=300.000, b=265.330
After 21 year, a=310.000, b=278.596
After 22 year, a=320.000, b=292.526
After 23 year, a=330.000, b=307.152
After 24 year, a=340.000, b=322.510
After 25 year, a=350.000, b=338.635
After 26 year, a=360.000, b=355.567
After 27 year, a=370.000, b=373.346
27 years later, a grows more than b.
a=370.000, b=373.346
ex17:
Chuckie Lucky赢得了100万美元(税后),他把奖金存入年利率8%的账户。在每年的最后一天, Chuckie取出10万美元。编写一个程序,计算多少年后Chuckie会取完账户的钱?
/* bonus */
#include <stdio.h>
int main(void){
double bonus = 100.;
double rate = .08;
double spend = 10.;
int year = 0;
printf("Initially, bonus has %.1lf.\n", bonus);
while (bonus > 0){
bonus += bonus * rate - spend;
year++;
printf("%2d years later, bonus left %.3lf.\n", year, bonus);
}
printf("%2d years later, bonus spend out.\n", year);
return 0;
}
output:
Initially, bonus has 100.0.
1 years later, bonus left 98.000.
2 years later, bonus left 95.840.
3 years later, bonus left 93.507.
4 years later, bonus left 90.988.
5 years later, bonus left 88.267.
6 years later, bonus left 85.328.
7 years later, bonus left 82.154.
8 years later, bonus left 78.727.
9 years later, bonus left 75.025.
10 years later, bonus left 71.027.
11 years later, bonus left 66.709.
12 years later, bonus left 62.046.
13 years later, bonus left 57.009.
14 years later, bonus left 51.570.
15 years later, bonus left 45.696.
16 years later, bonus left 39.351.
17 years later, bonus left 32.500.
18 years later, bonus left 25.100.
19 years later, bonus left 17.107.
20 years later, bonus left 8.476.
21 years later, bonus left -0.846.
21 years later, bonus spend out.
ex18:
Rabnud博士加入了一个社交圈。起初他有5个朋友。他注意到他的朋友数量以下面的方式增长。第1周少了1个朋友,剩下的朋友数量翻倍;第2周少了2个朋友,剩下的朋友数量翻倍。一般而言,第N周少了N个朋友,剩下的朋友数量翻倍。编写一个程序,计算并显示Rabnud博士每周的朋友数量。该程序一直运行,直到超过邓巴数(Dunbar’s number)。邓巴数是粗略估算一个人在社交圈中有稳定关系的成员的最大值,该值大约是150。
/* dunbar's number */
#include <stdio.h>
int main(void){
int n, num = 5;
printf("Enter an integer: ");
scanf("%d", &n);
for (int i = 0; i < n; num = 2*(num-i), i++)
printf("num = %d when i = %d\n", num, i);
printf("Finally, num = %d\n", num);
return 0;
}
output:
Enter an integer: 5
num = 5 when i = 0
num = 10 when i = 1
num = 18 when i = 2
num = 32 when i = 3
num = 58 when i = 4
Finally, num = 108