标准库
C 标准库提供了大量实用函数,涵盖输入输出、字符串处理、数学计算、内存管理等方面。熟练使用标准库可以大大提高开发效率。
输入输出库 stdio.h
文件操作
FILE* fopen(const char* filename, const char* mode); // 打开文件
int fclose(FILE* stream); // 关闭文件
int fflush(FILE* stream); // 刷新缓冲区
格式化输入输出
int printf(const char* format, ...); // 格式化输出到 stdout
int fprintf(FILE* stream, const char* format, ...); // 格式化输出到文件
int sprintf(char* str, const char* format, ...); // 格式化输出到字符串
int snprintf(char* str, size_t size, const char* format, ...); // 安全版本
int scanf(const char* format, ...); // 从 stdin 格式化输入
int fscanf(FILE* stream, const char* format, ...); // 从文件格式化输入
int sscanf(const char* str, const char* format, ...); // 从字符串格式化输入
格式说明符:
| 格式符 | 说明 |
|---|---|
%d | 有符号十进制整数 |
%u | 无符号十进制整数 |
%x | 十六进制(小写) |
%X | 十六进制(大写) |
%o | 八进制 |
%f | 浮点数 |
%e | 科学计数法 |
%c | 字符 |
%s | 字符串 |
%p | 指针 |
%zu | size_t |
%% | 百分号 |
字符输入输出
int fgetc(FILE* stream); // 从文件读取一个字符
int fputc(int ch, FILE* stream); // 向文件写入一个字符
char* fgets(char* str, int n, FILE* stream); // 从文件读取一行
int fputs(const char* str, FILE* stream); // 向文件写入字符串
二进制输入输出
size_t fread(void* ptr, size_t size, size_t count, FILE* stream);
size_t fwrite(const void* ptr, size_t size, size_t count, FILE* stream);
文件定位
int fseek(FILE* stream, long offset, int origin); // 设置文件位置
long ftell(FILE* stream); // 获取文件位置
void rewind(FILE* stream); // 重置到开头
int feof(FILE* stream); // 检查是否到达末尾
标准库 stdlib.h
内存管理
void* malloc(size_t size); // 分配内存
void* calloc(size_t n, size_t size); // 分配并初始化为 0
void* realloc(void* ptr, size_t size); // 重新分配
void free(void* ptr); // 释放内存
字符串转换
int atoi(const char* str); // 字符串转整数
long atol(const char* str); // 字符串转 long
double atof(const char* str); // 字符串转 double
long strtol(const char* str, char** endptr, int base); // 安全版本
double strtod(const char* str, char** endptr); // 安全版本
随机数
int rand(void); // 生成随机数(0 到 RAND_MAX)
void srand(unsigned int seed); // 设置随机种子
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
srand(time(NULL)); // 使用时间作为种子
for (int i = 0; i < 5; i++) {
printf("%d ", rand() % 100); // 0-99 的随机数
}
return 0;
}
程序控制
void exit(int status); // 正常终止程序
void abort(void); // 异常终止程序
int atexit(void (*func)(void)); // 注册退出函数
int system(const char* command); // 执行系统命令
void cleanup(void) {
printf("程序即将退出\n");
}
int main(void) {
atexit(cleanup); // 注册清理函数
printf("程序运行中...\n");
return 0; // 退出时自动调用 cleanup
}
排序与搜索
void qsort(void* base, size_t n, size_t size,
int (*compar)(const void*, const void*));
void* bsearch(const void* key, const void* base, size_t n, size_t size,
int (*compar)(const void*, const void*));
int compare_int(const void* a, const void* b) {
return *(int*)a - *(int*)b;
}
int main(void) {
int arr[] = {5, 2, 8, 1, 9, 3, 7, 4, 6};
int n = sizeof(arr) / sizeof(arr[0]);
qsort(arr, n, sizeof(int), compare_int);
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
int key = 5;
int* result = bsearch(&key, arr, n, sizeof(int), compare_int);
if (result != NULL) {
printf("找到: %d\n", *result);
}
return 0;
}
整数运算
int abs(int n); // 绝对值
long labs(long n);
div_t div(int numer, int denom); // 除法,返回商和余数
div_t result = div(17, 5);
printf("商: %d, 余数: %d\n", result.quot, result.rem); // 商: 3, 余数: 2
字符串库 string.h
字符串操作
size_t strlen(const char* str); // 字符串长度
char* strcpy(char* dest, const char* src); // 复制字符串
char* strncpy(char* dest, const char* src, size_t n); // 安全复制
char* strcat(char* dest, const char* src); // 连接字符串
char* strncpy(char* dest, const char* src, size_t n); // 安全连接
字符串比较
int strcmp(const char* s1, const char* s2); // 比较字符串
int strncmp(const char* s1, const char* s2, size_t n); // 比较前 n 个字符
返回值:小于 0(s1 < s2)、等于 0(相等)、大于 0(s1 > s2)。
字符串搜索
char* strchr(const char* str, int ch); // 查找字符(首次出现)
char* strrchr(const char* str, int ch); // 查找字符(最后出现)
char* strstr(const char* haystack, const char* needle); // 查找子串
char* strtok(char* str, const char* delim); // 分割字符串
char str[] = "Hello, World!";
char* p = strchr(str, 'o'); // "o, World!"
char* q = strstr(str, "World"); // "World!"
char text[] = "apple,banana,orange";
char* token = strtok(text, ",");
while (token != NULL) {
printf("%s\n", token);
token = strtok(NULL, ",");
}
内存操作
void* memcpy(void* dest, const void* src, size_t n); // 内存复制
void* memmove(void* dest, const void* src, size_t n); // 内存移动(允许重叠)
void* memset(void* str, int c, size_t n); // 设置内存
int memcmp(const void* s1, const void* s2, size_t n); // 内存比较
void* memchr(const void* str, int c, size_t n); // 内存搜索
int arr[10];
memset(arr, 0, sizeof(arr)); // 全部设置为 0
int src[] = {1, 2, 3, 4, 5};
int dst[5];
memcpy(dst, src, sizeof(src)); // 复制数组
字符处理库 ctype.h
字符分类
int isalpha(int c); // 是否字母
int isdigit(int c); // 是否数字
int isalnum(int c); // 是否字母或数字
int isspace(int c); // 是否空白字符
int isupper(int c); // 是否大写字母
int islower(int c); // 是否小写字母
int ispunct(int c); // 是否标点符号
int isprint(int c); // 是否可打印字符
int iscntrl(int c); // 是否控制字符
int isxdigit(int c); // 是否十六进制数字
字符转换
int toupper(int c); // 转大写
int tolower(int c); // 转小写
char str[] = "Hello, World!";
for (int i = 0; str[i] != '\0'; i++) {
str[i] = tolower(str[i]);
}
printf("%s\n", str); // hello, world!
// 统计字母数量
int letters = 0;
for (int i = 0; str[i] != '\0'; i++) {
if (isalpha(str[i])) {
letters++;
}
}
数学库 math.h
基本运算
double fabs(double x); // 绝对值
double fmod(double x, double y); // 取模
double pow(double x, double y); // 幂运算
double sqrt(double x); // 平方根
double cbrt(double x); // 立方根(C99)
取整函数
double ceil(double x); // 向上取整
double floor(double x); // 向下取整
double round(double x); // 四舍五入(C99)
double trunc(double x); // 截断小数(C99)
指数与对数
double exp(double x); // e^x
double log(double x); // 自然对数
double log10(double x); // 以 10 为底的对数
double log2(double x); // 以 2 为底的对数(C99)
三角函数
double sin(double x); // 正弦
double cos(double x); // 余弦
double tan(double x); // 正切
double asin(double x); // 反正弦
double acos(double x); // 反余弦
double atan(double x); // 反正切
double atan2(double y, double x); // 双参数反正切
其他函数
double hypot(double x, double y); // 斜边长度 sqrt(x² + y²)
double ldexp(double x, int exp); // x * 2^exp
double frexp(double x, int* exp); // 分解为尾数和指数
#include <math.h>
#include <stdio.h>
int main(void) {
printf("sqrt(16) = %f\n", sqrt(16)); // 4.0
printf("pow(2, 10) = %f\n", pow(2, 10)); // 1024.0
printf("ceil(3.2) = %f\n", ceil(3.2)); // 4.0
printf("floor(3.8) = %f\n", floor(3.8)); // 3.0
printf("round(3.5) = %f\n", round(3.5)); // 4.0
printf("fabs(-5.5) = %f\n", fabs(-5.5)); // 5.5
double angle = M_PI / 4; // 45 度
printf("sin(45°) = %f\n", sin(angle)); // 0.707...
printf("cos(45°) = %f\n", cos(angle)); // 0.707...
return 0;
}
时间库 time.h
时间类型
time_t // 日历时间类型
struct tm // 分解的时间结构
clock_t // 处理器时间类型
struct tm 成员:
| 成员 | 说明 | 范围 |
|---|---|---|
tm_sec | 秒 | 0-60 |
tm_min | 分 | 0-59 |
tm_hour | 时 | 0-23 |
tm_mday | 日 | 1-31 |
tm_mon | 月 | 0-11 |
tm_year | 年(从 1900 起) | |
tm_wday | 星期 | 0-6 |
tm_yday | 年内天数 | 0-365 |
tm_isdst | 夏令时标志 |
时间函数
time_t time(time_t* timer); // 获取当前时间
struct tm* localtime(const time_t* timer); // 转换为本地时间
struct tm* gmtime(const time_t* timer); // 转换为 UTC 时间
char* ctime(const time_t* timer); // 时间转字符串
char* asctime(const struct tm* tm); // tm 转字符串
time_t mktime(struct tm* tm); // tm 转 time_t
size_t strftime(char* str, size_t max, const char* format, const struct tm* tm); // 格式化时间
#include <time.h>
#include <stdio.h>
int main(void) {
time_t now = time(NULL);
printf("当前时间戳: %ld\n", now);
char* time_str = ctime(&now);
printf("ctime: %s", time_str);
struct tm* local = localtime(&now);
printf("年: %d\n", local->tm_year + 1900);
printf("月: %d\n", local->tm_mon + 1);
printf("日: %d\n", local->tm_mday);
char buffer[100];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", local);
printf("格式化: %s\n", buffer);
return 0;
}
计时
clock_t clock(void); // 获取处理器时间
double difftime(time_t end, time_t start); // 计算时间差
#include <time.h>
#include <stdio.h>
int main(void) {
clock_t start = clock();
// 执行一些操作
volatile long sum = 0;
for (long i = 0; i < 100000000; i++) {
sum += i;
}
clock_t end = clock();
double elapsed = (double)(end - start) / CLOCKS_PER_SEC;
printf("耗时: %.3f 秒\n", elapsed);
return 0;
}
断言库 assert.h
void assert(int expression); // 运行时断言
#include <assert.h>
void process(int* ptr, int size) {
assert(ptr != NULL);
assert(size > 0);
for (int i = 0; i < size; i++) {
ptr[i] = i * 2;
}
}
定义 NDEBUG 可以禁用断言:
#define NDEBUG
#include <assert.h> // 断言被禁用
布尔类型 stdbool.h(C99)
#define bool _Bool
#define true 1
#define false 0
#define __bool_true_false_are_defined 1
#include <stdbool.h>
bool is_even(int n) {
return n % 2 == 0;
}
int main(void) {
bool flag = true;
if (flag) {
printf("flag is true\n");
}
return 0;
}
固定宽度整数 stdint.h(C99)
int8_t // 8 位有符号整数
int16_t // 16 位有符号整数
int32_t // 32 位有符号整数
int64_t // 64 位有符号整数
uint8_t // 8 位无符号整数
uint16_t // 16 位无符号整数
uint32_t // 32 位无符号整数
uint64_t // 64 位无符号整数
intptr_t // 能容纳指针的整数
uintptr_t // 能容纳指针的无符号整数
#include <stdint.h>
#include <stdio.h>
int main(void) {
int32_t value = 2147483647;
uint64_t big_value = 18446744073709551615ULL;
printf("int32_t 大小: %zu\n", sizeof(int32_t)); // 4
printf("int64_t 大小: %zu\n", sizeof(int64_t)); // 8
return 0;
}
小结
本章介绍了 C 语言常用标准库:
<stdio.h>:输入输出<stdlib.h>:内存管理、随机数、排序搜索<string.h>:字符串和内存操作<ctype.h>:字符分类和转换<math.h>:数学函数<time.h>:时间日期<assert.h>:断言<stdbool.h>:布尔类型<stdint.h>:固定宽度整数
下一章将学习 知识速查表,提供快速参考。