经典习题

  1. 编写一个程序,要求用户输入一个华氏温度。程序应读取double类型的值作为温度值,并把该值作为参数传递给一个用户自定义的函数Temperatures()。该函数计算摄氏温度和开氏温度,并以小数点后面两位数字的精度显示3种温度。要使用不同的温标来表示这3个温度值。下面是华氏温度转摄氏温度的公式:
    摄氏温度 = 5.0 / 9.0 * (华氏温度 - 32.0)
    开氏温标常用于科学研究,0表示绝对零,代表最低的温度。下面是摄氏温度转开氏温度的公式:
    开氏温度 = 摄氏温度 + 273.16
    Temperatures()函数中用const创建温度转换中使用的变量。在main()函数中使用一个循环让用户重复输入温度,当用户输入 q 或其他非数字时,循环结束。scanf()函数返回读取数据的数量,所以如果读取数字则返回1,如果读取q则不返回1。可以使用==运算符将scanf()的返回值和1作比较,测试两值是否相等。
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 Temperatures(double fahrenheit);

int main() {
double fahrenheit;
printf("This program converts fahrenheit to celsius and kelvin.\n");
printf("Enter a temperature in dgrees fahrenheit (q to quit):");
while(scanf("%lf", &fahrenheit) == 1) // continue executing loop if user enters valid number
{
Temperatures(fahrenheit); // convert fahrenheit to celsius and kelvin

//prompt for new input
printf("Enter a temperatures in degrees fahrenheit (q to quit):");
}
printf("Bye!\n");
}

void Temperatures(double fahrenheit){
const double FAHR_TO_CEL_SCALE = 5.0 / 9.0;
const double FAHR_TO_OFFSET = -32.0;
const double CEL_TO_KEL_OFFSET = 273.16;

double celsius = (fahrenheit + FAHR_TO_OFFSET) * FAHR_TO_CEL_SCALE;
double kelvin = celsius + CEL_TO_KEL_OFFSET;

printf("%.2f degrees fahrenheit is %.2f degrees celsius or %.2f degrees kelvin.\n",
fahrenheit, celsius, kelvin);

}
  1. 编写一个程序,创建一个包含26个元素的数组,并在其中储存26个小写字母。然后打印数组的所有内容。
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
#define SIZE 26
int main(void){
char alphabet[SIZE];
for (char index='a';index<'a' + SIZE;index++)
alphabet[index-'a']= index;
for (int index = 0; index < SIZE; index++)
printf("%c ", alphabet[index]);
return 0;
};

  1. 编写一个程序,提示用户输入大写字母。使用嵌套循环以下面金字塔型的格式打印字母:
    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(" ");
    }
    }
  2. 考虑下面两个无限序列:
    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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>

int main() {
long int limit;
float sign = 1.0f;
float series1 = 0, series2 = 0;

printf("Enter a number of terms to sum:");
scanf("%ld", &limit);

for (double i = 1; i <= limit; i++)
{
series1 += 1.0f/i;
series2 += (1.0f/i) * sign;
sign = -sign; // toggle sign
}

printf("The %ldth partial sum for series 1 is: %.5f\n", limit, series1);
printf("The %ldth partial sum for series 2 is: %.5f\n", limit, series2);

//Answer: Series 1 has no limit. Series 2 appears to be bouned above
return 0;
}
  1. 编写一个程序,创建两个包含8个元素的double类型数组,使用循环提示用户为第一个数组输入8 个值。第二个数组元素的值设置为第一个数组对应元素的累积之和。例如,第二个数组的第 4个元素的值是第一个数组前4个元素之和,第二个数组的第5个元素的值是第一个数组前5个元素之和(用嵌套循环可以完成,但是利用第二个数组的第5个元素是第二个数组的第4个元素与第一个数组的第5个元素之和,只用一个循环就能完成任务,不需要使用嵌套循环)。最后,使用循环显示两个数组的内容,第一个数组显示成一行,第二个数组显示在第一个数组的下一行,而且每个元素都与第一个数组各元素相对应。
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
#include <stdio.h>

