代码
6.1 square.c 程序 显示平方表 现在编写一个程序来显示平方表。首先程序提示用户输入一个数 ,然后显示出 行的输出,每行包含一个1~n的数及其平方值。 This program prints a table of squares. Enter number of entries in table: 5 1 1 2 4 3 9 4 16 5 25 把期望的平方数个数存储在变量n 中。程序需要用一个循环来重复显示数i 和它的平方值,循环从i 等于1开始。如果i 小于或等于n,那么循环将反复进行。需要保证的是每次执行循环时对i 值加1。可以使用while 语句编写循环。(坦白地说,现在没有其他更多的选择,因为while 语句是目前为止我们唯一掌握的循环类型。)下面是完成的程序。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
int n, i;
printf("This program prints a table of squares.\n");
printf("Enter number of entries in table: ");
scanf("%d", &n);
i = 1;
while (i <= n) {
printf("%10d%10d\n", i, i * i);
i++;
}
return 0;
}
留意一下程序square.c 是如何把输出整齐地排成两列的。窍门是使用类似%10d 这样的转换说明代替%d ,并利用了printf 函数在指定宽度内将输出右对齐的特性。
6.1 sum.c 程序 数列求和 在下面这个用到while 语句的示例中,我们编写了一个程序对用户输入的整数数列进行求和计算。下面显示的是用户能看到的内容: This program sums a series of integers. Enter integers (0 to terminate): 8 23 71 5 0 The sum is: 107 很明显,程序需要一个循环来读入数(用scanf 函数)并将其累加。用n 表示当前读入的数,而sum 表示所有先前读入的数的总和,得到如下程序:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
int n, sum = 0;
printf("This program sums a series of integer.\n");
printf("Enter integers (0 to terminate) : ");
scanf("%d", &n);
while (n != 0) {
sum += n;
scanf("%d", &n);
}
printf("The sum is: %d\n", sum);
return 0;
}
注意,条件n != 0 在数被读入后立即进行判断,这样可以尽快终止循环。此外,程序中用到了两个完全一样的scanf 函数调用,在使用while 循环时往往很难避免这种现象。
6.2 numdigit.c 程序 计算整数的位数 虽然C程序中while 语句的出现次数远远多于do 语句,但是后者对于至少需要执行一次的循环来说是非常方便的。为了说明这一点,现在编写一个程序计算用户输入的整数的位数: Enter a nonnegative integer: 60 The number has 2 digit(s). 方法是把输入的整数反复除以10,直到结果变为0停止;除法的次数就是所求的位数。因为不知道到底需要多少次除法运算才能达到0,所以很明显程序需要某种循环。但是应该用while 语句还是do 语句呢?do 语句显然更合适,因为每个整数(包括0)都至少有一位数字。下面是程序。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
int digits = 0, n;
printf("Enter a nonnegative integer: ");
scanf("%d", &n);
do {
n = n / 10;
digits++;
} while (n > 0);
printf("The number has %d digit(s).\n", digits);
return 0;
}
为了说明do 语句是正确的选择,下面观察一下如果用相似的while循环替换do 循环会发生什么: while (n > 0) { n /= 10; digits++; } 如果n 初始值为0,上述循环根本不会执行,程序将打印出 The number has 0 digit(s).
6.3 square2.c 程序square.c (?6.1节)可以通过将while 循环转化为for 循环的方式进行改进。
#include <stdio.h>
int main(void)
{
int i, n;
printf("This program prints a table of squares.\n");
printf("Enter number of entries in table: ");
scanf("%d", &n);
for (i = 1; i <= n; i++)
printf("%10d%10d\n", i, i * i);
return 0;
}
利用这个程序可以说明关于for 语句的一个要点:C语言对控制循环行为的三个表达式没有加任何限制。虽然这些表达式通常对同一个变量进行初始化、判定和更新,但是没有要求它们之间以任何方式进行相互关联。看一下同一个程序的另一个版本。 square3.c
#include <stdio.h>
int main(void)
{
int i, n, odd, square;
printf("This program prints a table of squares.\n");
printf("Enter number of entries in table: ");
scanf("%d", &n);
i = 1;
odd = 3;
for (square = 1; i <= n; odd += 2) {
printf("%10d%10d\n", i, square);
++i;
square += odd;
}
return 0;
}
这个程序中的for 语句初始化一个变量(square ),对另一个变量(i )进行判定,并且对第三个变量(odd )进行自增操作。变量i是要计算平方值的数,变量square 是变量i 的平方值,而变量odd是一个奇数,需要用它来和当前平方值相加以获得下一个平方值(允许程序不执行任何乘法操作而计算连续的平方值)。 for 语句这种极大的灵活性有时是十分有用的。后面我们将会发现for 语句在处理链表(?17.5节)时非常有用。但是,for 语句很容易误用,所以请不要走极端。如果重新安排程序square3.c 的各部分内容,可以清楚地表明循环是由变量i 来控制的,这样程序中的for 循环就清楚多了。
6.4 checking.c 程序 账簿结算 许多简单的交互式程序都是基于菜单的:它们向用户显示可供选择的命令列表;一旦用户选择了某条命令,程序就执行相应的操作,然后提示用户输入下一条命令;这个过程一直会持续到用户选择“退出”或“停止”命令。这类程序的核心显然是循环。循环内将有语句提示用户输入命令,读命令,然后确定执行的操作:
for ( ; ; ) {
提示用户录入命令;
读入命令;
执行命令;
}
执行这个命令将需要switch 语句(或者级联式if 语句):
for ( ; ; ) {
提示用户录入命令;
读入命令;
switch(命令){
case 命令1:执行操作1; break;
case 命令2:执行操作2; break;
.
.
.
case 命令n:执行操作n; break;
default: 显示错误消息; break;
}
}
为了说明这种格式,开发一个程序用来维护账簿的余额。程序将为用户提供选择菜单:清空账户余额,往账户上存钱,从账户上取钱,显示当前余额,退出程序。选择项分别用整数0、1、2、3和4表示。程序会话类似这样: *** ACME checkbook-balancing program *** Commands: 0=clear, 1=credit, 2=debit, 3=balance, 4=exit
Enter command: 1 Enter amount of credit: 1042.56 Enter command: 2 Enter amount of debit: 133.79 Enter command: 1 Enter amount of credit: 1754.32 Enter command: 2 Enter amount of debit: 1400 Enter command: 2 Enter amount of debit: 68 Enter command: 2 Enter amount of debit: 50 Enter command: 3 Current balance: $1145.09 Enter command: 4
当用户录入命令4(即退出)时,程序需要从switch 语句以及外围的循环中退出。break 语句不可能做到,同时我们又不想使用goto语句。因此,决定采用return 语句,这条语句将可以使程序终止并且返回操作系统。
#include <stdio.h>
int main(void)
{
int cmd;
float balance = 0.0f, credit, debit;
printf("*** ACME checkbook-balancing program ***\n");
printf("Commands: 0=clear, 1=credit, 2=debit, ");
printf("3=balance, 4=exit\n\n");
for (;;) {
printf("Enter command: ");
scanf("%d", &cmd);
switch (cmd) {
case 0:
balance = 0.0f;
break;
case 1:
printf("Enter amount of credit: ");
scanf("%f", &credit);
balance += credit;
break;
case 2:
printf("Enter amount of debit: ");
scanf("%f", &debit);
balance -= debit;
break;
case 3:
printf("Current balance: $%.2f\n", balance);
break;
case 4:
return 0;
default:
printf("Commands: 0=clear, 1=credit, 2=debit, ");
printf("3=balance, 4=exit\n\n");
break;
}
}
}
练习题
1.下列程序片段的输出是什么?
i = 1;
while (i <= 128){
printf("%d ", i);
i *= 2;
}
1 2 4 8 16 32 64 128 2.下列程序片段的输出是什么?
i = 9384;
do {
printf("%d ", i);
i /= 10;
} while (i > 0);
9384 938 93 9
3.下面这条for 语句的输出是什么?
for (i = 5, j = i - 1; i > 0, j > 0; --i , j = i - 1)
printf("%d ", i);
5 4 3 2
4.下列哪条语句和其他两条语句不等价(假设循环体都是一样的)?
(a) for (i = 0; i < 10; i++)...
(b) for (i = 0; i < 10; ++i)...
(c) for (i = 0; i++ < 10; )...
c 5. 下列哪条语句和其他两条语句不等价(假设循环体都是一样的)?
(a) while (i < 10) {...}
(b) for (; i < 10;) {...}
(c) do {...} while (i < 10);
c
6.把练习题1中的程序片段改写为一条for 语句。
for (i = 1; i <= 128; i *= 2) {
pritnf("%d ", i);
}
7.把练习题2中的程序片段改写为一条for 语句。
for (i = 9384; i > 0; i /= 10) {
printf("%d ", i);
}
8.下面这条for 语句的输出是什么?
for (i = 10; i >= 1; i /= 2)
printf("%d ", i++);
10 5 3 2 [1] 9.把练习题8中的for 语句改写为一条等价的while语句。除了while 循环本身之外,还需要一条语句。
i = 10;
while (i >= 1) {
printf("%d ", i++);
i /= 2;
}
10.说明如何用等价的goto 语句替换continue 语句。
Solution
Label the end of the loop and `goto` that label:
```c
for (i = 0; i <= 10; i++) {
if (i % 2 == 1)
continue;
printf("%d ", i);
}
is the same as
for (i = 0; i <= 10; i++) {
if (i % 2 == 1)
goto end;
printf("%d ", i);
end:
}
11.下列程序片段的输出是什么?
```c
sum = 0;
for (i = 0; i < 10; i++) {
if (i % 2)
continue;
sum += i;
}
printf("%d\n", sum);
20
- 下面的“素数判定”循环作为示例出现在6.4节中:
for (d = 2; d < n; d++)
if (n % d == 0)
break;
这个循环不是很高效。没有必要用n 除以2~n-1 的所有数来判断它是否为素数。事实上,只需要检查不大于n 的平方根的除数。利用这一点来修改循环。提示 :不要试图计算出n 的平方根,用d*d和n 进行比较。 Solution
for (d = 2; d * d <= n; d++) {
if (n % d == 0)
break;
}
13.重写下面的循环,使其循环体为空。
for (n = 0; m > 0; n++)
m /= 2;
Solution
for (n = 0; m > 0; n++, m /= 2) {
;
}
14.找出下面程序片段中的错误并修正。
if (n % 2 == 0);
printf("n is even\n");
remove semicolon
编程题
- 编写程序,找出用户输入的一串数中的最大数。程序需要提示用户一个一个地输入数。当用户输入0或负数时,程序必须显示出已输入的最大非负数:
Enter a number: 60 Enter a number: 38.3 Enter a number: 4.89 Enter a number: 100.62 Enter a number: 75.2295 Enter a number: 0 The largest number entered was 100.62 注意,输入的数不一定是整数。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
float number, max = 0;
printf("Enter a number: ");
scanf("%f", &number);
while (number > 0) {
if (number > max) {
max = number;
}
printf("Enter a number: ");
scanf("%f", &number);
}
printf("The largest number entered was %.2f\n", max);
return 0;
}
存在问题: 使用了两次prinf 和 scanf
#include <stdio.h>
int main(void) {
float largest = 0.0f;
float current;
do {
printf("Enter a number: ");
scanf("%f", ¤t);
if (current > largest)
largest = current;
} while (current > 0);
printf("\nThe largest number entered was %f\n", largest);
return 0;
}
- 编写程序,要求用户输入两个整数,然后计算并显示这两个整数的最大公约数(GCD):
Enter two integers: 12 28 Greatest common divisor: 4 提示 :求最大公约数的经典算法是Euclid算法,方法如下:分别让变量m 和n 存储两个数的值。如果n 为0,那么停止操作,m 中的值是GCD;否则计算m 除以n 的余数,把n 保存到m 中,并把余数保存到n 中。然后重复上述过程,每次都先判定n 是否为0。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
int m, n, temp;
printf("Enter two integers: ");
scanf("%d%d", &m, &n);
do {
if (n == 0) {
printf("Greatest common divisor: %d\n", m);
break;
}
else {
temp = n;
n = m % n;
m = temp;
}
} while (1);
return 0;
}
存在问题: 多用了判断语句;采用了死循环
#include <stdio.h>
int main(void) {
int m, n, r;
printf("Enter two integers: ");
scanf("%d%d", &m, &n);
while (n != 0) {
r = m % n;
m = n;
n = r;
}
printf("Greatest common divisor: %d\n", m);
return 0;
}
- 编写程序,要求用户输入一个分数,然后将其约分为最简分式:
Enter a fraction: 6/12 In lowest terms: 1/2 提示 :为了把分数约分为最简分式,首先计算分子和分母的最大公约数,然后分子和分母都除以最大公约数。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int euclid(int m, int n);
int main(void)
{
int m, n, gcd;
printf("Enter a fraction: ");
scanf("%d/%d", &m, &n);
gcd = euclid(m, n);
printf("In lowest terms: %d/%d\n", m / gcd, n / gcd);
return 0;
}
int euclid(int m, int n)
{
int r;
while (n != 0) {
r = m % n;
m = n;
n = r;
}
return m;
}
存在问题: scanf(“%d /%d”, &m, &n);
#include <stdio.h>
int main(void) {
int num, denom, n, m, r;
printf("Enter a fraction: ");
scanf("%d /%d", &num, &denom);
m = num;
n = denom;
while (n != 0) {
r = m % n;
m = n;
n = r;
}
printf("In lowest terms: %d/%d\n", num / m, denom / m);
return 0;
}
- 在5.2节的broker.c 程序中添加循环,以便用户可以输入多笔交易并且程序可以计算每次的佣金。程序在用户输入的交易额为0时终止。
Enter value of trade: 30000 Commission: $166.00 Enter value of trade: 20000 Commission: $144.00 Enter value of trade: 0
#include <stdio.h>
int main(void) {
float commission, value;
printf("Enter value of trade: ");
scanf("%f", &value);
while (value > 0) {
if (value < 2500.00f)
commission = 30.00f + .017f * value;
else if (value < 6250.00f)
commission = 56.00f + .0066f * value;
else if (value < 20000.00f)
commission = 76.00f + .0034f * value;
else if (value < 50000.00f)
commission = 100.00f + .0022f * value;
else if (value < 500000.00f)
commission = 155.00f + .0011f * value;
else
commission = 255.00f + .0009f * value;
if (commission < 39.00f)
commission = 39.00f;
printf("Commission: $%.2f\n\nEnter value of trade: ", commission);
scanf("%f", &value);
}
return 0;
}
- 第4章的编程题1要求编写程序显示出两位数的逆序。设计一个更具一般性的程序,可以处理一位、两位、三位或者更多位的数。提示 :使用do 循环将输入的数重复除以10,直到值达到0为止。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
int number, amount = 0, temp, sum = 0, rank = 1;
printf("Enter a number: ");
scanf("%d", &number);
temp = number;
do {
temp /= 10;
amount++;
} while (temp != 0);
for (int i = 1; i <= amount; i++) {
temp = number % 10;
for (int j = 1; j <= amount - i; j++) {
rank *= 10;
}
sum += temp * rank;
number /= 10;
rank = 1;
}
printf("The reversal is: %d\n", sum);
return 0;
}
存在问题: 太蠢了
#include <stdio.h>
int main(void) {
int n;
printf("Enter an integer: ");
scanf("%d", &n);
printf("Digits reversed: ");
do {
printf("%d", n % 10);
n /= 10;
} while (n != 0);
printf("\n");
return 0;
}
- 编写程序,提示用户输入一个数n,然后显示出1~ n的所有偶数平方值。例如,如果用户输入100,那么程序应该显示出下列内容:
4 16 36 64 100
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
int n;
printf("Enter a number: ");
scanf("%d", &n);
for (int i = 2; i * i <= n; i += 2) {
printf("%d\n", i * i);
}
return 0;
}
#include <stdio.h>
int main(void) {
int n, i;
printf("Enter a number: ");
scanf("%d", &n);
for (i = 1; i * i <= n; i++) {
if ((i * i) % 2 != 0)
continue;
printf("%d\n", i * i);
}
return 0;
}
- 重新安排程序square3.c ,在for 循环中对变量i 进行初始化、判定以及自增操作。不需要重写程序,特别是不要使用任何乘法。
#include <stdio.h>
int main(void) {
int i, n, odd, square;
printf("This program prints a table of squares.\n");
printf("Enter number of entries in table: ");
scanf("%d", &n);
odd = 3;
for (i = 1, square = 1; i <= n; odd += 2, ++i) {
printf("%10d%10d\n", i, square);
square += odd;
}
return 0;
}
- 编写程序显示单月的日历。用户指定这个月的天数和该月起始日是星期几:
Enter number of days in month: 31 Enter starting day of the week (1=Sun, 7=Sat): 3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 提示 :此程序不像看上去那么难。最重要的部分是一个使用变量i 从1计数到n 的for 语句(这里n 是此月的天数),for 语句中需要显示i 的每个值。在循环中,用if 语句判定i 是否是一个星期的最后一天,如果是,就显示一个换行符。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
int days, startDay;
printf("Enter number of days in month: ");
scanf("%d", &days);
printf("Enter starting day of the week (1=Sun, 7=Sat): ");
scanf("%d", &startDay);
for (int i = 1; i <= days; i++) {
}
return 0;
}
存在问题:没思路,笨死了 思路:一个变量控制循环, 一个变量负责显示数字
#include <stdio.h>
int main(void) {
int n, day, weekday, i;
printf("Enter number of days in month: ");
scanf("%d", &n);
printf("Enter starting day of the week (1=Mon, 7=Sun): ");
scanf("%d", &weekday);
printf("\n Mo Tu We Th Fr Sa Su\n");
for (i = 1, day = 1; i <= n + weekday - 1; i++) {
if (i < weekday)
printf(" ");
else
printf("%3d", day++);
if (i % 7 == 0)
printf("\n");
}
printf("\n");
return 0;
}
- 第2章的编程题8要求编程计算第一、第二、第三个月还贷后剩余的贷款金额。修改该程序,要求用户输入还贷的次数并显示每次还贷后剩余的贷款金额。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void) {
float loan = 0.0f,
rate = 0.0f,
payment = 0.0f;
int time;
printf("Enter amount of loan: ");
scanf("%f", &loan);
printf("Enter interest rate: ");
scanf("%f", &rate);
printf("Enter monthly payment: ");
scanf("%f", &payment);
printf("Enter time of payment: ");
scanf("%d", &time);
for (int i = 0; i < time; i++) {
loan = loan - payment + (loan * rate / 100.0f / 12.0f);
printf("Balance remaining after %d payment: $%.2f\n", i + 1, loan);
}
return 0;
}
#include <stdio.h>
int main(void) {
float loan = 0.0f,
rate = 0.0f,
payment = 0.0f;
int i,
num_of_payments;
printf("Enter amount of loan: ");
scanf("%f", &loan);
printf("Enter interest rate: ");
scanf("%f", &rate);
printf("Enter monthly payment: ");
scanf("%f", &payment);
printf("Enter number of payments: ");
scanf("%d", &num_of_payments);
for (i = 1; i <= num_of_payments; i++) {
loan = loan - payment + (loan * rate / 100.0 / 12.0);
printf("Balance remaining after payment %d: $%.2f\n", i, loan);
}
return 0;
}
- 第5章的编程题9要求编写程序判断哪个日期更早。泛化该程序,使用户可以输入任意个日期。用0/0/0指示输入结束,不再输入日期。
Enter a date (mm/dd/yy): 3/6/08 Enter a date (mm/dd/yy): 5/17/07 Enter a date (mm/dd/yy): 6/3/07 Enter a date (mm/dd/yy): 0/0/0 5/17/07 is the earliest date
存在问题:又笨死了
#include <stdio.h>
int main(void) {
int d1, d2, m1, m2, y1, y2;
printf("Enter a date (mm/dd/yy): ");
scanf("%d /%d /%d", &m1, &d1, &y1);
while (1) {
printf("Enter a date (mm/dd/yy): ");
scanf("%d /%d /%d", &m2, &d2, &y2);
if (d2 == 0 && m2 == 0 && y2 == 0)
break;
if (y2 < y1 || (y1 == y2 && m2 < m1) ||
(y1 == y2 && m1 == m2 && d2 < d1)) {
d1 = d2;
m1 = m2;
y1 = y2;
}
}
printf("%d/%d/%.2d is the earliest date\n", m1, d1, y1);
return 0;
}
- 数学常量e的值可以用一个无穷级数表示:
编写程序,用下面的公式计算 的近似值:
这里n是用户输入的整数。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void) {
int n, factorial = 1;
float approximateValue = 1;
printf("Enter a number: ");
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
factorial *= j;
}
approximateValue += 1.0f / factorial;
factorial = 1;
}
printf("e = %f", approximateValue);
return 0;
}
存在问题:搞复杂了,关键在于:找到外部变量i与内部变量之间的关系
#include <stdio.h>
int main(void) {
int i, n, denom;
float e;
printf("Enter integer n: ");
scanf("%d", &n);
for (i = 1, denom = 1, e = 1.0f; i <= n; i++) {
e += 1.0f / (denom *= i);
}
printf("Approximation of e: %f\n", e);
return 0;
}
- 修改编程题11,使得程序持续执行加法运算,直到当前项小于u为止,其中u是用户输入的较小的(浮点)数。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void) {
int n, factorial = 1;
float approximateValue = 1, u;
printf("Enter a number: ");
scanf("%d", &n);
printf("Enter mix float: ");
scanf("%f", &u);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
factorial *= j;
}
approximateValue += 1.0f / factorial;
if (1.0f / factorial < u) {
break;
}
factorial = 1;
}
printf("e = %f", approximateValue);
return 0;
}
存在问题: 没有吸收半点第11题的教训,该打
#include <stdio.h>
int main(void) {
int i, denom;
float e, epsilon, term;
printf("Enter epsilon: ");
scanf("%f", &epsilon);
for (i = 1, denom = 1, e = 1.0f, term = 1.0f; term > epsilon; i++) {
term = (1.0f / (denom *= i));
e += term;
}
printf("Approximation of e: %f\n", e);
return 0;
}
|