第 16 章 标准函数库
# 第 16 章 标准函数库
# 16.1 整型函数
书本内容
# 16.1.1 算术 <stdlib.h>
书本内容
笔记
abs
labs
div
ldiv
# 16.1.2 随机数 <stdlib.h>
书本内容
笔记
rand
srand
- 随机数发生器,一般用
time
取当前的时间作为参数
- 随机数发生器,一般用
# 16.1.3 字符串转换 <stdlib.h>
书本内容
将字符串转变为整型值
- 会跳过前导的空白字符和非法缀尾字符
atoi
- ASCII to integer
atol
strol
strtoul
# 16.2 浮点型函数
书本内容
定义域错误(domain error) 和范围错误 (range error)
EDOM
和ERANGE
# 16.2.1 三角函数 <math.h>
书本内容
用弧度来表示角度
sin
cos
tan
asin
acos
atan
atan2
# 16.2.2 双曲函数 <math.h>
书本内容
笔记
sinh
cosh
tanh
# 16.2.3 对数和指数函数 <math.h>
书本内容
笔记
exp
log
- 返回以
为底的对数 - 其它底的对数可以通过下式进行计算
- 返回以
log10
# 16.2.4 浮点表示形式 <math.h>
书本内容
笔记
- 用于在浮点格式不兼容的机器之间传递浮点数
frexp
ldexp
modf
# 16.2.5 幂 <math.h>
书本内容
笔记
power
sqrt
# 16.2.6 底数, 顶数, 绝对值和余数 <math.h>
书本内容
笔记
floor
ceil
fabs
fmod
# 16.2.7 字符串转换 <stdlib.h>
书本内容
笔记
atof
strtod
# 16.3 日期和时间函数
书本内容
# 16.3.1 处理器时间 <time.h>
书本内容
笔记
clock
# 16.3.2 当天时间 <time.h>
书本内容
笔记
time
ctime
difftime
# 16.4 非本地跳转 <setjmp.h>
书本内容
笔记
setjmp
longjmp
longjmp
的效果就是使得执行流通过两次从setjmp
函数返回,从而立即跳回到顶层函数中setjmp
第 1 次被调用时,返回 0- 再次被调用时,其返回值是
setjmp
的第 2 个参数
# 16.4.1 实例
书本内容
# 16.4.2 何时使用非本地跳转
书本内容
# 16.5 信号
书本内容
提示
- 参照 CSAPP 8.5 信号
# 16.5.1 信号名 <signal.h>
书本内容
# 16.5.2 处理信号 <signal.h>
书本内容
# 16.5.3 信号处理函数
书本内容
# 16.6 打印可变参数列表 <stdarg.h>
书本内容
笔记
vprintf
vfprintf
vsprintf
- 可变参数列表
# 16.7 执行环境
书本内容
# 16.7.1 终止执行 <stdlib.h>
书本内容
笔记
abort
atexit
exit
# 16.7.2 断言 <assert.h>
书本内容
笔记
assert
宏断言可以使用
-DNDEBUG
编译器命令行选项,或者在源文件中assert.h
文件被包含前增加下面的定义#define NDEBUG
1- 即可消除掉所有断言
# 16.7.3 环境 <stdlib.h>
书本内容
提示
- 具体可参照 CSAPP
# 16.7.4 执行系统命令 <stdlib.h>
书本内容
# 16.7.5 排序和查找 <stdlib.h>
书本内容
笔记
qsort
bsearch
# 16.8 locale
书本内容
# 16.8.1 数值和货币格式 <locale.h>
书本内容
# 16.8.2 字符串和 locale
<string.h>
书本内容
# 16.8.3 改变 locale
的效果
书本内容
# 16.9 总结
书本内容
# 16.12 问题
#
问题 1
答案
- 标准未定义这种情况下的返回值,为了程序的可移植性,应该尽量避免使用
#
问题 2
答案
- 基本上可以满足需求,因为其产生的数字序列之间没有明显的关系
#
问题 3
答案
- 如果编译器提供的随机数生成函数足够优秀,则其生成的是交替出现的 0,1 序列
#
问题 4
答案
测试函数如下
- 如果最终输出的
total_time
远小于 2,则说明使得的是 CPU 使用时间 - 否则,说明最终使用的是总流逝时间
- 如果最终输出的
代码
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <unistd.h> int main(void) { clock_t start_clock, end_clock; double total_time; start_clock = clock(); sleep(2); end_clock = clock(); total_time = ((double)end_clock - start_clock) / CLOCKS_PER_SEC; printf("start_clock = %ld, end_clock = %ld, total_time = %f\n", start_clock, end_clock, total_time); return EXIT_SUCCESS; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#
问题 5
答案
主要问题
time
和localtime
函数均需要一个指向time_t
的指针作为参数tm
结构中tm_mon
加上 1 才为实际的月份tm_year
为自 1900 之后的年数,当超过 1999 年后,需要取其最后两位
修改后的代码如下
代码
#include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) { struct tm *tm; time_t now; time(&now); tm = localtime(&now); printf("%d:%02d:%02d %d/%02d/%02d\n", tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_mon + 1, tm->tm_mday, tm->tm_year % 100); return EXIT_SUCCESS; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#
问题 6
答案
错误是使用
longjmp
函数时,set_buffer
函数已返回,setjmp
函数保存的当前函数的调用环境会失去作用此时,在
Linux x86-64
下的结果如下❯ gcc q6.c && ./a.out 2 2 2 plus 2 equals 4 [1] 381425 segmentation fault (core dumped) ./a.out 2 2
1
2
3
如果将对
set_buffer
函数的调用替换为setjmp(jbuf)
,则程序会陷入无限循环具体可参照 CSAPP 非本地跳转
代码
#include <setjmp.h> #include <stdio.h> #include <stdlib.h> jmp_buf jbuf; void set_buffer() { setjmp(jbuf); } int main(int argc, char **argv) { int a = atoi(argv[1]); int b = atoi(argv[2]); set_buffer(); // setjmp(jbuf); printf("%d plus %d equals %d\n", a, b, a + b); longjmp(jbuf, 1); printf("After longjmp\n"); return EXIT_SUCCESS; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#
问题 7
答案
检测程序如下
#include <setjmp.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> typedef void handler_t(int); jmp_buf buf; handler_t *Signal(int signum, handler_t *handler) { struct sigaction action, old_action; action.sa_handler = handler; sigemptyset(&action.sa_mask); /* block sigs of type being handled */ action.sa_flags = SA_RESTART; /* restart syscalls if possible */ if (sigaction(signum, &action, &old_action) < 0) exit(EXIT_FAILURE); return (old_action.sa_handler); } void sigfpe_handler(int sig) { longjmp(buf, 1); } int main(void) { int a; float b, c, d; Signal(SIGFPE, sigfpe_handler); switch (setjmp(buf)) { case 0: a = 1 / 0; printf("Integer division by zero doesn't result in SIGFPE signal\n"); break; case 1: printf("Integer division by zero results in SIGFPE signal\n"); break; default: break; } switch (setjmp(buf)) { case 0: b = 1.0 / 0.0; c = 0.0 / 0.0; d = -1.0 / 0.0; printf("Floating-point division by zero doesn't result in SIGFPE signal\n"); printf("1.0/0.0 = %f, 0.0/0.0 = %f -1.0/0.0 = %f\n", b, c, d); break; case 1: printf("Floating-point division by zero results in SIGFPE signal\n"); break; default: break; } return EXIT_SUCCESS; }
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在
gcc 11.1.0
下的运行结果如下Integer division by zero results in SIGFPE signal Floating-point division by zero doesn't result in SIGFPE signal 1.0/0.0 = inf, 0.0/0.0 = -nan -1.0/0.0 = -inf
1
2
3- 可以看出整数除 0, 会产生
SIGFPE
信号,而浮点数除 0,则不会产生SIGFPE
信号- 浮点除以 0,可能会产生
inf
,-inf
和-nan
- 与
IEE754
的定义相符
- 与
- 浮点除以 0,可能会产生
- 可以看出整数除 0, 会产生
不同的编译器,其结果会有所不同
在
clang 13.0.1
下编译运行,结果如下Integer division by zero doesn't result in SIGFPE signal Floating-point division by zero doesn't result in SIGFPE signal 1.0/0.0 = inf, 0.0/0.0 = nan -1.0/0.0 = -inf
1
2
3
提示
- 由于
SIGFPE
在Linux
下由系统进行处理,因此需要在handler
函数中使用longjmp
函数来清除掉产生的SIGFPE
信号- 不然会重复调用
sigfpe_handler
函数 - c-handle-signal-sigfpe-and-continue-execution (opens new window)
- 不然会重复调用
#
问题 8
答案
- 将会导致数组按照降序排列
# 16.13 编程练习
#
编程练习 1
答案
代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define BUFFER_SIZE 128 int main(int argc, char **argv) { int age; int radix; div_t res; if (argc != 2) { fputs("Usage: age_radix your-age\n", stderr); exit(EXIT_FAILURE); } age = atoi(argv[1]); for (radix = 2; radix <= 36; radix++) { res = div(age, radix); if (res.quot <= 2 && res.rem <= 9) break; } if (radix <= 36) { printf("Use radix %d when telling your age; %d in base %d is %d%d\n", radix, age, radix, res.quot, res.rem); return EXIT_SUCCESS; } else { printf("Sorry, even in base 36 your age is greater than 29!\n"); return EXIT_FAILURE; } }
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
提示
- 输入是 10 进制整数
- 按进制转换后,不能超过 2 位
- 而且第 2 位要小于2
- 且第 1 位不能超过 10
- 超过 10 后,无法用十进制进行表示
#
编程练习 2
答案
代码
#include <stdio.h> #include <stdlib.h> #include <time.h> #define MAX_OK_RAND ((int)((((long)RAND_MAX + 1) / 6) * 6 - 1)) int die() { static int is_seeded = 0; int value; if (!is_seeded) { is_seeded = 1; srand((unsigned int)time(NULL)); } do { value = rand(); } while (value > MAX_OK_RAND); return value % 6 + 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
提示
- 需要确保产生的随机数的最大值
MAX_OK_RAND % 6 == 5
才能保证产生的各个点数的概率是相同的
#
编程练习 3
答案
代码
#include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) { time_t now; struct tm *tm; int hour; int minute; time(&now); tm = localtime(&now); hour = tm->tm_hour; minute = tm->tm_min; if (minute >= 30) hour++; hour %= 12; if (hour == 0) hour = 12; minute += 2; minute /= 5; if (minute == 0) minute = 12; printf("The big hand is on the %d and the little hand is on the %d\n", hour, minute); return EXIT_SUCCESS; }
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
提示
- 需要注意时钟的格式,并将分针也转换为 1 ~ 12 的范围
- 0 点和 12 点重合
- 指针超过一半则指向下一个数值
- 时钟格式
#
编程练习 4
答案
代码
#include <stdio.h> #include <stdlib.h> #include <time.h> char *day[] = {"日", "一", "二", "三", "四", "五", "六"}; int main(int argc, char **argv) { struct tm tm; if (argc != 4) { fputs("Usage: day_of_seek Month Day Year.\n", stderr); exit(EXIT_FAILURE); } tm.tm_sec = 1; tm.tm_min = 0; tm.tm_hour = 0; tm.tm_mday = atoi(argv[2]); tm.tm_mon = atoi(argv[1]) - 1; tm.tm_year = atol(argv[3]) - 1900; tm.tm_isdst = 0; mktime(&tm); printf("%04d 年 %02d 月 %02d 日是星期%s\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, day[tm.tm_wday]); return EXIT_SUCCESS; }
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
提示
- 为了消除歧义,
tm.tm_sec
选为 1 - 可以使用下列方法查看
time_t
的数据格式- what-is-time-t-ultimately-a-typedef-to (opens new window)
gcc-11.1.0 x86_64-pc-linux-gnu
下time_t
的格式为long
- 如果
time_t
是用int
,即 32 位表示的可以用下列代码查看如果
time_t
为int
时表示的日期范围#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <time.h> int main() { time_t int_max, int_min; int_max = INT_MAX; int_min = INT_MIN; fputs(asctime(gmtime(&int_max)), stdout); fputs(asctime(gmtime(&int_min)), stdout); return EXIT_SUCCESS; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16输出为
Tue Jan 19 03:14:07 2038 Fri Dec 13 20:45:52 1901
1
2即从 1901 年 12 月 13 号至 2038 年 1 月 19 号(即 2038 问题)
- 如果
time_t
用long
,即 64 位表示,则理论上,其可表示的年限至少为- 假设一年有 365 天
- 但由于
struct tm
中的tm.tm_year
是用int
表示的,为了防止其溢出,对应于输入的年份应在至 之间 - 即
-2147481748 ~ 2147485547
之间
- 即
mktime
和ctime
默认转换的均是本地时间
#
编程练习 5
答案
代码
#include <math.h> #include <stdio.h> #include <stdlib.h> #define A 10.45 #define B 10 #define C -1 #define X 1.78816 double wind_chill(double temp, double velocity) { return 33 - (A + B * sqrt(velocity) + C * velocity) * (33 - temp) / (A + B * sqrt(X) + C * X); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
提示
- 题目有点歧义,最终的风寒度为
33 - Windchill
- 引入
math.h
后,gcc
编译时需要加入-lm
选项
#
编程练习 6
答案
代码
#include <math.h> #include <stdio.h> #include <stdlib.h> double payment(double amount, double interest, int periods) { interest /= 1200; periods *= 12; amount = amount * interest / (1 - pow(1 + interest, -periods)); return floor(amount * 100 + 0.5) / 100; }
1
2
3
4
5
6
7
8
9
10
11
12
提示
- 输入是年利息,要转换为月利息
- 期限是年,要将其转换为月份数
- 注意四舍五入的技巧
#
编程练习 7
答案
参照参考答案,用宏定义的代码如下
#include <stdio.h> #include <stdlib.h> int frequency2[2]; int frequency3[3]; int frequency4[4]; int frequency5[5]; int frequency6[6]; int frequency7[7]; int frequency8[8]; int frequency9[9]; int frequency10[10]; int cycle2[2][2]; int cycle3[3][3]; int cycle4[4][4]; int cycle5[5][5]; int cycle6[6][6]; int cycle7[7][7]; int cycle8[8][8]; int cycle9[9][9]; int cycle10[10][10]; #define MAX_TIMES 10000 #define CHECK(number) \ remainder = x % number; \ frequency##number[remainder] += 1; \ cycle##number[remainder][last_x % number] += 1 #define PRINT_F(number) \ printf("\nFrequency of random numbers modulo %d\n", number); \ for (i = 0; i < number; i++) \ printf("%5d ", frequency##number[i]); \ printf("\n") #define PRINT_C(number) \ printf("\nCyclic frequency of random numbers modulo %d\n", number); \ for (i = 0; i < number; i++) \ { \ for (j = 0; j < number; j++) \ printf("%5d ", cycle##number[i][j]); \ printf("\n"); \ } int main(int argc, char **argv) { int remainder; int x; int last_x; int i; int j; if (argc > 1) srand(atoi(argv[1])); last_x = rand(); for (i = 0; i < MAX_TIMES; i++) { x = rand(); CHECK(2); CHECK(3); CHECK(4); CHECK(5); CHECK(6); CHECK(7); CHECK(8); CHECK(9); CHECK(10); last_x = x; } PRINT_F(2); PRINT_F(3); PRINT_F(4); PRINT_F(5); PRINT_F(6); PRINT_F(7); PRINT_F(8); PRINT_F(9); PRINT_F(10); PRINT_C(2); PRINT_C(3); PRINT_C(4); PRINT_C(5); PRINT_C(6); PRINT_C(7); PRINT_C(8); PRINT_C(9); PRINT_C(10); return EXIT_SUCCESS; }
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非宏定义的代码如下
#include <stdio.h> #include <stdlib.h> #define MAX_NUMBER 10 #define MAX_TIMES 10000 int main(int argc, char **argv) { int i; int j; int k; int x; int last_x; int remainder; if (argc > 1) srand(atoi(argv[1])); for (i = 2; i <= MAX_NUMBER; i++) { int frequency[i]; for (j = 0; j < i; j++) frequency[j] = 0; for (j = 0; j < MAX_TIMES; j++) { x = rand(); remainder = x % i; frequency[remainder] += 1; } printf("\nFrequency of random numbers modulo %d\n", i); for (j = 0; j < i; j++) printf("%5d ", frequency[j]); printf("\n"); } for (i = 2; i <= MAX_NUMBER; i++) { int cycle[i][i]; for (j = 0; j < i; j++) for (k = 0; k < i; k++) cycle[j][k] = 0; for (j = 0, last_x = rand(); j < MAX_TIMES; j++) { x = rand(); cycle[x % i][last_x % i] += 1; last_x = x; } printf("\nCyclic frequency of random numbers modulo %d\n", i); for (j = 0; j < i; j++) { for (k = 0; k < i; k++) printf("%5d ", cycle[j][k]); printf("\n"); } } }
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- 借助栈来储存数组,但是多次生成了随机数,与参考答案的逻辑不同
借助
malloc
预先分配数据结构,其实现代码如下#include <stdio.h> #include <stdlib.h> #define MAX_NUMBER 10 #define MAX_TIMES 10000 int **frequency; int ***cycle; void *Malloc(size_t size) { void *p; if ((p = malloc(size)) == NULL) { fprintf(stderr, "Malloc error.\n"); exit(EXIT_FAILURE); } return p; } void init_data_structure() { int i; int ii; int j; int k; frequency = Malloc((MAX_NUMBER - 1) * sizeof(*frequency)); cycle = Malloc((MAX_NUMBER - 1) * sizeof(*cycle)); for (i = 2; i <= MAX_NUMBER; i++) { ii = i - 2; frequency[ii] = Malloc(i * sizeof(**frequency)); cycle[ii] = Malloc(i * sizeof(**cycle)); for (j = 0; j < i; j++) { frequency[ii][j] = 0; cycle[ii][j] = Malloc(i * sizeof(***cycle)); for (k = 0; k < i; k++) cycle[ii][j][k] = 0; } } } void free_data_structure() { int i; int ii; int j; for (i = 2; i <= MAX_NUMBER; i++) { ii = i - 2; free(frequency[ii]); for (j = 0; j < i; j++) free(cycle[ii][j]); free(cycle[ii]); } free(frequency); frequency = NULL; free(cycle); cycle = NULL; } int main(int argc, char **argv) { int i; int ii; int j; int k; int x; int last_x; int remainder; if (argc > 1) srand(atoi(argv[1])); init_data_structure(); for (i = 2; i <= MAX_NUMBER; i++) { ii = i - 2; for (j = 0, last_x = rand(); j < MAX_TIMES; j++, last_x = x) { x = rand(); remainder = x % i; frequency[ii][remainder] += 1; cycle[ii][remainder][last_x % i] += 1; } } for (i = 2; i <= MAX_NUMBER; i++) { ii = i - 2; printf("\nFrequency of random numbers modulo %d\n", i); for (j = 0; j < i; j++) printf("%5d ", frequency[ii][j]); printf("\n"); } for (i = 2; i <= MAX_NUMBER; i++) { ii = i - 2; printf("\nCyclic frequency of random numbers modulo %d\n", i); for (j = 0; j < i; j++) { for (k = 0; k < i; k++) printf("%5d ", cycle[ii][j][k]); printf("\n"); } } free_data_structure(); }
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- 基本上与参考答案的逻辑相同
提示
- 宏定义的代码,将相关的数组定义为全局变量,其会储存到
.bss
段,其初始值会为 0 - 非宏定义的代码,声明的数组储存在栈上,需要将其初始化为 0
- 宏定义的代码时间代价较小,但是空间代价较高,非宏定义的代码正好相反
- 时空平衡的完美例子
- 非宏定义的代码拓展性较差
#
编程练习 8
答案
代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #define MAX_LINE 512 int main(void) { char buffer[MAX_LINE]; int members; long total; long age; char *bp; while(fgets(buffer, MAX_LINE, stdin) > 0){ members = 0; total = 0; bp = buffer; while((age = strtol(bp, &bp, 10)) > 0){ members += 1; total += age; } if(members <= 0) continue; printf("%5.2f: %s", (double)total / members, buffer); } return EXIT_SUCCESS; }
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输入
45 42 22 36 35 7 3 1 22 20
1
2
3输出
36.33: 45 42 22 16.40: 36 35 7 3 1 21.00: 22 20
1
2
3
提示
- 假定输入的年龄为大于 0 的整数,则没有其它非法字符
- 打印年龄时直接打印输入的字符串的即可
#
编程练习 9
答案
代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <assert.h> #define ONE_YEAR 365 #define MAX_OK_RAND ((int)((((long)RAND_MAX + 1) \ / ONE_YEAR) * ONE_YEAR - 1)) #define TRIALS 10000 int main(int argc, char **argv) { int *birthdays; int test; int i; int j; int match; long rand_number; int count; if(argc != 2){ printf("Usage: birthday n_student\n"); exit(EXIT_FAILURE); } int n_students; n_students = atoi(argv[1]); if(n_students < 2){ printf("n_student must greater than 1\n"); exit(EXIT_FAILURE); } srand(time(NULL)); birthdays = (int *)malloc(n_students * sizeof(int)); assert(birthdays != NULL); count = 0; for(test = 0; test < TRIALS; test++){ match = 0; for(i= 0; i < n_students && !match; i++){ do{ rand_number = rand(); }while(rand_number > MAX_OK_RAND); rand_number %= 365; for(j = 0; j < i && !match; j++){ if(birthdays[j] == rand_number){ match = 1; count++; } } birthdays[i] = rand_number; } } printf("The odd of any two people in a group of %d\n" "having the same birthday is %g%%\n", n_students, (double)count / TRIALS * 100); free(birthdays); return EXIT_SUCCESS; }
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
提示
为了保守估计,应该假设一年有 366 天
为了严格保证随机性,应确保
rand
产生非负随机数的最大值模 366 同余 365最终的结果如下,可得最终答案为 23 人
❯ ./birthday 30 The odd of any two people in a group of 30 having the same birthday is 70.13% ❯ ./birthday 23 The odd of any two people in a group of 23 having the same birthday is 51.14% ❯ ./birthday 22 The odd of any two people in a group of 22 having the same birthday is 46.73%
1
2
3
4
5
6
7
8
9
#
编程练习 10
答案
代码
#include <stdlib.h> #include <string.h> void insertion_sort(void *base, size_t n_element, size_t el_size, int (*compare)(void const *, void const *)) { void *i, *j; void *temp; temp = malloc(el_size); if(temp == NULL) exit(EXIT_FAILURE); for(i = base + el_size; i < base + el_size * n_element; i+= el_size){ memcpy(temp, i, el_size); for(j = i - el_size; j >= base; j-=el_size){ if(compare(j, temp) > 0) memcpy(j + el_size, j, el_size); else break; } memcpy(j + el_size, temp, el_size); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
提示
- 基本逻辑可以参照 CLRS 中的描述
编辑 (opens new window)
上次更新: 2022/03/07, 15:03:00