int main() {
int array[8], cumulative_sum[8];
int sum = 0;

printf("Enter 8 integers:\n");
for (int i = 0; i < 8; i++)
{
scanf("%d",&array[i]);
sum += array[i];
cumulative_sum[i] = sum;
}
//display loops
printf("Integers: ");
for (int i = 0; i < 8; i++)
{
printf("%6d ", array[i]);
}
printf("\n");
printf("Cumulative sum:");
for (int i = 0; i < 8; i++)
{
printf("%6d ", cumulative_sum[i]);
}
printf("\n");
return 0;
}
  1. 编写一个程序,读取一行输入,然后把输入的内容倒序打印出来。可以把输入储存在char类型的数组中,假设每行字符不超过255。回忆一下,根据%c转换说明,scanf()函数一次只能从输入中读取一个字符,而且在用户按下Enter键时scanf()函数会生成一个换行字符(\n)。
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main() {
char line[255];
int i = 0; // array
printf("Enter a line to reerse:\n");
while (scanf("%c", &line[i]), line[i] != '\n')
i++;
for (; 0 <= i; i--) //previous loop leaves i in right postion
printf("%c", line[i]);
return 0;
}
  1. 编写一个统计单词数量的程序(即,该程序读取并报告单词的数量)。该程序还可以计算字符数和行数。
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
// wordcnt.c -- 统计字符数、单词数、行数
#include <stdio.h>
#include <ctype.h> //为isspace()函数提供原型
#include <stdbool.h> //为bool、true、false提供定义
#define STOP '|'
int main() {
char c; //读入字符
char prev; //读入的前一个字符
long n_chars = 0L; //字符数
int n_lines = 0; //行数
int n_words = 0; //单词数
int p_lines = 0; //不完整的行数
bool inword = false; //如果c在单词中,inword等于true
printf("Enter text to be analyzed (| to terminate):\n");
prev = '\n'; //用于识别完整的行
while ((c = getchar()) != STOP)
{
n_chars++; //统计字符
if(c == '\n')
n_lines++; //统计行
if (!isspace(c) && !inword)
{
inword = true; //开始一个新的单词
n_words++; //统计单词
}
if(isspace(c) && inword)
inword = false; //打到单词的末尾
prev = c; //保存字符的值
}
if(prev != '\n')
p_lines = 1;
printf("characters = %ld, words = %d, lines = %d,",
n_chars, n_words, n_lines);
printf("partial lines = %d\n", p_lines);
return 0;
}
  1. 编写程序读取输入,读到#停止,报告ei出现的次数。
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
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>

#define STOP '#'

int main(void)
{
char ch;
unsigned int ei_count = 0;
bool e_flag = false;

printf("This program reads input and counts the number of times the\n"
"sequence 'ei' occurs (case insensitive).\n");
printf("Enter input (%c to stop):\n", STOP);

while ((ch = getchar()) != STOP)
{
ch = tolower(ch);
if (ch == 'e')
e_flag = true;
else if (ch == 'i')
{
if (e_flag)
ei_count++;
e_flag = false;
}
else
e_flag = false;

}

printf("The sequence 'ei' occurs %u times.\n", ei_count);

return 0;
}
  1. 编写一个程序,提示用户输入一周工作的小时数,然后打印工资总额、税金和净收入。做如下假设:
    a.加班(超过40小时) = 1.5倍的时间
    b.税率: 前300美元为15%
    续150美元为20%
    余下的为25%

让程序可以给出一个供选择的工资等级菜单。使用switch完成工资等级选择。运行程序后,显示的菜单应该类似这样:

1
2
3
4
5
6
*****************************************************************
Enter the number corresponding to the desired pay rate or action:
1) $8.75/hr 2) $9.33/hr
2) $10.00/hr 4) $11.20/hr
3) quit
*****************************************************************

如果选择 1~4 其中的一个数字,程序应该询问用户工作的小时数。程序要通过循环运行,除非用户输入 5。如果输入 1~5 以外的数字,程序应提醒用户输入正确的选项,然后再重复显示菜单提示用户输入。使用#define创建符号常量表示各工资等级和税率。

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
97
98
99
100
101
102
103
104
#include <stdio.h>
#include <stdbool.h>

#define RATE_1 8.75
#define RATE_2 9.33
#define RATE_3 10.00
#define RATE_4 11.20

#define OVERTIME_HOURS 40.0
#define OVERTIME_MULTIPLIER 1.5
#define TAX_RATE_1 0.15
#define TAX_BRACKET_1 300.0
#define TAX_RATE_2 0.20
#define TAX_BRACKET_2 450.0
#define TAX_RATE_3 0.25

void flush_input_buffer(void);
float calculate_gross_pay(float hours, float rate);
float calulate_taxes(float gross_pay);

