这一章在干嘛?

按头文件分逛标准库:stdlib/math 的数值函数、time 时间、setjmp 非本地跳转、signal 信号、assert 断言、qsort/bsearch 排序查找。不求背,求「知道有这个东西」。

16.1 整型与浮点函数:stdlib.h / math.h

16.2 时间与随机数:time.h

16.3 非本地跳转、信号与断言

16.4 qsort 与 bsearch:标准排序查找

16.1 整型与浮点函数:stdlib.h / math.h

头文件函数一句话
stdlib.habs / labs / div绝对值 / 商+余数一次算
stdlib.hrand / srand伪随机数:rand 返回 0~RAND_MAX,srand 设种子(不设每次运行同序列)
stdlib.hstrtol / strtod字符串转数值的严谨版:能报错、能拿「没读完的尾巴」
math.hsin/cos/tan、exp/log/log10、pow/fabs/floor/ceil/fmod三角、指数对数、幂、取整;参数和返回都是 double
/* strtol 优于 atoi:能检测「根本不是数字」和「溢出」 */
char *end;
errno = 0;
long v = strtol("123xyz", &end, 10);
if (end == "123xyz")        /* 一个字符都没转 */
    fprintf(stderr, "不是数字\n");
else if (*end != '\0')      /* 123 读到了,后面剩 xyz */
    fprintf(stderr, "尾巴:%s\n", end);

16.2 时间与随机数:time.h

clock_t c0 = clock();          /* 处理器时间(测耗时) */
do_work();
double sec = (double)(clock() - c0) / CLOCKS_PER_SEC;

time_t now = time(NULL);       /* 当天时间:从纪元起的秒数 */
struct tm *t = localtime(&now);
printf("%04d-%02d-%02d %02d:%02d:%02d\n",
       t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
       t->tm_hour, t->tm_min, t->tm_sec);

char buf[64];
strftime(buf, sizeof buf, "%Y-%m-%d %H:%M:%S", t);  /* 格式化时间 */
puts(buf);

两套时钟:clock() 测「程序用了多少 CPU 时间」,time() 给「墙上的钟」。测性能用前者,打日志用后者。struct tm 的年份从 1900 数、月份从 0 数——两个经典 off-by-one。

16.3 非本地跳转、信号与断言

/* setjmp/longjmp:跨函数「弹射」,错误处理的前身 */
jmp_buf env;

void deep(void)
{
    longjmp(env, 1);           /* 直接弹回 setjmp 处,跳过所有中间层 */
}

int main(void)
{
    if (setjmp(env) == 0)      /* 首次调用返回 0:正常流程 */
        deep();
    else                       /* longjmp 弹回后返回 1:错误流程 */
        puts("从深处逃出来了");
}
/* signal:异步事件(Ctrl+C 等)的处理钩子 */
void on_int(int sig) { (void)sig; exit(0); }
signal(SIGINT, on_int);        /* SIGFPE 算术错误 / SIGSEGV 段违例 ... */

/* assert:调试期契约检查,发布版 #define NDEBUG 一键关闭 */
assert(p != NULL && "指针不能为空");   /* 失败即打印位置并终止 */

setjmp 的限制:

弹回时中间函数的局部变量不可依赖(已销毁);volatile 修饰的局部变量才能保证值留存。signal 处理器内只做「设标志 + 返回」,别在里面干重活。

16.4 qsort 与 bsearch:标准排序查找

static int cmp_int(const void *a, const void *b)
{
    int x = *(const int *)a, y = *(const int *)b;
    return (x > y) - (x < y);
}

int arr[] = { 5, 3, 9, 1, 7 };
qsort(arr, 5, sizeof arr[0], cmp_int);          /* 快排:任意类型 */

int key = 7;
int *hit = bsearch(&key, arr, 5, sizeof arr[0], cmp_int);
if (hit)
    printf("找到了:%d\n", *hit);

两者共用同一套「元素比较函数」约定:返回负/零/正。bsearch 要求已排序——先 qsort 再 bsearch 是固定组合。比较函数写 (x>y)-(x<y) 而不是 x-y,可避免极端差值溢出。

本章通关标准:

转换字符串数值优先想到 strtol 而不是 atoi;记住 struct tm 的年月偏移;会用 qsort + 自定义比较函数排任意结构体数组。