Appearance
常用库函数速查
📌 关于代码:本文所有代码基于 C11 标准,使用
gcc -Wall -Wextra编译验证。📎 原始来源:本文为原创补充内容。
本文分类整理 C 标准库中最常用的函数,每个函数给出原型、说明和示例,方便随时查阅。
<stdio.h> — 输入/输出
printf — 格式化输出到标准输出
c
int printf(const char* format, ...);| 参数 | 说明 |
|---|---|
format | 格式字符串 |
... | 可变参数,按格式串中的占位符依次填入 |
返回值:成功返回打印的字符数,失败返回负数。
常见占位符:%d(int)、%f(double)、%c(char)、%s(string)、%p(指针)、%x(16进制)、%%(输出一个%)。
c
int age = 20;
double pi = 3.14159;
printf("年龄:%d,π约等于 %.2f\n", age, pi);
// 输出:年龄:20,π约等于 3.14scanf — 从标准输入格式化读取
c
int scanf(const char* format, ...);⚠️ 注意:变量前面必须加 &(取地址),除了数组名和 char*。
返回值:成功读取的项数,失败返回 EOF。
c
int a, b;
scanf("%d %d", &a, &b); // ⚠️ &a 和 &b 不能漏
printf("a=%d, b=%d\n", a, b);getchar — 读取一个字符
c
int getchar(void);返回值:读取的字符(作为 unsigned char 转为 int),或 EOF。
c
int c = getchar(); // 从键盘读一个字符
putchar(c); // 输出这个字符fopen / fclose — 打开/关闭文件
c
FILE* fopen(const char* filename, const char* mode);
int fclose(FILE* stream);mode 参数:
| 模式 | 含义 | 文件不存在时 |
|---|---|---|
"r" | 只读 | 返回 NULL |
"w" | 只写(会清空原文件) | 创建新文件 |
"a" | 追加写入 | 创建新文件 |
"rb" | 二进制只读 | 返回 NULL |
"wb" | 二进制只写 | 创建新文件 |
"ab" | 二进制追加 | 创建新文件 |
c
FILE* fp = fopen("test.txt", "w");
if (fp == NULL)
{
perror("fopen"); // 打印错误信息
return 1;
}
fprintf(fp, "Hello File!\n");
fclose(fp); // ⚠️ 用完必须 fclose,否则数据可能没写进去fprintf / fscanf — 文件版 printf / scanf
c
int fprintf(FILE* stream, const char* format, ...);
int fscanf(FILE* stream, const char* format, ...);和 printf/scanf 用法一样,只是多了第一个 FILE* 参数指定文件。
c
FILE* fp = fopen("data.txt", "w");
fprintf(fp, "%d %s\n", 42, "answer");
fclose(fp);fread / fwrite — 二进制读写
c
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);| 参数 | 说明 |
|---|---|
ptr | 数据存放位置(读)或来源(写) |
size | 每个元素的字节大小 |
count | 读写多少个元素 |
stream | 文件指针 |
返回值:实际读写的元素个数(可能小于 count,比如到文件末尾了)。
c
// 写一个结构体数组到文件
struct Person people[3] = { {"张三", 20}, {"李四", 21}, {"王五", 22} };
FILE* fp = fopen("data.bin", "wb");
fwrite(people, sizeof(struct Person), 3, fp);
fclose(fp);
// 再读回来
struct Person buf[3];
fp = fopen("data.bin", "rb");
int n = fread(buf, sizeof(struct Person), 3, fp);
printf("读取了 %d 个人的数据\n", n);
fclose(fp);<stdlib.h> — 通用工具
malloc — 动态申请内存
c
void* malloc(size_t size);| 参数 | 说明 |
|---|---|
size | 需要申请的字节数 |
返回值:成功返回指向新分配内存的指针(未初始化),失败返回 NULL。
c
// 申请 10 个 int 的空间
int* p = (int*)malloc(10 * sizeof(int));
if (p == NULL)
{
perror("malloc");
return 1;
}
// 使用 p...
free(p); // ⚠️ 用完必须 freefree — 释放动态内存
c
void free(void* ptr);| 参数 | 说明 |
|---|---|
ptr | 之前由 malloc/calloc/realloc 返回的指针(或 NULL) |
⚠️ 注意:
free(NULL)是安全的,什么也不做- 不要 free 两次同一块内存
- 不要 free 非
malloc分配的内存(比如栈变量) free之后建议把指针置NULL,避免野指针
c
int* p = (int*)malloc(sizeof(int));
free(p);
p = NULL; // ✅ 好习惯:置空防野指针calloc — 分配并清零
c
void* calloc(size_t num, size_t size);| 参数 | 说明 |
|---|---|
num | 元素个数 |
size | 每个元素的字节数 |
和 malloc(num * size) 等价,但自动清零所有字节为 0。
c
// 申请 10 个 int,初始都是 0
int* arr = (int*)calloc(10, sizeof(int));
// 等价于:int* arr = malloc(10*sizeof(int)); memset(arr, 0, 10*sizeof(int));realloc — 重新调整内存大小
c
void* realloc(void* ptr, size_t size);| 参数 | 说明 |
|---|---|
ptr | 原来的内存指针(可以是 NULL,此时等价于 malloc) |
size | 新的字节大小 |
返回值:新地址(可能和旧地址不同!)。必须接住返回值,不要直接 ptr = realloc(ptr, ...),万一 realloc 返回 NULL 就把旧指针丢了。
c
int* p = (int*)malloc(5 * sizeof(int));
// 扩容到 10 个
int* tmp = (int*)realloc(p, 10 * sizeof(int));
if (tmp == NULL)
{
// 扩容失败,p 还指向原来的内存
printf("扩容失败\n");
}
else
{
p = tmp; // 扩容成功,更新指针
}atoi — 字符串转整数
c
int atoi(const char* str);c
printf("%d\n", atoi("123")); // 123
printf("%d\n", atoi(" -42abc")); // -42(跳过空格,遇到非数字停止)exit — 终止程序
c
void exit(int status);| 参数 | 说明 |
|---|---|
status | 退出状态码,0 表示成功,非 0 表示异常 |
会自动执行 atexit 注册的清理函数,关闭所有文件。
c
if (something_wrong)
{
printf("出错了,退出\n");
exit(1); // 等同于 return 1 在 main 中
}system — 执行 shell 命令
c
int system(const char* command);c
system("cls"); // Windows 清屏
system("clear"); // Linux/Mac 清屏
system("pause"); // Windows 暂停显示 "按任意键继续..."
system("mode con cols=100 lines=30"); // 设置控制台大小<string.h> — 字符串和内存
strlen — 字符串长度
c
size_t strlen(const char* str);⚠️ 返回值是 size_t(无符号整数),注意和有符号数比较时可能有坑。
c
printf("%zu\n", strlen("Hello")); // 5(不含结尾的 \0)
printf("%zu\n", strlen("")); // 0strcpy — 字符串拷贝
c
char* strcpy(char* dest, const char* src);⚠️ 危险函数! 不检查目标缓冲区大小,可能越界溢出。推荐用 strncpy。
c
char buf[20];
strcpy(buf, "Hello World"); // ✅ 目标足够大
strcpy(buf, "这是一个非常非常非常长的字符串"); // ❌ 溢出!strcmp — 字符串比较
c
int strcmp(const char* s1, const char* s2);| 返回值 | 含义 |
|---|---|
< 0 | s1 < s2 |
== 0 | s1 == s2 |
> 0 | s1 > s2 |
按 ASCII 码字典序比较。
c
if (strcmp(name, "admin") == 0) // 注意:字符串比较用 strcmp,不能用 ==
{
printf("欢迎管理员!\n");
}strcat — 字符串追加
c
char* strcat(char* dest, const char* src);⚠️ 也不检查边界! 把 src 拼接到 dest 后面,覆盖 dest 原有的 \0。
c
char greeting[50] = "Hello, ";
strcat(greeting, "World!");
printf("%s\n", greeting); // Hello, World!memcpy — 内存拷贝
c
void* memcpy(void* dest, const void* src, size_t n);从 src 拷贝 n 字节到 dest。不能处理源和目标重叠的情况(比如数组内部移动),重叠时用 memmove。
c
int src[5] = {1, 2, 3, 4, 5};
int dest[5];
memcpy(dest, src, sizeof(src));
// dest 现在是 {1, 2, 3, 4, 5}memmove — 内存移动(可重叠)
c
void* memmove(void* dest, const void* src, size_t n);功能和 memcpy 一样,但源和目标可以重叠。
c
char str[] = "Hello World";
memmove(str + 6, str + 5, 6); // 把 " World" 向右移一位(重叠操作)
// str 变成 "Hello World"memset — 内存填充
c
void* memset(void* s, int c, size_t n);| 参数 | 说明 |
|---|---|
s | 要填充的内存起始地址 |
c | 要填充的字节值(int 但实际是 unsigned char) |
n | 填充多少字节 |
⚠️ 注意:memset 是逐字节填充!对 int 数组来说,memset(arr, 0, sizeof(arr)) 可以清零(因为 0 的所有字节都是 0),但 memset(arr, 1, sizeof(arr)) 并不能把每个 int 设成 1(而是每个字节设成 1,拼起来可能是 0x01010101)。
c
int arr[10];
memset(arr, 0, sizeof(arr)); // ✅ 把所有字节清零 → 每个 int 都是 0
char buf[100];
memset(buf, 'A', 99); // ✅ 字符数组可以正常用
buf[99] = '\0';<ctype.h> — 字符分类和转换
isdigit — 判断是否数字
c
int isdigit(int c);返回非零(真)如果是 '0' 到 '9'。
c
char ch = '7';
if (isdigit(ch))
printf("%c 是数字\n", ch);isalpha — 判断是否字母
c
int isalpha(int c);返回非零如果是 'a'-'z' 或 'A'-'Z'。
c
char ch = 'B';
if (isalpha(ch))
printf("%c 是字母\n", ch);isxdigit — 判断是否十六进制数字
c
int isxdigit(int c);包括 '0'-'9'、'a'-'f'、'A'-'F'。
isspace — 判断是否空白字符
c
int isspace(int c);包括空格、\t、\n、\r、\f、\v。
tolower — 转小写
c
int tolower(int c);如果是大写字母,返回对应的小写;否则原样返回。
c
printf("%c\n", tolower('A')); // a
printf("%c\n", tolower('7')); // 7toupper — 转大写
c
int toupper(int c);和 tolower 相反。
<math.h> — 数学函数(补充)
使用时编译要加 -lm 链接数学库。
| 函数 | 原型 | 说明 |
|---|---|---|
sqrt | double sqrt(double x); | 平方根 |
pow | double pow(double x, double y); | x 的 y 次方 |
abs | int abs(int x); | int 绝对值(在 stdlib.h) |
fabs | double fabs(double x); | double 绝对值 |
sin | double sin(double x); | 正弦(弧度) |
cos | double cos(double x); | 余弦 |
c
#include <math.h>
double r = 5.0;
double area = M_PI * r * r; // M_PI 是 π(有些编译器需要定义 _USE_MATH_DEFINES)
double dist = sqrt(3*3 + 4*4); // 5.0
// 编译:gcc math_demo.c -o math_demo -lm<time.h> — 时间函数(补充)
c
#include <time.h>
#include <stdlib.h>
// 随机数种子
srand((unsigned int)time(NULL));
// 生成 1-100 的随机数
int num = rand() % 100 + 1;速查表:常见坑
| 函数 | 坑 | 正确姿势 |
|---|---|---|
scanf | 忘记加 & | scanf("%d", &a); |
strcpy | 溢出 | 用 strncpy 或确保目标够大 |
free | free 野指针 / free 两次 | free 后置 NULL |
memset | 对 int 数组设为非 0 值失败 | memset 只能安全设 0 |
realloc | 直接接原指针,失败丢失 | 用临时变量接住 |
strcmp | 用 == 比较字符串 | 必须用 strcmp |
getchar | 吃掉回车符 | 循环读取或用 fflush(stdin) |
fread/fwrite | 写完忘记 fclose | 用完务必 fclose |