int main() {
bool exit_flag = false;
int rate_option;
double rate, hours, gross_pay, taxes,net_pay;

while (1) {
printf("*****************************************************************\n");
printf("Enter the number corresponding to the desired pay rate or action:\n");
printf("1) $8.75/hr 2) $9.33/hr\n");
printf("3) $10.00/hr 4) $11.20/hr\n");
printf("5) quit\n");
printf("*****************************************************************\n");

scanf("%d", &rate_option);
switch (rate_option)
{
case 1:
rate = RATE_1;
break;
case 2:
rate = RATE_2;
break;
case 3:
rate = RATE_3;
break;
case 4:
rate = RATE_4;
break;
case 5:
exit_flag = true;
break;
default: //invalid input
flush_input_buffer();
printf("please enter an integer between 1 and 5.\n");
continue; // repeat main program loop
}

if (exit_flag)
break; //exit program

printf("Enter the number of hours worked in a week:");
while (scanf("%lf", &hours) != 1 || hours <= 0)
{
flush_input_buffer();
printf("please enter a positive number.\n");
printf("Enter number of hours worked in a week:");
}

gross_pay = calculate_gross_pay(hours, rate);
taxes = calulate_taxes(gross_pay);
net_pay = gross_pay - taxes;

printf("Gross pay: $%.2f\n", gross_pay);
printf("Taxes pay: $%.2f\n", taxes);
printf("Net pay: $%.2f\n", net_pay);

}
printf("Bye.\n");
return 0;
}

void flush_input_buffer(void)
{
while (getchar() != '\n')
;
}

float calculate_gross_pay(float hours, float rate)
{
if (hours > OVERTIME_HOURS)
return OVERTIME_HOURS * rate + (hours - OVERTIME_HOURS) * rate * OVERTIME_MULTIPLIER;
else
return hours * rate;
}

float calulate_taxes(float gross_pay)
{
if (gross_pay > TAX_BRACKET_2)
return TAX_RATE_3 * (gross_pay - TAX_BRACKET_2) + TAX_RATE_2 * (TAX_BRACKET_2 - TAX_BRACKET_1) + TAX_RATE_1 * TAX_BRACKET_1;
else if (gross_pay > TAX_BRACKET_1)
return TAX_RATE_2 * (gross_pay - TAX_BRACKET_1) + TAX_RATE_1 * TAX_BRACKET_1;
else
return TAX_RATE_1 * gross_pay;
}
  1. 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
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <stdio.h>
#include <stdbool.h>

#define ARTICHOKE_PRICE_PER_LB 2.05
#define BEET_PRICE_PER_LB 1.15
#define CARROT_PRICE_PER_LB 1.09

#define TRANSPORT_5LB 6.50
#define TRANSPORT_20LB 14.00
#define TRANSPORT_OVER_20_RATE 0.5

#define DISCOUNT_RATE 0.05

void flush_input_buffer(void);
float calculate_transport(float weight);

int main() {
float artichokeWeight = 0, beetWeight = 0, carrotWeight = 0, totalWeight;
float artichokePrice, beetPrice, carrotPrice, subtotal, discount, transport, total;
bool discount_flag;
float weight;
char option;

while (1){
printf("What would you like to order?\n");
printf("a) artichoke b) beet c) carrot q) quit\n");
option = getchar();
switch(option)
{
case ('q'):
printf("Bye.\n");
return 0; //exit program

case ('a'): //artichokes
printf("How many pound of artichokes would you like to add?");
if (scanf("%f", &weight) == 1)
artichokeWeight += weight;
else
{
flush_input_buffer();
printf("Invalid input. Try again.\n");
continue; //repeat main program loop
}
break;

case ('b'): //beets
printf("How many pounds of beets would you like to add?");
if (scanf("%f", &weight) == 1)
beetWeight += weight;
else
{
flush_input_buffer();
printf("Invalid input. Try again.\n");
continue; //repeat main program loop
}
break;

case ('c')://carrots
printf("How many pounds of carrots would you like to add?");
if (scanf("%f", &weight) == 1)
carrotWeight += weight;
else
{
flush_input_buffer();
printf("Invalid input. Try again.\n");
continue; //repeat main program loop
}
break;
default:
printf("Invalid input. Try again.\n");
continue; //repeat main program loop
}
//calculate subtotal
artichokePrice = artichokeWeight * ARTICHOKE_PRICE_PER_LB;
beetPrice = beetWeight * BEET_PRICE_PER_LB;
carrotWeight = carrotWeight * CARROT_PRICE_PER_LB;
subtotal = artichokePrice + beetPrice + carrotPrice;

//calculate discount
if (subtotal >= 100)
{
discount_flag = true;
discount = DISCOUNT_RATE * subtotal;
}
else
discount_flag = false;

//calulate transport
totalWeight = artichokeWeight + beetWeight + carrotWeight;
transport = calculate_transport(totalWeight);

//grand total
total = subtotal + transport - (discount_flag ? discount : 0.0);

printf("\n");
printf("Your order summary:\n\n");
printf("Artichokes: %.2flbs @ $.2f/lb: $%.2f\n",
artichokeWeight, ARTICHOKE_PRICE_PER_LB, artichokePrice);
printf("Beets: %.2flbs @ $.2f/lb: $%.2f\n",
beetWeight, BEET_PRICE_PER_LB, beetPrice);
printf("Carrots: %.2flbs @ $%.2f/lb: $%.2f\n",
carrotWeight, CARROT_PRICE_PER_LB, carrotPrice);
printf("\n");
printf("Subtotal: $%.2f\n", subtotal);
if (discount_flag)
printf("%.0f%% discount: $%.2f\n", DISCOUNT_RATE * 100, discount);
printf("Transport charges: $%.2f\n", transport);
printf("Grand total: $%.2f\n", total);
printf("\n");

flush_input_buffer();
}
return 0;
}

