经典习题
- 编写一个程序,要求用户输入一个华氏温度。程序应读取double类型的值作为温度值,并把该值作为参数传递给一个用户自定义的函数Temperatures()。该函数计算摄氏温度和开氏温度,并以小数点后面两位数字的精度显示3种温度。要使用不同的温标来表示这3个温度值。下面是华氏温度转摄氏温度的公式:
摄氏温度 = 5.0 / 9.0 * (华氏温度 - 32.0)
开氏温标常用于科学研究,0表示绝对零,代表最低的温度。下面是摄氏温度转开氏温度的公式:
开氏温度 = 摄氏温度 + 273.16
Temperatures()函数中用const创建温度转换中使用的变量。在main()函数中使用一个循环让用户重复输入温度,当用户输入 q 或其他非数字时,循环结束。scanf()函数返回读取数据的数量,所以如果读取数字则返回1,如果读取q则不返回1。可以使用==运算符将scanf()的返回值和1作比较,测试两值是否相等。
1 | #include <stdio.h> |
- 编写一个程序,创建一个包含26个元素的数组,并在其中储存26个小写字母。然后打印数组的所有内容。
1 | #include <stdio.h> |
编写一个程序,提示用户输入大写字母。使用嵌套循环以下面金字塔型的格式打印字母:
A
ABA
ABCBA
ABCDCBA
ABCDEDCBA
打印这样的图形,要根据用户输入的字母来决定。例如,上面的图形是在用户输入E后的打印结果。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
32
33
34
35
36
37
38
39
40
41
42
43#include <stdio.h>
void print_spaces(unsigned int n);
int main() {
char uppercase_letter;
char c1, c2;
do // get uppercase letter from user
{
printf("Enter an uppercases letter:");
scanf("%c", &uppercase_letter);
}while (uppercase_letter < 'A'|| 'Z' < uppercase_letter);
for(c1 = 'A'; c1 <= uppercase_letter; c1++)
{
//print opening spaces
print_spaces(uppercase_letter -c1);
//print letter
//ascending
for (c2 = 'A'; c2 < c1; c2++){
printf("%c", c2);
}
// descending
for (; 'A' <= c2; c2--)
{
printf("%c", c2);
}
//print closing spaces
print_spaces(uppercase_letter - c1);
printf("\n");
}
return 0;
}
void print_spaces(unsigned int n){
for (int i = 0; i < n; i++)
{
printf(" ");
}
}考虑下面两个无限序列:
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项后的总和,是否发现每个序列都收敛于某值?
1 | #include <stdio.h> |
- 编写一个程序,创建两个包含8个元素的double类型数组,使用循环提示用户为第一个数组输入8 个值。第二个数组元素的值设置为第一个数组对应元素的累积之和。例如,第二个数组的第 4个元素的值是第一个数组前4个元素之和,第二个数组的第5个元素的值是第一个数组前5个元素之和(用嵌套循环可以完成,但是利用第二个数组的第5个元素是第二个数组的第4个元素与第一个数组的第5个元素之和,只用一个循环就能完成任务,不需要使用嵌套循环)。最后,使用循环显示两个数组的内容,第一个数组显示成一行,第二个数组显示在第一个数组的下一行,而且每个元素都与第一个数组各元素相对应。
1 | #include <stdio.h> |
- 编写一个程序,读取一行输入,然后把输入的内容倒序打印出来。可以把输入储存在char类型的数组中,假设每行字符不超过255。回忆一下,根据%c转换说明,scanf()函数一次只能从输入中读取一个字符,而且在用户按下Enter键时scanf()函数会生成一个换行字符(\n)。
1 | #include <stdio.h> |
- line[i] != ‘\n’ 的条件判断使得循环在用户输入的行中包含换行符之前继续执行。当用户按下 Enter 键时,输入的换行符会被检测到,并导致循环结束。
- 编写一个统计单词数量的程序(即,该程序读取并报告单词的数量)。该程序还可以计算字符数和行数。
1 | // wordcnt.c -- 统计字符数、单词数、行数 |
- 编写程序读取输入,读到#停止,报告ei出现的次数。
- 注意
该程序要记录前一个字符和当前字符。用“Receive your eieio award”这样的输入来测试。
1 | #include <stdio.h> |
- 编写一个程序,提示用户输入一周工作的小时数,然后打印工资总额、税金和净收入。做如下假设:
a.加班(超过40小时) = 1.5倍的时间
b.税率: 前300美元为15%
续150美元为20%
余下的为25%
让程序可以给出一个供选择的工资等级菜单。使用switch完成工资等级选择。运行程序后,显示的菜单应该类似这样:
1 | ***************************************************************** |
如果选择 1~4 其中的一个数字,程序应该询问用户工作的小时数。程序要通过循环运行,除非用户输入 5。如果输入 1~5 以外的数字,程序应提醒用户输入正确的选项,然后再重复显示菜单提示用户输入。使用#define创建符号常量表示各工资等级和税率。
1 | #include <stdio.h> |
switch
语句中使用的表达式必须具有整数类型或枚举类型,或者是具有单个转换函数到整数或枚举类型的类类型,无法进行bool等逻辑运算。
- ABC 邮购杂货店出售的洋蓟售价为 2.05美元/磅,甜菜售价为 115 美元/磅,胡萝卜售价为1.09美元/磅。在添加运费之前,100美元的订单有 5%的打折优惠。少于或等于5磅的订单收取 6.5 美元的运费和包装费,5磅~ 20 磅的订单收取14 美元的运费和包装费,超过 20 磅的订单在 14 美元的基础上每续重1磅增加 0.5 美元。
编写一个程序,在循环中用 switch 语句实现用户输入不同的字母时有不同的响应,即输入a的响应是让用户输入洋蓟的磅数,b 是甜菜的磅数,c 是胡萝人的磅数,q 是退出订购。程序要记录累计的重量。即,如果用户输入 4磅的甜菜,然后输入 5磅的甜菜,程序应报告9 磅的甜菜。然后,该程序要计算货物总价、折扣(如果有的话) 、运费和包装费。随后,程序应显示所有的购买信息: 物品售价、订购的重量(单位:磅) 、订购的蔬菜费用、订单的总费用、折扣(如果有的话)、运费和包装费,以及所有的费用总额。
1 | #include <stdio.h> |
- 设计一个名为alter()的函数,接受两个int类型的变量x和y,把它们的值分别改成两个变量之和以及两变量之差。
使用指针
1 | void alter(int * pa, int * pb) |
** or **
1 | void alter(int * pa, int * pb) |
- power()函数返回一个double类型数的正整数次幂。改进该函数,使其能正确计算负幂。另外,函数要处理0的任何次幂
都为0,任何数的0次幂都为1(函数应报告0的0次幂未定义,因此把该值处理为1)。使用递归函数并在程序中测试该函数。
1 | #include <stdio.h> |
编写一个函数,返回储存在double类型数组中最大值的下标,并在一个简单的程序中测试该函数。
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SIZE 10
int index_of_max(double *arr, int arr_size);
int main(void)
{
// test index_of_max
printf("Driver for index_of_max: returns index of the largest value stored "
"in an array of doubles.\n");
putchar('\n');
double test[SIZE];
srand(time(NULL)); // seed random number generator
// initialize test array with random doubles
for (int i = 0; i < SIZE; i++)
test[i] = rand() / (double) RAND_MAX;
// print test array
printf("%5s ", "Index");
for (int i = 0; i < SIZE; i++)
printf("| %6d ", i);
printf("\n");
printf("%5s ", "Value");
for (int i = 0; i < SIZE; i++)
printf("| %6.4f ", test[i]);
printf("\n");
printf("\n");
// print results
printf("The maximum value occurs at index %d\n", index_of_max(test, SIZE));
return 0;
}
int index_of_max(double *arr, int arr_size)
{
// return index of max value in array of doubles
int index_of_max = 0;
for (int i = 1; i < arr_size; i++)
if (*(arr + i) > *(arr + index_of_max))
index_of_max = i;
return index_of_max;
}编写一个函数,把double类型数组中的数据倒序排列,并在一个简单的程序中测试该函数。
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void reverse_array(double *arr, int arr_size);
int main(void)
{
// test reverse_array()
printf("Testing reverse_array()\n");
double test1[9];
double test2[10];
double test3[2];
srand(time(NULL));
// initialize test array 1 with 9 random doubles
for (int i = 0; i < 9; i++)
test1[i] = rand() / (double) RAND_MAX;
// initialize test array 2 with 10 random doubles
for (int i = 0; i < 10; i++)
test2[i] = rand() / (double) RAND_MAX;
// initialize test array 1 with 2 random doubles
for (int i = 0; i < 2; i++)
test3[i] = rand() / (double) RAND_MAX;
// test array 1
printf("First Test\n");
// print original array
printf("%10s: ", "Original");
for (int i = 0; i < 9; i++)
printf("%5.2f ", test1[i]);
putchar('\n');
//print reversed array
reverse_array(test1, 9);
printf("%10s: ", "Reversed");
for (int i = 0; i < 9; i++)
printf("%5.2f ", test1[i]);
putchar('\n');
// test array 2
printf("Second Test\n");
// print original array
printf("%10s: ", "Original");
for (int i = 0; i < 10; i++)
printf("%5.2f ", test2[i]);
putchar('\n');
//print reversed array
reverse_array(test2, 10);
printf("%10s: ", "Reversed");
for (int i = 0; i < 10; i++)
printf("%5.2f ", test2[i]);
putchar('\n');
// test array 3
printf("Third Test\n");
// print original array
printf("%10s: ", "Original");
for (int i = 0; i < 2; i++)
printf("%5.2f ", test3[i]);
putchar('\n');
//print reversed array
reverse_array(test3, 2);
printf("%10s: ", "Reversed");
for (int i = 0; i < 2; i++)
printf("%5.2f ", test3[i]);
putchar('\n');
return 0;
}
void reverse_array(double *arr, int arr_size)
{
// reverse an array of double
double tmp;
for (int i = 0; i < arr_size / 2; i++)
{
// swap values between indexes i and (arr_size - 1 - i)
tmp = arr[i];
arr[i] = arr[arr_size - 1 - i];
arr[arr_size - 1 - i] = tmp;
}
}使用编程练习2中的拷贝函数,把一个内含7个元素的数组中第3~第5个元素拷贝至内含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#include <stdio.h>
void copy_ptrs(double *target, double *source_start, double *source_end);
int main(void)
{
double source[7] = {2.4, 5.9, 7.8, 1.5, 3.3, 5.3, 6.8};
double target[3];
copy_ptrs(target, source + 2, source + 5);
// print arrays
for (int i = 0; i < 7; i++)
printf("%.1f ", source[i]);
putchar('\n');
for (int i = 0; i < 3; i++)
printf("%.1f ", target[i]);
putchar('\n');
return 0;
}
void copy_ptrs(double *target, double *source_start, double *source_end)
{
// copy arr using pointer notation and pointer endpoint
for (double *ptr = source_start; ptr < source_end; ptr++, target++)
*target = *ptr;
}编写一个程序,初始化一个double类型的3×5二维数组,使用一个处理变长数组的函数将其拷贝至另一个二维数组中。还要编写一个以变长数组为形参的函数以显示两个数组的内容。这两个函数应该能处理任意N×M数组。
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49#include <stdio.h>
#define ROWS 3
#define COLUMNS 5
void copy_2dim_arr(int rows, int cols, double source[rows][cols], double target[rows][cols]);
void print_2dim_arr(int rows, int cols, double arr[rows][cols]);
int main() {
double array1[ROWS][COLUMNS] = {
{4.3, 5.7, 2.1, 6.6, .8},
{5.6, 23.5, 73.2, 12.3, 123},
{22.1, 35.3, 6.35, 0.132, 11.1}
};
double array2[ROWS][COLUMNS];
// copy array1 to array2
copy_2dim_arr(ROWS, COLUMNS, array1, array2);
// print contents of arrays
printf("Array 1:\n");
print_2dim_arr(ROWS, COLUMNS, array1);
putchar('\n');
printf("Array2:\n");
print_2dim_arr(ROWS, COLUMNS, array2);
return 0;
}
void copy_2dim_arr(int rows, int cols, double source[rows][cols], double target[rows][cols])
{
// copy one two-dimensional array to another
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++)
target[i][j] = source[i][j];
}
}
void print_2dim_arr(int rows, int cols, double arr[rows][cols])
{
//print the contents of a two-dimensional array
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++)
printf(" %10.3f ", arr[i][j]);
putchar('\n');
}
}编写一个函数,把两个数组中相对应的元素相加,然后把结果储存到第 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
32
33
34
35
36
37
38
39#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SIZE 10
void add_arrays(int *addend1, int *addend2, int *sum, int array_length);
int main() {
//test add_arrays
srand(time(NULL));
int array1[SIZE];
int array2[SIZE];
int sum[SIZE];
// initialize arrays with random ints
for (int i = 0; i < SIZE; i++)
{
array1[i] = rand() % 20;
array2[i] = rand() % 20;
}
// get sum of arrays
add_arrays(array1, array2, sum, SIZE);
//print arrays
printf("%8s %8s %8s\n", "Array 1", "Array 2", "Sum");
for (int i = 0; i < SIZE; i++)
printf("%8d %8d %8d\n", array1[i], array2[i], sum[i]);
return 0;
}
void add_arrays(int *addend1, int *addend2, int *sum, int array_length)
{
// calculate elementwise sum of two arrays
for (int *tar = sum; tar < sum + array_length; tar++, addend1++, addend2++)
*tar = *addend1 + *addend2;
}编写一个程序,提示用户输入3组数,每组数包含5个double类型的数(假设用户都正确地响应,不会输入非数值数据)。该程序应完成下列任
务。
a.把用户输入的数据储存在3×5的数组中
b.计算每组(5个)数据的平均值
c.计算所有数据的平均值
d.找出这15个数据中的最大值
e.打印结果
每个任务都要用单独的函数来完成(使用变长数组作为函数形参的方式)。完成任务b,要编写一个计算并返回一维数组平均值的函数,利用循环调用该函数3次。对于处理其他任务的函数,应该把整个数组作为参数,完成任务c和d的函数应把结果返回主调函数。
1 | #include <stdio.h> |
- 编写一个函数,读入10个字符串或者读到EOF时停止。该程序为用户提供一个有5个选项的菜单:打印源字符串列表、以ASCII中的顺序打印字
符串、按长度递增顺序打印字符串、按字符串中第1个单词的长度打印字符串、退出。菜单可以循环显示,除非用户选择退出选项。当然,该程序要能真正完成菜单中各选项的功能。
1 | #include <stdio.h> |
- 编写一个通过命令行运行的程序计算幂。第1个命令行参数是double类型的数,作为幂的底数,第2个参数是整数,作为幂的指数。
1 | #include <stdio.h> |
- 编写一个程序,生成1000个1~10范围内的随机数。不用保存或打印这些数字,仅打印每个数出现的次数。用 10 个不同的种子值运行,生成的
数字出现的次数是否相同?可以使用本章自定义的函数或ANSI C的rand()和srand()函数,它们的格式相同。这是一个测试特定随机数生成器随机性的方法。
1 | #include <stdio.h> |
- 编写一个符合以下描述的函数。首先,询问用户需要输入多少个单词。然后,接收用户输入的单词,并显示出来,使用malloc()并回答第1个问
题(即要输入多少个单词),创建一个动态数组,该数组内含相应的指向char的指针(注意,由于数组的每个元素都是指向char的指针,所以用于储
存malloc()返回值的指针应该是一个指向指针的指针,且它所指向的指针指向char)。在读取字符串时,该程序应该把单词读入一个临时的char数组,使用malloc()分配足够的存储空间来储存单词,并把地址存入该指针数组(该数组中每个元素都是指向 char 的指针)。然后,从临时数组中把单词拷贝到动态分配的存储空间中。因此,有一个字符指针数组,每个指针都指向一个对象,该对象的大小正好能容纳被储存的特定单词。下面是该程序的一个运行示例:
How many words do you wish to enter? 5
Enter 5 words now:
I enjoyed doing this exerise
Here are your words:
I
enjoyed
doing
this
exercise
1 | #include <stdio.h> |
复习题
假设在测试程序时要暂时跳过一块代码,如何在不移除这块代码的前提下完成这项任务?
使用条件编译指令。一种方法是使用#ifndef
:
1 | #define _SKIP_ /* 如果不需要跳过代码,则删除这条指令 */ |