7.1 sum2.c
程序 数列求和(改进版)
6.1节编写了一个程序对用户输入的整数数列求和。该程序的一个问题就是所求出的和(或其中某个输入数)可能会超出int 型变量允许的最大值。如果程序运行在整数长度为16位的机器上,可能会发生下面的情况:
This program sums a series of integers.
Enter integers (0 to terminate): 10000 20000 30000 0
The sum is: -5536
求和的结果应该为60 000,但这个值不在int 型变量表示的范围内,所以出现了溢出。当有符号整数发生溢出时,结果是未定义的,在本例中我们得到了一个毫无意义的结果。为了改进这个程序,可以把变量改换成long 型。
sum2.c #includeint main(void) { long n, sum = 0; printf("This program sums a series of integers.n"); printf("Enter integers (0 to terminate): "); scanf("%ld", &n); while (n != 0) { sum += n; scanf("%ld", &n); } printf("The sum is: %ldn", sum); return 0; }
这种改变非常简单:将n 和sum 声明为long 型变量而不是int 型变量,然后把scanf 和printf 函数中的转换说明由%d 改为%ld。
7.3 length.c
程序 确定消息的长度
为了说明字符的读取方式,下面编写一个程序来计算消息的长度。在用户输入消息后,程序显示长度:
Enter a message: Brevity is the soul of wit.
Your message was 27 character(s) long.
消息的长度包括空格和标点符号,但是不包含消息结尾的换行符。程序需要采用循环结构来实现读入字符和计数器自增操作,循环在遇到换行符时立刻终止。我们既可以采用scanf 函数也可以采用getchar 函数读取字符,但大多数C程序员愿意采用getchar 函数。采用简明的while 循环书写的程序如下:
#includeint main(void) { char ch; int len = 0; printf("Enter a message: "); ch = getchar(); while (ch != 'n') { len++; ch = getchar(); } printf("Your message was %d character(s) long.n", len); return 0; }
回顾有关while 循环和getchar 函数惯用法的讨论,我们发现程序可以缩短成如下形式:
length2.c #include练习题int main(void) { int len = 0; printf("Enter a message: "); while (getchar() != 'n') len++; printf("Your message was %d character(s) long.n", len); return 0; }
- 给出下列整数常量的十进制值。
(a) 077 (b) 0x77 (c) 0xABC
(a) 63 (b) 119 (c) 2748
- 下列哪些常量在C语言中不是合法的?区分每一个合法的常量是整数还是浮点数。
(a) 010E2 (b) 32.1E+5 (c) 0790 (d) 100_000 (e) 3.978e-2
(c) and (d) are illegal constants, because of undefined numeral `9` in octal number `0790`, and underscore in `100_000`. (a), (b) and (e) are legal, floating point constants.
- 下列哪些类型在C语言中不是合法的?
(a) short unsigned int (b) short float (c) long double (d) unsigned long
(b) `short float` is not a legal type. The only available floating point types are `float`, `double` and `long double`.
- 如果变量c 是char 类型,那么下列哪条语句是非法的?
(a) i += c; (b) c = 2 * c - 1; (c) putchar(c); (d) printf(c);
(d) `printf(c);` is illegal, because the `printf` function prints strings, not individual (numerical representations of) characters.
- 下列哪条不是书写数65的合法方式?(假设字符集是ASCII。)
(a) 'A' (b) 0b1000001 (c) 0101 (d) 0x41
(b) `0b1000001` is illegal, as C does not allow binary represented numbers.
- 对于下面的数据项,指明char 、short 、int 、long 类型中哪种类型是足以存储数据的最小类型。
(a) 一个月的天数 (b) 一年的天数 (c) 一天的分钟数 (d) 一天的秒数
(a) Max. 31: `char` (b) Max. 366: `short` (c) Max. 1500: `short` (d) Max. 86760: `long`
- 对于下面的字符转义,给出等价的八进制转义。(假定字符集是ASCII。)可以参考附录E,其中列出了ASCII字符的数值码。
(a) b (b) n (c) r (d) t
(a) `10` (b) `12` (c) `15` (d) `11`
- 重复练习题7,给出等价的十六进制转义。
(a) `x08` (b) `x0a` (c) `x0d` (d) `x09`
- 假设变量i 和变量j 都是int 类型,那么表达式i / j + ‘a’ 是什么类型?
`int`. The expression automatically promotes the `char` value `'a'` to an `int`.
- 假设变量i 是int 类型,变量j 是long int 类型,并且变量k 是unsigned int 类型,那么表达式i + (int)j * k 是什么类型?
`unsigned int`. `j` casts to `int`, and `k` promotes the expression to `unsigned int`.
- 假设变量i 是int 类型,变量f 是float 类型,变量d 是double 类型,那么表达式i * f / d 是什么类型?
`double`, as it will promote the other types automatically to `double`.
- 假设变量i 是int 类型,变量f 是float 类型,变量d 是double 类型,请解释在执行下列语句时发生了什么转换?
d = i + f;
The addition operation will require conversion of the value of `i` to `float`, and the assignment operation will require conversion of the summed value to `double`.
- 假设程序包含下列声明:
char c = '1'; short s = 2; int i = -3; long m = 5; float f = 6.5f; double d = 7.5;
给出下列每个表达式的值和类型。
(a) c * i (c) f / c (e) f - d (b) s + m (d) d / s (f) (int) f
(a) `-3`, `int` (b) `7`, `long` (c) `6.5f`, `float` (d) `3.75`, `double` (e) `-1.0`, `double` (f) `6`, `int`
- 下列语句是否总是可以正确地计算出f 的小数部分(假设f 和frac_part 都是float 类型的变量)?frac_part = f - (int) f;如果不是,那么出了什么问题?
No, the statement could fail if the value of `f` is larger than the largest value of `int`.
- 使用typedef 创建名为Int8 、Int16 和Int32 的类型。定义这些类型以便它们可以在你的机器上分别表示8位、16位和32位的整数。
typedef char Int8; char uses 1 byte (8 bits) of memory typedef short Int16; short uses 2 bytes (16 bits) of memory typedef int Int32; int uses 4 bytes (32 bits) of memory Unlike #define macros, we put our intended variable types at the end of typedef编程题
- 如果i * i 超出了int 类型的最大取值,那么6.3节的程序square2.c 将失败(通常会显示奇怪的答案)。运行该程序,并确定导致失败的n 的最小值。尝试把变量i 的类型改成short 并再次运行该程序。(不要忘记更新printf 函数调用中的转换说明!)然后尝试改成long 。从这些实验中,你能总结出在你的机器上用于存储整数类型的位数是多少吗?
#includeint main(void) { short i, n; printf("This program prints a table of squares.n"); printf("Enter number of entries in table: "); scanf("%hd", &n); for (i = 1; i <= n; i++) printf("%20hd%20hdn", i, i * i); return 0; }
- 修改6.3节的程序square2.c ,每24次平方后暂停并显示下列信息:
Press Enter to continue…
显示完上述消息后,程序应该使用getchar 函数读入一个字符。getchar 函数读到用户录入的回车键才允许程序继续。
#includeint main(void) { int i, n; printf("This program prints a table of squares.n"); printf("Enter number of entries in table: "); scanf("%d", &n); getchar(); for (i = 1; i <= n; i++) { printf("%10d%10dn", i, i * i); if (i % 24 == 0) { printf("Press Enter to continue..."); while (getchar() != 'n') ; } } return 0; }
3. 修改7.1节的程序sum2.c ,对double 型值组成的数列求和。
#includeint main(void) { double n, sum = 0.0; printf("This program sums a series of floating-point numbers.n"); printf("Enter numbers (0 to terminate): "); scanf("%lf", &n); while (n != 0.0) { sum += n; scanf("%lf", &n); } printf("The sum is: %fn", sum); return 0; }
- 编写程序可以把字母格式的电话号码翻译成数值格式:
Enter phone number: CALLATT
2255288
(如果没有电话在身边,参考这里给出的字母在键盘上的对应关系:2=ABC ,3=DEF ,4=GHI ,5=JKL ,6=MNO ,7=PQRS ,8=TUV ,9=WXYZ 。)原始电话号码中的非字母字符(例如数字或标点符号)保持不变:
Enter phone number: 1-800-COL-LECT
1-800-265-5328
可以假设任何用户输入的字母都是大写字母。
#includeint main(void) { char c; printf("Enter phone number: "); while ((c = getchar()) != 'n') { switch (c) { case 'A': case 'B': case 'C': putchar('2'); break; case 'D': case 'E': case 'F': putchar('3'); break; case 'G': case 'H': case 'I': putchar('4'); break; case 'J': case 'K': case 'L': putchar('5'); break; case 'M': case 'N': case 'O': putchar('6'); break; case 'P': case 'R': case 'S': putchar('7'); break; case 'T': case 'U': case 'V': putchar('8'); break; case 'W': case 'X': case 'Y': putchar('9'); break; default: putchar(c); break; } } printf("n"); return 0; }
- 在十字拼字游戏中,玩家利用小卡片组成单词,每个卡片包含字母和面值。面值根据字母稀缺程度的不同而不同。(面值有:1——
AEILNORSTU,2——DG,3——BCMP,4——FHVWY,5——K,8——JX,10——QZ。)编写程序通过对单词中字母的面值求和来计算单词的值:
Enter a word: pitfall
Scrabble value: 12
编写的程序应该允许单词中混合出现大小写字母。提示 :使用toupper 库函数。
#include#include int main(void) { char c; int sum; printf("Enter a word: "); while ((c = getchar()) != 'n') { switch (toupper(c)) { case 'A': case 'E': case 'I': case 'L': case 'N': case 'O': case 'R': case 'S': case 'T': case 'U': sum++; break; case 'D': case 'G': sum += 2; break; case 'B': case 'C': case 'M': case 'P': sum += 3; break; case 'F': case 'H': case 'V': case 'W': case 'Y': sum += 4; break; case 'K': sum += 5; break; case 'J': case 'X': sum += 8; break; case 'Q': case 'Z': sum += 10; break; default: break; } } printf("Scrabble value: %dn", sum); return 0; }
- 编写程序显示sizeof(int) 、sizeof(short) 、sizeof(long) 、sizeof(float) 、sizeof(double) 和sizeof(long double) 的值。
#includeint main(void) { printf("%lu, %lu, %lu, %lu, %lu, %lun", (unsigned long) sizeof(int), (unsigned long) sizeof(short), (unsigned long) sizeof(long), (unsigned long) sizeof(float), (unsigned long) sizeof(double), (unsigned long) sizeof(long double)); return 0; }
- 修改第3章的编程题6,使得用户可以对两个分数进行加、减、乘、除运算(在两个分数之间输入+ 、- 、* 或/ 符号)。
#includeint main(void) { int num1, denom1, num2, denom2, result_num, result_denom; char operator; printf("Enter two fractions separated by an operator: "); scanf("%d /%d %c %d /%d", &num1, &denom1, &operator, &num2, &denom2); switch (operator) { case '+': result_num = num1 * denom2 + num2 * denom1; result_denom = denom1 * denom2; break; case '-': result_num = num1 * denom2 - num2 * denom1; result_denom = denom1 * denom2; break; case '*': result_num = num1 * num2; result_denom = denom1 * denom2; break; case '/': result_num = num1 * denom2; result_denom = num2 * denom1; break; default: printf("Operation %c not supported.n", operator); return 1; } int temp, num_temp = result_num, gcd = result_denom; while (num_temp != 0) { temp = gcd % num_temp; gcd = num_temp; num_temp = temp; } if (result_num / gcd == result_denom / gcd) printf("Result: %dn", result_num / gcd); else if (result_num > result_denom) { printf("Result: %d %d/%dn", result_num / result_denom, result_num % result_denom, result_denom); } else printf("Result: %d/%dn", result_num / gcd, result_denom / gcd); return 0; }
- 修改第5章的编程题8,要求用户输入12小时制的时间。输入时间的格式为时∶分 后跟A、P、AM或PM(大小写均可)。数值时间和AM/PM之间允许有空白(但不强制要求有空白)。有效输入的示例如下:
1:15P
1:15PM
1:15p
1:15pm
1:15 P
1:15 PM
1:15 p
1:15 pm
可以假定输入的格式就是上述之一,不需要进行错误判定。
#include#include int main(void) { int user_time, hour, minute, d1 = 480, d2 = 583, d3 = 679, d4 = 767, d5 = 840, d6 = 945, d7 = 1140, d8 = 1305; char c; printf("Enter a 12-hour time with AM/PM indicator: "); scanf("%d :%d %c", &hour, &minute, &c); user_time = (((toupper(c) == 'P' ? 12 : 0) + hour) * 60) + minute; printf("Closest departure time is "); if (user_time <= d1 + (d2 - d1) / 2) printf("8:00 a.m., arriving at 10:16 a.m.n"); else if (user_time < d2 + (d3 - d2) / 2) printf("9:43 a.m., arriving at 11:52 a.m.n"); else if (user_time < d3 + (d4 - d3) / 2) printf("11:19 a.m., arriving at 1:31 p.m.n"); else if (user_time < d4 + (d5 - d4) / 2) printf("12:47 p.m., arriving at 3:00 p.m.n"); else if (user_time < d5 + (d6 - d5) / 2) printf("2:00 p.m., arriving at 4:08 p.m.n"); else if (user_time < d6 + (d7 - d6) / 2) printf("3:45 p.m., arriving at 5:55 p.m.n"); else if (user_time < d7 + (d8 - d7) / 2) printf("7:00 p.m., arriving at 9:20 p.m.n"); else printf("9:45 p.m., arriving at 11:58 p.m.n"); return 0; }
- 编写程序要求用户输入12小时制的时间,然后用24小时制显示该时间:
Enter a 12-hour time: 9:11 PM
Equivalent 24-hour time: 21:11
参考编程题8中关于输入格式的描述。
#include#include int main(void) { int user_time, hour, minute; char c; printf("Enter a 12-hour time with AM/PM indicator: "); scanf("%d :%d %c", &hour, &minute, &c); user_time = (toupper(c) == 'P' ? 12 : 0) + hour; printf("Closest departure time is %d:%dn", user_time, minute); return 0; }
与第五章第二题类似
存在问题: 未考虑12点的
12 : 36 AM 00:36
12:36 PM – 12:36
#include#include int main(void) { int hour, minute; char c; printf("Enter a 12-hour time: "); scanf("%d :%d %c", &hour, &minute, &c); hour = (hour == 12 ? 0 : hour); if (toupper(c) == 'P') hour += 12; printf("Equivalent 24-hour time: %.2d:%.2dn", hour, minute); return 0; }
- 编写程序统计句子中元音字母(a、e、i、o、u)的个数:
Enter a sentence: And that’s the way it is.
Your sentence contains 6 vowels.
#include#include int main(void) { char c; int vowels = 0; printf("Enter a sentence: "); while ((c = getchar()) != 'n') { switch (toupper(c)) { case 'A': case 'E': case 'I': case 'O': case 'U': vowels++; break; default: break; } } printf("Your sentence contains %d vowels.n", vowels); return 0; }
- 编写一个程序,根据用户输入的英文名和姓先显示姓氏,其后跟一个逗号,然后显示名的首字母,最后加一个点:
Enter a first and last name: Lloyd Fosdick
Fosdick, L.
用户的输入中可能包含空格(名之前、名和姓之间、姓氏之后)。
#define _CRT_SECURE_NO_WARNINGS #include#include int main(void) { char first; char ch; printf("Enter a first and last name: "); while ((ch = getchar()) == ' ') { ; } first = ch; while (getchar() != ' ') { ; } while ((ch = getchar()) == ' ') { ; } printf("%c", ch); while ((ch = getchar()) != 'n') { printf("%c", ch); } printf(", %c.n", first); return 0; }
存在问题:
太多循环了
#includeint main(void) { char c, initial; printf("Enter a first and last name: "); scanf(" %c", &initial); while ((c = getchar()) != ' ') ; while ((c = getchar()) == ' ') ; do { putchar(c); } while ((c = getchar()) != 'n' && c != ' '); printf(", %c.n", initial); return 0; }
- 编写程序对表达式求值:
Enter an expression: 1+2.53
Value of expression: 10.5
表达式中的操作数是浮点数,运算符是+ 、- 、 和/ 。表达式从左向右求值(所有运算符的优先级都一样)。
#includeint main(void) { double num = 0.0, total = 0.0; char c; printf("Enter an expression: "); scanf("%lf", &total); while ((c = getchar()) != 'n') { switch (c) { case '+': scanf("%lf", &num); total += num; break; case '-': scanf("%lf", &num); total -= num; break; case '*': scanf("%lf", &num); total *= num; break; case '/': scanf("%lf", &num); total /= num; break; default: break; } } printf("Value of expression: %fn", total); return 0; }
- 编写程序计算句子的平均词长:
Enter a sentence: It was deja vu all over again.
Average word length: 3.4
简单起见,程序中把标点符号看作其前面单词的一部分。平均词长显示一个小数位。
#includeint main(void) { char c; double length = 0.0; int words = 1; printf("Enter a sentence: "); while ((c = getchar()) != 'n') { if (c == ' ') words++; else length++; } printf("Average word length: %.1fn", length / words); return 0; }
- 编写程序,用牛顿方法计算正浮点数的平方根:
Enter a positive number: 3
Square root: 1.73205
设x是用户输入的数。牛顿方法需要先给出x平方根的猜测值y(我们使用1)。后续的猜测值通过计算y和x/y的平均值得到。下表给出了求解3的平方根的过程。
x y x/y y和x/y的平均值
3 1 3 2
3 2 1.5 1.75
3 1.75 1.71429 1.73214
3 1.73214 1.73196 1.73205
3 1.73205 1.73205 1.73205
注意, y的值逐渐接近x的平方根。为了获得更高的精度,程序中应使用double 类型的变量代替float 类型的变量。当y的新旧值之差的绝对值小于0.00001和y的乘积时程序终止。提示 :调用fabs 函数求double 类型数值的绝对值。(为了使用fabs 函数,需要在程序的开头包含头。)
#include#include int main(void) { double x, y = 1.0; printf("Enter a positive number: "); scanf("%lf", &x); while (fabs((y + x / y) / 2 - y) > .00001 * y) y = (y + x / y) / 2; printf("Square root: %fn", y); return 0; }
- 编程计算正整数的阶乘:
Enter a positive integer: 6
Factorial of 6: 720
(a) 用short 类型变量存储阶乘的值。为了正确打印出 的阶乘, 的最大值是多少?
(b) 用int 类型变量重复(a)。
© 用long 类型变量重复(a)。
(d) 如果你的编译器支持long long 类型,用long long 类型变量重复(a)。
(e) 用float 类型变量重复(a)。
(f) 用double 类型变量重复(a)。
(g) 用long double 类型变量重复(a)。
在(e)~(g)几种情况下,程序会显示阶乘的近似值,不一定是准确值。
#includeint main(void) { int i, n; long double fact = 1.0; printf("Enter a positive integer: "); scanf("%d", &n); for (i = n; i > 1; i--) fact *= i; printf("Factorial of %d: %Lfn", n, fact); return 0; }