void flush_input_buffer(void)
{
while (getchar() != '\n');
}

float calculate_transport(float weight)
{
if (weight < 5.0)
return TRANSPORT_5LB;
else if (weight < 20.0)
return TRANSPORT_20LB;
else
return TRANSPORT_20LB + TRANSPORT_OVER_20_RATE * (weight - 20.0);
}
  1. 设计一个名为alter()的函数,接受两个int类型的变量x和y,把它们的值分别改成两个变量之和以及两变量之差。

使用指针

1
2
3
4
5
6
7
void alter(int * pa, int * pb)
{
int temp;
temp = *pa + *pb;
*pb = *pa - *pb;
*pa = temp;
}

** or **

1
2
3
4
5
void alter(int * pa, int * pb)
{
*pa += *pb;
*pb = *pa - 2 * *pb;
}
  1. power()函数返回一个double类型数的正整数次幂。改进该函数,使其能正确计算负幂。另外,函数要处理0的任何次幂
    都为0,任何数的0次幂都为1(函数应报告0的0次幂未定义,因此把该值处理为1)。使用递归函数并在程序中测试该函数。
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
#include <stdio.h>
#include <stdlib.h> //prototype for abs()

double power(double base, int exponent);

int main() {
double base, output;
int exponent;

printf("Test power() function:\n");
printf("Enter a :double: base and :int: exponent: ");
while (scanf("%lf %d", &base, &exponent) == 2)
{
output = power(base, exponent);

printf("%f ^ %d = %f \n", base, exponent, output);

printf("Enter a :double: base and :int: exponent: ");
}
return 0;
}

double power(double base, int exponent)
{
double dbl_power;

//handle powers of zero
if (base == 0)
{
if (exponent == 0)
{
printf("Warning: 0 ^ 0 is undefined. Using 1.\n");
return 1.0;
}
else
return 0;
}
if (exponent == 0) return 1; //stop recursion

dbl_power = base * power(base, abs(exponent) - 1); // recursion step

//if exponent is negative, take reciprocal
if (exponent < 0) dbl_power = 1 / dbl_power;

return dbl_power;
}
  1. 编写一个函数,返回储存在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;
    }
  2. 编写一个函数,把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;
    }
    }
  3. 使用编程练习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;
    }
  4. 编写一个程序,初始化一个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');
    }
    }
  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
    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;
    }
  6. 编写一个程序,提示用户输入3组数,每组数包含5个double类型的数(假设用户都正确地响应,不会输入非数值数据)。该程序应完成下列任
    务。
    a.把用户输入的数据储存在3×5的数组中
    b.计算每组(5个)数据的平均值
    c.计算所有数据的平均值
    d.找出这15个数据中的最大值
    e.打印结果
    每个任务都要用单独的函数来完成(使用变长数组作为函数形参的方式)。完成任务b,要编写一个计算并返回一维数组平均值的函数,利用循环调用该函数3次。对于处理其他任务的函数,应该把整个数组作为参数,完成任务c和d的函数应把结果返回主调函数。

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
#include <stdio.h>
#define ROWS 3
#define COLUMNS 5

void input_data(int rows, int columns, double array[][5]);
double compute_row_average(double *array, int cols);
double compute_array_average(int rows, int cols, double array[rows][cols]);
double largest_vlue(int rows, int cols, double array[rows][cols]);

