代码
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
#include <stdio.h>
int 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: %ld\n", 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 循环书写的程序如下:
#include <stdio.h>
int 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 <stdio.h>
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; /* i has type int */
(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 。从这些实验中,你能总结出在你的机器上用于存储整数类型的位数是多少吗?
#include <stdio.h>
int 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%20hd\n", i, i * i);
return 0;
}
- 修改6.3节的程序square2.c ,每24次平方后暂停并显示下列信息:
Press Enter to continue… 显示完上述消息后,程序应该使用getchar 函数读入一个字符。getchar 函数读到用户录入的回车键才允许程序继续。
#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);
getchar();
for (i = 1; i <= n; i++) {
printf("%10d%10d\n", i, i * i);
if (i % 24 == 0) {
printf("Press Enter to continue...");
while (getchar() != '\n')
;
}
}
return 0;
}
3. 修改7.1节的程序sum2.c ,对double 型值组成的数列求和。
#include <stdio.h>
int 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: %f\n", 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 可以假设任何用户输入的字母都是大写字母。
#include <stdio.h>
int 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 <stdio.h>
#include <ctype.h>
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: %d\n", sum);
return 0;
}
- 编写程序显示sizeof(int) 、sizeof(short) 、sizeof(long) 、sizeof(float) 、sizeof(double) 和sizeof(long double) 的值。
#include <stdio.h>
int main(void) {
printf("%lu, %lu, %lu, %lu, %lu, %lu\n",
(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,使得用户可以对两个分数进行加、减、乘、除运算(在两个分数之间输入+ 、- 、* 或/ 符号)。
#include <stdio.h>
int 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: %d\n", result_num / gcd);
else if (result_num > result_denom) {
printf("Result: %d %d/%d\n",
result_num / result_denom, result_num % result_denom, result_denom);
} else
printf("Result: %d/%d\n", 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 <stdio.h>
#include <ctype.h>
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 <stdio.h>
#include <ctype.h>
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:%d\n", user_time, minute);
return 0;
}
与第五章第二题类似 存在问题: 未考虑12点的 12 : 36 AM 00:36 12:36 PM – 12:36
#include <stdio.h>
#include <ctype.h>
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:%.2d\n", 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 <stdio.h>
#include <ctype.h>
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 <stdio.h>
#include <ctype.h>
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;
}
存在问题: 太多循环了
#include <stdio.h>
int 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 表达式中的操作数是浮点数,运算符是+ 、- 、 和/ 。表达式从左向右求值(所有运算符的优先级都一样)。
#include <stdio.h>
int 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: %f\n", total);
return 0;
}
- 编写程序计算句子的平均词长:
Enter a sentence: It was deja vu all over again. Average word length: 3.4 简单起见,程序中把标点符号看作其前面单词的一部分。平均词长显示一个小数位。
#include <stdio.h>
int 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: %.1f\n", 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 函数,需要在程序的开头包含<math.h> 头。)
#include <stdio.h>
#include <math.h>
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: %f\n", 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)几种情况下,程序会显示阶乘的近似值,不一定是准确值。
#include <stdio.h>
int 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: %Lf\n", n, fact);
return 0;
}
|