int main() {
double data[ROWS][COLUMNS];

input_data(ROWS, COLUMNS, data);

//print row averages
printf("Row Averages:\n");
for (int i = 0; i < ROWS; i++)
{
printf("\t Average for row %d: %3.f\n", i + 1,
compute_row_average(data[i], COLUMNS));
}

//print array average
printf("Average for entire array: %.3f\n",
compute_array_average(ROWS,COLUMNS, data));

// print largest value
printf("Maximum array value: %.3f\n",
largest_vlue(ROWS, COLUMNS, data));

return 0;
}

void input_data(int rows, int columns, double array[][5])
{
printf("Enter 3 groups of 5 double values each:\n");
for (int i = 0; i < rows; i++)
{
printf("Grop %d:", i + 1);
for (int j = 0; j < columns; j++)
scanf("%lf", array[i] + j);
}
}

double compute_row_average(double *array, int cols)
{
double total = 0;
for (int i = 0; i < cols; i++)
total += array[i];

return total / cols;
}

double compute_array_average(int rows, int cols, double array[rows][cols])
{
double total = 0;
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
total += array[i][j];

return total / (rows * cols);
}

double largest_vlue(int rows, int cols, double array[rows][cols])
{
double max = array[0][0];
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
if (array[i][j] > max)
max = array[i][j];

return max;
}
  1. 编写一个函数,读入10个字符串或者读到EOF时停止。该程序为用户提供一个有5个选项的菜单:打印源字符串列表、以ASCII中的顺序打印字
    符串、按长度递增顺序打印字符串、按字符串中第1个单词的长度打印字符串、退出。菜单可以循环显示,除非用户选择退出选项。当然,该程序要能真正完成菜单中各选项的功能。
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define COUNT 10
#define LIMIT 50

void sort_ASCII(char *strings[], int n);
void sort_length(char *strings[], int n);
int fwlen(char *string);
void sort_firstword_length(char *strings[], int n);
char * get(char *string, int n);
void print_menu(void);

int main() {
char strings[COUNT][LIMIT];
char *strptrs[COUNT];
char * success;
char ch;

// initialize array of pointer
for (int i = 0; i < COUNT; i++)
strptrs[i] = strings[i];

printf("Enter up to 10 strings (EOF to stop): \n");

//read up to ten strings from input
for (int i = 0; i < COUNT; i++)
{
printf("%d: ", i + 1);
success = get(strings[i], LIMIT);

// if EOF encountered, stop reading strings
if (!success)
break;
}
printf("\n");

print_menu();
while((ch = getchar()) != 'q')
{
//discard rest of the line
if (ch != '\n')
while (getchar() != '\n')
continue;

// sort strings
switch (ch) {
case ('a'):
sort_ASCII(strptrs, COUNT);
break;
case ('l'):
sort_length(strptrs, COUNT);
break;
case ('f'):
sort_firstword_length(strptrs, COUNT);
break;
case ('o'):
break;
default:
printf("Invalid input. Try again.\n\n");
print_menu();
continue;
}
// print sorted strings
puts("");
for (int i = 0; i < COUNT; i++)
puts(strptrs[i]);

puts("");
print_menu();
}
puts("Bye");
return 0;
}

void sort_ASCII(char *strings[], int n)
{
// sort array of string pointers by ASCII collating sequence

char *tmp;

for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
{
if (strcmp(strings[i], strings[j]) > 0)
{
tmp = strings[i];
strings[i] = strings[j];
strings[j] = tmp;
}
}
}

void sort_length(char *strings[], int n)
{
// sort array of string pointer by length

char *tmp;

// 冒泡排序
for (int i = 0; i < n - 1; i++)
for (int j = i + 1; j < n; j++)
{
if (strlen(strings[i]) > strlen(strings[j]))
{
tmp = strings[i];
strings[i] = strings[j];
strings[j] = tmp;
}
}
}

int fwlen(char *string)
{
// return length of first word of string

int length = 0;

// skip leading whitespace
while (isspace(*string))
string++;

// count first word length
while (!isspace(*string))
{
length++;
string++;
}
return length;
}

void sort_firstword_length(char *strings[], int n)
{
// sort array of string pointers by ASCII collating sequence

char *tmp;

for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
{
if (fwlen(strings[i]) > fwlen(strings[j]))
{
tmp = strings[i];
strings[i] = strings[j];
strings[j] = tmp;
}
}
}

char * get(char *string, int n)
{
// wrapper for fgets that repalces first newline with null

char *ret_val = fgets(string, n, stdin);
while (*string != '\0')
{
if (*string == '\n')
*string = '\0';
string++;
}
return ret_val;
}

void print_menu(void)
{
puts("Choose an option: ");
puts("(o) Print strings in original order.");
puts("(a) Print strings in ASCII collating sequence.");
puts("(l) Print strings ordered by length.");
puts("(f) Print strings ordered by length of the first word.");
puts("(q) Quit.");
puts("");
puts("Enter a character: ");
}
  1. 编写一个通过命令行运行的程序计算幂。第1个命令行参数是double类型的数,作为幂的底数,第2个参数是整数,作为幂的指数。
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
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

void print_error_message(void);

int main(int argc, char *argv[]) {
double base;
long power;
char *end;

if (argc != 3)
{
print_error_message();
return 1;
}

// get exponent
end = argv[2];
while(*end != '\0')
end++;
power = strtol(argv[2], &end, 10);

if(*end) //error condition
{
print_error_message();
return 1;
} //strtol 函数会将 end 指向转换后的字符串的最后一个字符的下一个位置,通常是字符串的结束符 \0。

printf("%f ^ %ld = %f\n", base, power, pow(base, power));

return 0;
}

void print_error_message(void)
{
puts("Usage: <program_name> <arg1 base:double> <arg2 power:int>");
}
  1. 编写一个程序,生成1000个1~10范围内的随机数。不用保存或打印这些数字,仅打印每个数出现的次数。用 10 个不同的种子值运行,生成的
    数字出现的次数是否相同?可以使用本章自定义的函数或ANSI C的rand()和srand()函数,它们的格式相同。这是一个测试特定随机数生成器随机性的方法。
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
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define SIZE 1000
#define RANGE 10

void generate_random_numbers(void);

int main() {
for (int seed= 1; seed <= 10; seed++)
{
printf("Seed: %d\n", seed);
generate_random_numbers();
printf("\n");
}
return 0;
}

void generate_random_numbers(void)
{
srand((unsigned int) time(NULL)); // 设置种子值为当前时间

int counts[RANGE] = {0}; // 用于记录每个数字出现的次数

for (int i = 0; i < SIZE; i++)
{
int random_count = rand() % RANGE + 1; // 生成1~10范围内的随机数
counts[random_count - 1]++; // 更新对应数字出现次数的计数
}

// 打印每个数字出现的次数
for (int i = 0; i < RANGE; i++)
printf("Number %d: %d times\n", i + 1, counts[i]);
}
  1. 编写一个符合以下描述的函数。首先,询问用户需要输入多少个单词。然后,接收用户输入的单词,并显示出来,使用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
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_WORD_LENGTH 20 // 单词的最大长度

void get_words(int n);

int main(void) {
int num_words;

printf("How many words do you wish to enter?");
scanf("%d", &num_words);

while (getchar() != '\n')
continue; // 清楚输入缓冲区

if (num_words > 0)
get_words(num_words);
else
printf("No words to enter.\n");

return 0;
}

void get_words(int n)
{
char **words = (char **)malloc(n * sizeof(char *)); // 动态分配存储单词指针的数组
if (words == NULL)
{
fprintf(stderr, "Memory allocation failed. Exiting,\n");
exit(EXIT_FAILURE);
}

printf("Enter %d words now:\n", n);

for (int i = 0; i < n; i++)
{
char temp[MAX_WORD_LENGTH];
scanf("%s", temp); // 读取单词到临时数组中
words[i] = (char *) malloc((strlen(temp) + 1) * sizeof(char)); // 为单词分配存储空间
if (words[i] == NULL)
{
fprintf(stderr, "Memory allocation failed. Exiting.\n");
exit(EXIT_FAILURE);
}
strcpy(words[i], temp); // 复制单词到动态分配的存储空间中
}

printf("Here are your words:\n");
for (int i = 0; i < n; i++)
printf("%s\n", words[i]);

// 释放分配的内存
for (int i = 0; i < n; i++)
free(words[i]);
free(words);
}

复习题

假设在测试程序时要暂时跳过一块代码,如何在不移除这块代码的前提下完成这项任务?

使用条件编译指令。一种方法是使用#ifndef

1
2
3
4
5
6
#define _SKIP_      /* 如果不需要跳过代码,则删除这条指令 */
#ifndef _SKIP_

/* 需要跳过的代码 */

#endif