函数速查表

news/2025/11/18 16:51:08/文章来源:https://www.cnblogs.com/Jaklin/p/19238459

函数速查表

printf格式控制符表

格式控制符 含义 适用数据类型 参数说明 示例 输出结果(示例)
整型相关
%d 有符号十进制整数 int、short 接收int/short类型变量,按十进制输出 printf("%d", 123); 123
%i 有符号十进制整数(与%d功能一致) int、short 同%d,兼容早期C标准 printf("%i", -45); -45
%u 无符号十进制整数 unsigned int 接收unsigned int类型,仅输出非负数 printf("%u", 123U); 123
%o 无符号八进制整数(无前缀0) unsigned int 按八进制输出,不显示前缀0 printf("%o", 10); 12
%x 无符号十六进制整数(小写字母,无前缀0x) unsigned int 0-9用数字,10-15用a-f printf("%x", 255); ff
%X 无符号十六进制整数(大写字母,无前缀0X) unsigned int 0-9用数字,10-15用A-F printf("%X", 255); FF
%#o 无符号八进制整数(带前缀0) unsigned int 自动添加前缀0标识八进制 printf("%#o", 10); 012
%#x 无符号十六进制整数(带前缀0x) unsigned int 自动添加前缀0x标识十六进制 printf("%#x", 255); 0xff
浮点型相关
%f 单/双精度浮点数(小数形式) float、double 接收float/double,默认保留6位小数 printf("%f", 3.14); 3.140000
%lf 双精度浮点数(printf中与%f无区别) double 仅在scanf中区分float(%f)和double(%lf) printf("%lf", 3.1415); 3.141500
%e 浮点数(指数形式,小写e) float、double 尾数e+指数格式,尾数默认6位小数 printf("%e", 300.0); 3.000000e+02
%E 浮点数(指数形式,大写E) float、double 尾数E+指数格式,尾数默认6位小数 printf("%E", 300.0); 3.000000E+02
%g 自动选%f/%e(短格式,无意义0不显示) float、double 优先用%f,若数值过大/过小自动切换%e,删除末尾无意义0 printf("%g", 3.000); 3
%G 自动选%f/%E(短格式,无意义0不显示) float、double 同%g,指数部分用大写E printf("%G", 0.000300); 0.0003
字符/字符串相关
%c 单个字符 char 接收char类型,输出对应ASCII字符 printf("%c", 'A'); A
%s 字符串 char*(字符串指针) 接收以\0结尾的字符数组/指针,输出到\0停止 printf("%s", "Hello"); Hello
指针相关
%p 指针地址(十六进制形式) void* 接收任意类型指针,输出其内存地址(依赖系统位数) int a; printf("%p", &a); 0x7ffd42a1b23c(64位系统)
特殊符号
%% 输出一个百分号% 无参数,用于打印%本身(避免被解析为格式符) printf("%%"); %

示例

#include <stdio.h>
int main() {int a = 123;          // 整型unsigned int b = 456; // 无符号整型float c = 3.14159f;   // 单精度浮点型double d = 2.71828;   // 双精度浮点型char e = 'A';         // 字符型char f[] = "Hello";   // 字符串型int *g = &a;          // 指针(指向整型a)// 基础格式符输出printf("1. 整型(%d):%d\n", a, a);                  // %d:有符号十进制整数printf("2. 无符号整型(%u):%u\n", b, b);            // %u:无符号十进制整数printf("3. 单精度浮点(%f):%.3f\n", c, c);          // %f:浮点数,%.3f保留3位小数printf("4. 双精度浮点(%lf):%.4lf\n", d, d);        // %lf:双精度浮点数(printf中%f也可)printf("5. 字符(%c):%c\n", e, e);                  // %c:单个字符printf("6. 字符串(%s):%s\n", f, f);                // %s:字符串(以'\0'结尾)printf("7. 指针地址(%p):%p\n", g, g);              // %p:指针的十六进制地址(格式因系统而异)return 0;
}

** printf附加格式修饰符表**

修饰符 含义 参数说明 示例 输出结果(示例)
%md 输出宽度为m,不足用空格填充(右对齐) m为int型,指定输出总宽度 printf("%5d", 10); 10(共5位,前面补3个空格)
%-md 输出宽度为m,不足用空格填充(左对齐) m为int型,-表示左对齐 printf("%-5d", 10); 10 (共5位,后面补3个空格)
%0md 输出宽度为m,不足用0填充(右对齐) m为int型,0表示用0填充空位 printf("%05d", 10); 00010(共5位,前面补3个0)
%m.nf 输出宽度为m,保留n位小数 m:总宽度;n:小数位数 printf("%8.2f", 3.14159); 3.14(总8位,前面4个空格,保留2位小数)
%.nf 仅保留n位小数(宽度不限) n:小数位数 printf("%.3f", 3.14); 3.140(保留3位小数)
%.f 宽度和小数位由参数指定 第一个对应宽度m,第二个对应小数位n printf("%*.*f", 8, 2, 3.14); 3.14(等价于%8.2f)

示例

#include <stdio.h>
int main() {int num = 10;// 附加修饰符:%md(宽度)、%-md(左对齐)、%0md(0填充)printf("1. 指定宽度5(%5d):[%5d]\n", num, num);      // 宽度5,右对齐(默认),不足补空格printf("2. 左对齐宽度5(%-5d):[%-5d]end\n", num, num); // 左对齐,不足补空格printf("3. 0填充宽度5(%05d):%05d\n", num, num);    // 宽度5,不足补0printf("4. 正负号显示(%+d):%+d 和 %+d\n", num, -num, num); // %+d强制显示正负号return 0;
}

运算符优先级与结合性表

优先级(1最高,16最低) 运算符 含义 操作数数量 结合性 参数/表达式示例 说明
1 () 函数调用/表达式分组 1(函数调用)/2(分组) 左到右 func(3, 4)(a+b)*c 函数调用时括号内为参数列表;分组时改变运算顺序
1 [] 数组下标 2(数组名+下标) 左到右 arr[5] 等价于*(arr+5),下标为int型
1 -> 指针访问结构体成员 2(指针+成员名) 左到右 p->name p为结构体指针,name为结构体成员
1 . 结构体/联合体访问成员 2(变量+成员名) 左到右 obj.age obj为结构体变量,age为成员
2 ++(后置) 后置自增 1(变量) 左到右 a++ 先使用a的值,再a=a+1
2 --(后置) 后置自减 1(变量) 左到右 a-- 先使用a的值,再a=a-1
2 & 取地址 1(变量) 右到左 &a 返回变量a的内存地址(指针类型)
2 * 解引用(指针取值) 1(指针) 右到左 *p 返回指针p指向的变量值
2 sizeof 计算内存大小 1(类型/变量) 右到左 sizeof(int)sizeof(a) 返回字节数,类型需加括号,变量可省略
3 ++(前置) 前置自增 1(变量) 右到左 ++a 先a=a+1,再使用a的值
3 --(前置) 前置自减 1(变量) 右到左 --a 先a=a-1,再使用a的值
3 +(正) 正号 1(数值/变量) 右到左 +3+a 无实际运算,仅标识正数
3 -(负) 负号 1(数值/变量) 右到左 -3-a 取变量的相反数
3 ! 逻辑非 1(布尔值/变量) 右到左 !flag 真(非0)变假(0),假变真(1)
3 ~ 位非(按位取反) 1(整型变量) 右到左 ~a 对变量的每一位二进制取反(0变1,1变0)
3 (type) 强制类型转换 1(变量/表达式) 右到左 (int)3.14 将数据转换为指定类型,可能丢失精度
4 *(乘) 乘法 2(数值/变量) 左到右 a*b 整型/浮点型乘法
4 /(除) 除法 2(数值/变量) 左到右 a/b 整型除法取商(如5/2=2),浮点除法取精确值(5.0/2=2.5)
4 %(取模) 取余数 2(整型变量) 左到右 a%b 仅支持整型,结果符号与被除数一致(如5%2=1,-5%2=-1)
5 +(加) 加法 2(数值/变量) 左到右 a+b 整型/浮点型加法
5 -(减) 减法 2(数值/变量) 左到右 a-b 整型/浮点型减法
6 <<(左移) 按位左移 2(整型变量+移位位数) 左到右 a<<2 变量a的二进制左移2位,右边补0(等价于a*2^2)
6 >>(右移) 按位右移 2(整型变量+移位位数) 左到右 a>>2 有符号数左补符号位,无符号数左补0(等价于a/2^2)
7 > 大于 2(数值/变量) 左到右 a>b 成立返回1(真),不成立返回0(假)
7 >= 大于等于 2(数值/变量) 左到右 a>=b 成立返回1,不成立返回0
7 < 小于 2(数值/变量) 左到右 a<b 成立返回1,不成立返回0
7 <= 小于等于 2(数值/变量) 左到右 a<=b 成立返回1,不成立返回0
8 == 等于 2(数值/变量/指针) 左到右 a==bp==NULL 比较值是否相等,成立返回1,不成立返回0
8 != 不等于 2(数值/变量/指针) 左到右 a!=b 比较值是否不相等,成立返回1,不成立返回0
9 &(位与) 按位与 2(整型变量) 左到右 a&b 对应位均为1则为1,否则为0
10 ^(位异或) 按位异或 2(整型变量) 左到右 a^b 对应位不同则为1,相同则为0
11 |(位或) 按位或 2(整型变量) 左到右 a|b 对应位有1则为1,否则为0
12 &&(逻辑与) 逻辑与 2(布尔值/表达式) 左到右 a&&b 短路特性:左为假则右不执行,均为真返回1,否则0
13 ||(逻辑或) 逻辑或 2(布尔值/表达式) 左到右 a||b 短路特性:左为真则右不执行,有一个真返回1,否则0
14 ?:(条件运算符) 三目运算 3(表达式1?表达式2:表达式3) 右到左 a>b?a:b 表达式1为真则取表达式2的值,否则取表达式3的值
15 = 赋值 2(变量=表达式) 右到左 a=3a=b+c 将右边表达式的值赋给左边变量
15 += 加赋值 2(变量+=表达式) 右到左 a+=2 等价于a=a+2
15 -= 减赋值 2(变量-=表达式) 右到左 a-=2 等价于a=a-2
15 *= 乘赋值 2(变量*=表达式) 右到左 a*=2 等价于a=a*2
15 /= 除赋值 2(变量/=表达式) 右到左 a/=2 等价于a=a/2
15 %= 模赋值 2(变量%=表达式) 右到左 a%=2 等价于a=a%2
15 <<= 左移赋值 2(变量<<=位数) 右到左 a<<=2 等价于a=a<<2
15 >>= 右移赋值 2(变量>>=位数) 右到左 a>>=2 等价于a=a>>2
15 &= 位与赋值 2(变量&=表达式) 右到左 a&=b 等价于a=a&b
15 ^= 位异或赋值 2(变量^=表达式) 右到左 a^=b 等价于a=a^b
15 |= 位或赋值 2(变量|=表达式) 右到左 a|=b 等价于a=a|b
16 ,(逗号运算符) 表达式分隔 多个(表达式1,表达式2,...) 左到右 a=3, b=4, a+b 从左到右依次执行,最终取最后一个表达式的值(结果为7)

字符串操作函数

函数原型 功能描述 参数说明 返回值说明 头文件 关键注意事项
char *strcpy(char *dest, const char *src) 将源字符串(含终止符\0)复制到目标缓冲区,覆盖目标缓冲区原有内容 - destchar*,目标缓冲区(可读写,需足够大)
- srcconst char*,源字符串(只读,以\0结尾)
成功:返回dest(目标缓冲区首地址)
失败:无(但可能因缓冲区溢出导致程序崩溃)
<string.h> 1. 不安全:不检查dest长度,若src过长会溢出
2. 自动复制src\0dest
char *strncpy(char *dest, const char *src, size_t n) 将源字符串的前n个字符复制到目标缓冲区,是strcpy的安全版本,限制复制长度 - destchar*,目标缓冲区
- srcconst char*,源字符串
- n:size_t,最大复制字节数
成功:返回dest
失败:无(相对安全,溢出风险低)
<string.h> 1. 相对安全:最多复制n字节
2. 若src长度≤n,复制src\0;若src长度>n,仅复制前n字节,不自动加\0(需手动补)
char *strcat(char *dest, const char *src) 将源字符串追加到目标字符串的末尾(从目标字符串的\0位置开始),自动复制\0 - destchar*,目标字符串(可读写,以\0结尾,需足够大)
- srcconst char*,源字符串(只读,以\0结尾)
成功:返回dest
失败:无(可能溢出)
<string.h> 1. 不安全:不检查dest剩余空间,src过长会溢出
2. 从dest\0位置开始拼接,自动复制src\0
char *strncat(char *dest, const char *src, size_t n) 将源字符串的前n个字符追加到目标字符串末尾,自动添加\0,是strcat的安全版本 - destchar*,目标字符串
- src:const char*,源字符串
- n:size_t,最大拼接字节数
成功:返回dest
失败:无
<string.h> 1. 安全:最多拼接n字节,自动在末尾加\0
2. 拼接长度 = min(strlen(src),n)
int strcmp(const char *s1, const char *s2) 按ASCII值逐字符比较两个字符串,直到遇到不同字符或\0,判断字符串的字典序关系 - s1const char*,第一个字符串
- s2const char*,第二个字符串
返回值:
- <0s1字典序小于s2
- 0s1s2完全相同
- >0s1字典序大于s2
<string.h> 1. 按ASCII值逐字符比较,直到\0或不同字符
2. 区分大小写(如'A'(65)< 'a'(97))
size_t strlen(const char *s) 计算字符串的长度(字节数),从字符串起始位置到第一个\0为止,不包含\0 - sconst char*,字符串(以\0结尾) 成功:返回字符串长度(字节数,不含\0
失败:无(sNULL会段错误)
<string.h> 1. 时间复杂度O(n),需遍历到\0
2. 若字符串无\0,会越界访问(结果不确定)
char *strchr(const char *s, int c) 从字符串起始位置往后查找指定字符(含\0),返回首次出现该字符的指针 - sconst char*,字符串
- c:int,要查找的字符(ASCII值,低8位有效)
成功:返回指向该字符第一次出现位置的指针
失败:返回NULL
<string.h> 1. 从字符串开头往后查找,包括\0(如strchr(s, '\0')返回s+strlen(s)
2. 找到后返回的指针可用于修改字符(若s非const)
char *strrchr(const char *s, int c) 从字符串末尾位置往前查找指定字符(含\0),返回最后一次出现该字符的指针 - sconst char*,字符串
- c:int,要查找的字符
成功:返回指向该字符最后一次出现位置的指针
失败:返回NULL
<string.h> 1. 从字符串末尾往前查找(反向查找)
2. 其他特性同strchr
char *strstr(const char *haystack, const char *needle) 在主字符串中查找子字符串首次出现的位置,返回子字符串的起始指针;子字符串为空时返回主字符串 - haystackconst char*,主字符串(被查找的字符串)
- needleconst char*,子字符串(要查找的字符串)
成功:返回指向子字符串第一次出现位置的指针
失败:返回NULL
<string.h> 1. 若needle为空字符串,返回haystack(标准规定)
2. 区分大小写,不支持通配符
char *strtok(char *str, const char *delim) 按指定分隔符集合分割字符串,将分隔符替换为\0,返回当前分割的子字符串指针 - strchar*,要分割的字符串(首次调用传非NULL,后续传NULL)
- delimconst char*,分隔符集合(如",. "表示逗号、句号、空格均为分隔符)
成功:返回当前分割出的子字符串指针
失败/分割完毕:返回NULL
<string.h> 1. 修改原字符串:将分隔符替换为\0
2. 非线程安全(同一进程多个线程调用会相互干扰)
3. 示例:char s[]="a,b.c"; strtok(s, ",.");返回"a",下次传NULL返回"b"
void *memcpy(void *dest, const void *src, size_t n) 按字节从源内存复制n字节数据到目标内存,不关心数据类型,支持任意内存块复制 - destvoid*,目标内存(可读写)
- src:const void*,源内存(只读)
- n:size_t,要复制的字节数
成功:返回dest
失败:无(src/destNULL会段错误)
<string.h> 1. 按字节复制,不关心数据类型(可复制结构体、数组等)
2. 源/目标内存重叠时行为未定义(需用memmove
void *memmove(void *dest, const void *src, size_t n) 按字节从源内存复制n字节数据到目标内存,内部处理内存重叠问题,是memcpy的安全版本 - destvoid*,目标内存
- src:const void*,源内存
- n:size_t,复制字节数
成功:返回dest
失败:无
<string.h> 1. 功能同memcpy,但内部会处理内存重叠(先将数据临时存储)
2. 比memcpy稍慢,但更安全
void *memset(void *s, int c, size_t n) 按字节将目标内存的前n字节设置为指定值c,常用于内存初始化(如清零) - svoid*,目标内存(可读写)
- c:int,填充值(按字节填充,低8位有效)
- n:size_t,填充字节数
成功:返回s
失败:无
<string.h> 1. 仅按字节填充,不适用于int数组初始化(如memset(arr, 1, sizeof(arr))会将每个字节设为1,int值为0x01010101≠1)
2. 常用场景:内存清零(memset(s, 0, n)

示例

#include <stdio.h>
#include <string.h> // 字符串函数头文件int main() {char str1[20] = "Hello";char str2[20] = "World";char str3[20];int len, cmp_result;// 1. strlen:计算字符串长度(不含'\0')len = strlen(str1);printf("1. strlen(str1) = %d\n", len); // 输出5("Hello"共5个字符)// 2. strcpy:复制字符串(str2 → str3,不安全:可能溢出)strcpy(str3, str2); // 把str2的"World"复制到str3printf("2. strcpy(str3, str2) → str3 = %s\n", str3); // 输出World// 3. strncpy:安全复制(限制复制长度,避免溢出)char str4[10];strncpy(str4, str1, 3); // 复制str1的前3个字符到str4str4[3] = '\0'; // 手动补'\0'(strncpy不自动加'\0',需手动处理)printf("3. strncpy(str4, str1, 3) → str4 = %s\n", str4); // 输出Hel// 4. strcat:追加字符串(str2 → str1,不安全:可能溢出)strcat(str1, " "); // 先给str1追加空格(str1变为"Hello ")strcat(str1, str2); // 再追加str2(str1变为"Hello World")printf("4. strcat(str1, str2) → str1 = %s\n", str1); // 输出Hello World// 5. strcmp:比较字符串(按ASCII码字典序)// 返回值:0(相等)、正数(str1>str2)、负数(str1<str2)cmp_result = strcmp("Apple", "Banana");printf("5. strcmp(\"Apple\", \"Banana\") = %d\n", cmp_result); // 输出负数(A的ASCII < B)cmp_result = strcmp("Hello", "Hello");printf("   strcmp(\"Hello\", \"Hello\") = %d\n", cmp_result); // 输出0(相等)return 0;
}

标准IO函数

函数原型 功能描述 参数说明 返回值说明 头文件 关键注意事项
FILE *fopen(const char *pathname, const char *mode) 打开指定文件,返回文件指针用于后续IO操作;文件不存在时根据mode决定是否创建 - pathnameconst char*,指定文件的完整路径(如"/home/test.txt")或当前目录文件名(如"test.txt"
- modeconst char*,打开模式,常用值:
- "r":只读,文件不存在则失败
- "w":只写,文件不存在则创建,存在则清空内容
- "a":追加写,文件不存在则创建,写入从文件尾开始
- "r+":读写,文件不存在则失败
- "w+":读写,文件不存在则创建,存在则清空
- "a+":读写,文件不存在则创建,写入从文件尾开始
成功:返回指向FILE结构体的指针(文件指针),用于后续IO操作
失败:返回NULL,并设置errno(可通过perror打印错误)
<stdio.h> 1. 文本文件与二进制文件打开模式一致(Linux下无区别)
2. 打开后必须调用fclose关闭,避免资源泄漏
int fclose(FILE *stream) 关闭已打开的文件指针,释放文件相关资源,并自动刷新缓冲区数据到文件 - streamFILE*fopen返回的文件指针 成功:返回0
失败:返回-1,并设置errno
<stdio.h> 1. 关闭前会自动刷新缓冲区(全缓冲/行缓冲)
2. 关闭后stream指针变为野指针,不可再使用
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 从指定文件中按数据块读取数据,存储到用户缓冲区,适用于二进制文件或批量数据读取 - ptrvoid*,用户缓冲区指针(用于存储读取到的数据,需提前分配内存)
- size:size_t,单个数据块的字节数(如sizeof(int)
- nmemb:size_t,要读取的数据块数量
- streamFILE*,文件指针
成功:返回实际读取的数据块数量(不是字节数)
失败/EOF:返回0,需通过feof(stream)判断是否到文件尾,ferror(stream)判断是否错误
<stdio.h> 1. 适用于二进制文件(如图片、视频),也可用于文本文件
2. 读取字节数 = 返回值 × size
3. 若读取到部分数据(如文件尾),返回值小于nmemb
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 将用户缓冲区中的数据按数据块写入指定文件,适用于二进制文件或批量数据写入 - ptrconst void*,用户缓冲区指针(存储要写入的数据)
- size:size_t,单个数据块的字节数
- nmemb:size_t,要写入的数据块数量
- streamFILE*,文件指针
成功:返回实际写入的数据块数量
失败:返回0,并设置errno
<stdio.h> 1. 写入字节数 = 返回值 × size
2. 全缓冲模式下,数据先存缓冲区,满了才写入文件;需fflush强制刷新
int fgetc(FILE *stream) 从指定文件中读取单个字符,文件指针自动向后移动,支持文本文件的字符级读取 - streamFILE*,文件指针(如stdin表示标准输入) 成功:返回读取到的字符(ASCII值,范围0-255)
失败/EOF:返回EOF(宏定义为-1)
<stdio.h> 1. 每次读取1个字符,文件指针自动后移
2. 读取标准输入时,streamstdin(如fgetc(stdin)等价于getchar()
int fputc(int c, FILE *stream) 向指定文件中写入单个字符,文件指针自动向后移动,支持文本文件的字符级写入 - c:int,要写入的字符(ASCII值,低8位有效)
- streamFILE*,文件指针(如stdout表示标准输出)
成功:返回写入的字符(ASCII值)
失败:返回EOF
<stdio.h> 1. 每次写入1个字符,文件指针自动后移
2. 写入标准输出时,streamstdout(如fputc('A', stdout)等价于putchar('A')
char *fgets(char *s, int size, FILE *stream) 从指定文件中按行读取文本数据,存储到用户字符数组,自动添加字符串终止符\0 - schar*,用户字符数组(存储读取的行数据)
- size:int,数组最大长度(需预留1字节存\0
- streamFILE*,文件指针
成功:返回s(数组首地址)
失败/EOF:返回NULL
<stdio.h> 1. 读取到\nsize-1字节后停止,自动在末尾加\0
2. 会读取\n并存入数组(区别于gets
3. 避免缓冲区溢出(size需小于数组长度)
int fputs(const char *s, FILE *stream) 将指定字符串写入目标文件,写入到字符串终止符\0为止,不自动添加换行符 - sconst char*,要写入的字符串(需以\0结尾)
- streamFILE*,文件指针
成功:返回非负整数(具体值依赖系统)
失败:返回EOF
<stdio.h> 1. 不自动添加\n(区别于puts
2. 写入到\0停止,\0不写入文件
int fprintf(FILE *stream, const char *format, ...) 按指定格式将可变参数数据写入目标文件,支持格式化输出(如整数、字符串、浮点数) - streamFILE*,文件指针(如stdout表示屏幕输出)
- format:const char*,格式控制字符串(含%d%s等)
- ...:可变参数,与format中的格式符一一对应
成功:返回实际写入的字节数(不含\0
失败:返回负数
<stdio.h> 1. 格式符需与参数类型匹配(如%d对应int)
2. 标准输出用fprintf(stdout, ...),等价于printf(...)
int fscanf(FILE *stream, const char *format, ...) 按指定格式从目标文件中读取数据,存储到指定变量,支持格式化输入 - streamFILE*,文件指针(如stdin表示键盘输入)
- format:const char*,格式控制字符串
- ...:可变参数,需传变量地址(如&a
成功:返回成功匹配并赋值的参数个数
失败/EOF:返回EOF
<stdio.h> 1. 跳过空白符(空格、\t\n
2. 读取字符串时,遇空白符停止(不读取空白符)
3. 标准输入用fscanf(stdin, ...),等价于scanf(...)
int fseek(FILE *stream, long offset, int whence) 调整文件指针的位置,实现文件的随机访问,支持从文件头、当前位置或文件尾偏移 - streamFILE*,文件指针
- offset:long,偏移量(正数向右移,负数向左移)
- whence:int,偏移基准:
- SEEK_SET:从文件头开始(offset≥0)
- SEEK_CUR:从当前位置开始
- SEEK_END:从文件尾开始(offset常为负)
成功:返回0
失败:返回-1,并设置errno
<stdio.h> 1. 用于随机访问文件,不适用于管道、socket等流式文件
2. 文本文件中,offset需为ftell返回值(避免换行符转换问题)
long ftell(FILE *stream) 获取当前文件指针相对于文件头的偏移量(字节数),用于记录文件位置或计算文件长度 - streamFILE*,文件指针 成功:返回当前位置到文件头的字节数
失败:返回-1L,并设置errno
<stdio.h> 1. 常与fseek配合使用(如记录当前位置,后续恢复)
2. 文本文件中,换行符可能被转换(如Windows下\n存为\r\n),影响字节数计算
int fflush(FILE *stream) 强制刷新文件的缓冲区,将缓冲区中的数据立即写入文件,避免数据滞留丢失 - streamFILE*,文件指针;若为NULL,刷新所有打开的流 成功:返回0
失败:返回EOF,并设置errno
<stdio.h> 1. 强制将缓冲区数据写入文件(适用于全缓冲/行缓冲)
2. 标准输出stdout默认行缓冲,加\nfflush(stdout)可刷新
3. 只读流(如"r"模式)调用fflush行为未定义

示例

#include <stdio.h>
#include <stdlib.h> // 用于exit()函数int main() {FILE *fp; // 文件指针char buffer[100];int num = 123;float pi = 3.14f;// 1. fopen:打开文件(模式"w"=只写,文件不存在则创建,存在则清空)fp = fopen("test.txt", "w");if (fp == NULL) { // 必须判断打开是否成功(如权限不足会失败)perror("fopen write error"); // 打印错误信息exit(1); // 退出程序(异常状态)}// 2. fprintf:向文件写数据(格式与printf类似,多一个文件指针参数)fprintf(fp, "This is a test file.\n");fprintf(fp, "Integer: %d\n", num);fprintf(fp, "Float: %.2f\n", pi);printf("文件写入完成!\n");// 3. fclose:关闭文件(必须关闭,避免数据丢失)fclose(fp);fp = NULL; // 指针置空,避免野指针// 4. 重新打开文件(模式"r"=只读,读取刚才写入的内容)fp = fopen("test.txt", "r");if (fp == NULL) {perror("fopen read error");exit(1);}// 5. fgets:从文件读一行数据到缓冲区(最多读99个字符,留1个给'\0')printf("\n从文件读取内容:\n");while (fgets(buffer, sizeof(buffer), fp) != NULL) { // 读到文件末尾返回NULLprintf("%s", buffer); // 打印读取的内容}// 6. 再次关闭文件fclose(fp);fp = NULL;return 0;
}

系统IO函数

函数原型 功能描述 参数说明 返回值说明 头文件 关键注意事项
int open(const char *pathname, int flags, ...) 打开或创建指定文件,返回文件描述符用于底层IO操作;支持细粒度的打开选项(如非阻塞、追加) - pathnameconst char*,文件路径/名称(同fopen
- flags:int,打开选项(必选+可选组合,用|连接):
- 必选(三选一):O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(读写)
- 可选:O_CREAT(文件不存在则创建,需传第3参数mode)、O_APPEND(追加写,每次写前移到文件尾)、O_TRUNC(文件存在则清空)、O_NONBLOCK(非阻塞模式)
- ...:可变参数,仅当flagsO_CREAT时有效,为mode_t mode(文件权限,如0644)
成功:返回文件描述符(非负整数,0=标准输入,1=标准输出,2=标准错误)
失败:返回-1,并设置errno
<fcntl.h> 1. 权限计算:实际权限 = mode - umask(系统默认umask为0022或0002)
2. 打开后需调用close关闭,避免描述符泄漏
3. 区别于fopen:返回文件描述符(int),而非文件指针(FILE*)
int close(int fd) 关闭指定的文件描述符,释放文件相关内核资源;若多个描述符指向同一文件,需全部关闭才释放文件 - fd:int,open返回的文件描述符 成功:返回0
失败:返回-1,并设置errno
<unistd.h> 1. 关闭后fd不可再使用
2. 若多个描述符指向同一文件(如dup复制),需全部关闭才释放文件资源
ssize_t read(int fd, void *buf, size_t count) 从指定文件描述符中读取数据,存储到用户缓冲区,支持底层字节级读取 - fd:int,文件描述符
- bufvoid*,用户缓冲区(存储读取的数据,需提前分配)
- count:size_t,要读取的最大字节数
成功:返回实际读取的字节数(0表示EOF)
失败:返回-1,并设置errno
<unistd.h> 1. 阻塞模式下,若无数据则等待;非阻塞模式下,无数据返回-1(errno=EAGAIN
2. 读取字节数可能小于count(如文件尾、网络数据不完整)
ssize_t write(int fd, const void *buf, size_t count) 将用户缓冲区中的数据写入指定文件描述符,支持底层字节级写入 - fd:int,文件描述符
- bufconst void*,用户缓冲区(存储要写入的数据)
- count:size_t,要写入的字节数
成功:返回实际写入的字节数
失败:返回-1,并设置errno
<unistd.h> 1. 若磁盘满或缓冲区满,写入字节数可能小于count
2. 标准输出fd=1,标准错误fd=2(如write(1, "Hello", 5)等价于printf("Hello")
off_t lseek(int fd, off_t offset, int whence) 调整文件描述符对应的文件偏移量,实现底层文件的随机访问 - fd:int,文件描述符
- offset:off_t,偏移量(正数右移,负数左移)
- whence:int,偏移基准(同fseekSEEK_SET/SEEK_CUR/SEEK_END
成功:返回当前位置到文件头的字节数
失败:返回-1,并设置errno
<unistd.h> 1. 适用于可随机访问的文件(如普通文件),不适用于管道、socket
2. 偏移到文件尾外会产生“文件空洞”(占用磁盘空间,但内容为0)
int fcntl(int fd, int cmd, ...) 对已打开的文件描述符进行控制操作,如获取/设置文件属性、复制描述符、设置非阻塞 - fd:int,文件描述符
- cmd:int,控制命令(常用):
- F_GETFL:获取文件状态标志(如是否非阻塞)
- F_SETFL:设置文件状态标志(如添加O_NONBLOCK
- F_DUPFD:复制文件描述符,返回最小未用描述符
- ...:可变参数,依赖cmd(如F_SETFL需传标志值)
成功:返回值依赖cmd(如F_GETFL返回标志值,F_DUPFD返回新描述符)
失败:返回-1,并设置errno
<fcntl.h> 1. 常用场景:设置非阻塞模式( fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)
2. 不同cmd的参数和返回值需查阅man 2 fcntl
int dup(int oldfd) 复制指定的文件描述符,返回系统中最小的未使用文件描述符;新描述符与原描述符指向同一文件 - oldfd:int,已打开的文件描述符 成功:返回最小未使用的新文件描述符
失败:返回-1,并设置errno
<unistd.h> 1. 新描述符与oldfd指向同一文件,共享文件偏移量和状态
2. 关闭其中一个描述符,不影响另一个
int dup2(int oldfd, int newfd) 复制指定的文件描述符,并将新描述符指定为newfd;若newfd已打开,先关闭再复制 - oldfd:int,已打开的文件描述符
- newfd:int,目标新描述符
成功:返回newfd
失败:返回-1,并设置errno
<unistd.h> 1. 若newfd已打开,先关闭newfd,再复制oldfdnewfd
2. 常用于重定向(如dup2(fd, 1)将标准输出重定向到fd对应的文件)

示例

#include <stdio.h>
#include <unistd.h> // 系统IO核心头文件(open/close/read/write)
#include <fcntl.h>  // 包含open函数的模式宏(如O_WRONLY、O_CREAT)
#include <stdlib.h>
#include <string.h>int main() {int fd; // 文件描述符(系统IO用整数标识文件,区别于标准IO的FILE*)char write_buf[] = "Hello from System IO!"; // 要写入的内容char read_buf[100] = {0}; // 读取缓冲区(初始化为0)ssize_t write_len, read_len; // 实际读写的字节数(ssize_t是系统定义的带符号整数)// 1. open:打开/创建文件(系统IO的“打开”函数)// 模式说明:O_WRONLY(只写)| O_CREAT(文件不存在则创建)// 第三个参数:文件权限(0644=所有者读写,其他只读)fd = open("sys_io_test.txt", O_WRONLY | O_CREAT, 0644);if (fd == -1) { // 打开失败返回-1perror("open write error");exit(1);}// 2. write:向文件写数据(系统IO的“写”函数)write_len = write(fd, write_buf, strlen(write_buf));if (write_len == -1) {perror("write error");close(fd); // 出错也要关闭文件exit(1);}printf("系统IO写入字节数:%zd\n", write_len); // 输出21(字符串长度)// 3. close:关闭文件(系统IO的“关闭”函数)close(fd);fd = -1; // 置为无效值,避免误用// 4. 重新打开文件(模式O_RDONLY=只读)fd = open("sys_io_test.txt", O_RDONLY);if (fd == -1) {perror("open read error");exit(1);}// 5. read:从文件读数据(系统IO的“读”函数)read_len = read(fd, read_buf, sizeof(read_buf) - 1); // 留1个字节给'\0'if (read_len == -1) {perror("read error");close(fd);exit(1);}read_buf[read_len] = '\0'; // 手动加字符串结束符(read不自动加)printf("系统IO读取内容:%s\n", read_buf); // 输出Hello from System IO!// 6. 再次关闭文件close(fd);fd = -1;return 0;
}

内存操作函数

函数原型 功能描述 参数说明 返回值说明 头文件 关键注意事项
void *malloc(size_t size) 从堆内存中申请指定字节数的连续内存块,不初始化内存内容(内容为随机值) - size:size_t,要申请的堆内存字节数 成功:返回指向堆内存的指针(void*,需强制类型转换)
失败:返回NULL,并设置errno
<stdlib.h> 1. 申请的内存未初始化(内容为随机值)
2. 需检查返回值是否为NULL(避免野指针)
3. 内存需用free释放,否则内存泄漏
void *calloc(size_t nmemb, size_t size) 从堆内存中申请nmemb × size字节的连续内存块,自动将内存初始化为0,适用于创建堆数组 - nmemb:size_t,元素个数
- size:size_t,单个元素字节数
成功:返回指向堆数组的指针
失败:返回NULL,并设置errno
<stdlib.h> 1. 申请nmemb × size字节的堆内存,并初始化为0
2. 等价于malloc(nmemb×size) + memset(..., 0, ...)
3. 适用于创建数组(如calloc(5, sizeof(int))创建5个int的堆数组)
void *realloc(void *ptr, size_t size) 调整已有的堆内存块大小,可扩大或缩小;扩大时可能分配新内存并复制数据,缩小则截断内存 - ptrvoid*,已有的堆内存指针(malloc/calloc返回值;若为NULL,等价于malloc(size)
- size:size_t,新的内存大小(字节数)
成功:返回指向新堆内存的指针
失败:返回NULL,原内存ptr不变
<stdlib.h> 1. 若新size>原size:可能扩展原内存,或分配新内存并复制数据(原内存自动释放)
2. 若新size<原size:截断内存,多余部分释放
3. 避免用原指针接收返回值(失败时原指针被覆盖为NULL
void free(void *ptr) 释放之前通过malloc/calloc/realloc申请的堆内存,将内存归还给系统,避免内存泄漏 - ptrvoid*malloc/calloc/realloc返回的堆内存指针 无返回值 <stdlib.h> 1. 仅释放堆内存,不修改指针值(ptr变为野指针,需手动设为NULL
2. 不可重复释放(同一指针释放多次会崩溃)
3. 不可释放栈内存(如局部变量地址)
void bzero(void *s, size_t n) 将目标内存的前n字节清零,功能等价于memset(s, 0, n),是BSD扩展函数 - svoid*,目标内存(可读写)
- n:size_t,要清零的字节数
无返回值 <strings.h> 1. 功能同memset(s, 0, n),仅清零
2. 是BSD扩展函数,部分系统可能不支持(建议用memset保证可移植性)

示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 定义结构体(用于动态内存存储)
typedef struct {char name[20];int age;
} Person;int main() {// 1. malloc:分配指定字节数的内存(未初始化,内容随机)int *arr1 = (int *)malloc(5 * sizeof(int)); // 分配5个int的内存(约20字节)if (arr1 == NULL) { // 必须判断内存分配是否成功(失败返回NULL)perror("malloc arr1 error");exit(1);}// 手动初始化动态数组for (int i = 0; i < 5; i++) {arr1[i] = i * 10; // arr1 = [0, 10, 20, 30, 40]}printf("1. malloc动态数组arr1:");for (int i = 0; i < 5; i++) {printf("%d ", arr1[i]);}printf("\n");// 2. calloc:分配内存并初始化为0(适合数组)int *arr2 = (int *)calloc(3, sizeof(int)); // 分配3个int,初始化为0if (arr2 == NULL) {perror("calloc arr2 error");free(arr1); // 若分配失败,需释放已分配的内存exit(1);}printf("2. calloc动态数组arr2(初始化为0):");for (int i = 0; i < 3; i++) {printf("%d ", arr2[i]); // 输出 [0, 0, 0]}printf("\n");// 3. realloc:调整已分配内存的大小(扩容/缩容)int *arr1_new = (int *)realloc(arr1, 8 * sizeof(int)); // 将arr1从5个int扩容到8个if (arr1_new == NULL) {perror("realloc arr1_new error");free(arr1); // 扩容失败时,原内存arr1仍有效,需手动释放free(arr2);exit(1);}arr1 = arr1_new; // 扩容成功,更新指针指向新内存// 给新增的3个元素赋值for (int i = 5; i < 8; i++) {arr1[i] = i * 10; // arr1 = [0,10,20,30,40,50,60,70]}printf("3. realloc扩容后arr1:");for (int i = 0; i < 8; i++) {printf("%d ", arr1[i]);}printf("\n");// 4. free:释放动态内存(必须调用,避免内存泄漏)free(arr1); // 释放arr1指向的内存free(arr2); // 释放arr2指向的内存arr1 = NULL; // 指针置空,避免野指针(指向已释放的内存)arr2 = NULL;printf("4. 动态内存已全部释放\n");// 5. 动态内存存储结构体Person *p = (Person *)malloc(sizeof(Person));if (p == NULL) { perror("malloc Person error"); exit(1); }strcpy(p->name, "Li Si"); // 给结构体成员赋值p->age = 22;printf("5. 动态结构体:姓名=%s,年龄=%d\n", p->name, p->age);free(p);p = NULL;return 0;
}

进程操作函数

函数原型 功能描述 参数说明 返回值说明 头文件 关键注意事项
pid_t fork(void) 创建子进程,子进程完全复刻父进程的内存空间(代码段、数据段、栈、堆),父子进程从fork后并发执行 无参数 成功:
- 父进程:返回子进程的PID(正整数)
- 子进程:返回0
失败:返回-1,并设置errno
<unistd.h> 1. 子进程复刻父进程的内存空间(代码段、数据段、栈、堆),但PID不同
2. 父子进程并发执行,顺序不确定(需同步机制控制)
3. 子进程继承父进程的打开文件、环境变量等
pid_t wait(int *wstatus) 阻塞等待任意子进程退出,回收子进程的内核资源,避免僵尸进程;可获取子进程退出状态 - wstatus:int*,存储子进程退出状态;若为NULL,表示不关心退出状态 成功:返回回收的子进程PID
失败:
- 无子进程:返回-1,errno=ECHILD
- 被信号中断:返回-1,errno=EINTR
<sys/wait.h> 1. 阻塞等待:父进程暂停执行,直到有子进程退出
2. 若有多个子进程,仅回收第一个退出的子进程
3. 可通过宏解析wstatus
- WIFEXITED(wstatus):是否正常退出
- WEXITSTATUS(wstatus):获取正常退出的返回值
- WIFSIGNALED(wstatus):是否被信号杀死
pid_t waitpid(pid_t pid, int *wstatus, int options) 指定回收某个或某组子进程,支持阻塞/非阻塞模式,比wait更灵活;可避免父进程长时间阻塞 - pid:pid_t,指定回收的子进程:
- pid > 0:回收PID为pid的子进程
- pid = -1:回收任意子进程(同wait
- pid = 0:回收与父进程同组的子进程
- pid < -1:回收组ID为-pid的子进程
- wstatus:int*,存储退出状态(同wait
- options:int,选项:
- 0:阻塞等待
- WNOHANG:非阻塞,无僵尸子进程则立即返回0
成功:
- 阻塞模式:返回回收的子进程PID
- 非阻塞模式:有子进程回收则返回PID,无则返回0
失败:返回-1,并设置errno
<sys/wait.h> 1. 比wait更灵活,可指定子进程和等待模式
2. 常用场景:非阻塞轮询回收子进程(waitpid(-1, NULL, WNOHANG)
int execl(const char *path, const char *arg, ...) 加载并执行指定路径的程序,替换当前进程的代码段和数据段(PID不变);参数以NULL结尾 - pathconst char*,要执行的程序路径(如"/bin/ls"
- argconst char*,程序的第一个参数(通常为程序名)
- ...:可变参数,后续参数为程序的命令行参数,(char*)NULL结尾
成功:不返回(程序替换当前进程内存空间)
失败:返回-1,并设置errno
<unistd.h> 1. 替换当前进程的代码段和数据段,PID不变
2. 若执行成功,后续代码不执行;仅失败时返回
3. 示例:execl("/bin/ls", "ls", "-l", NULL)执行ls -l
int execlp(const char *file, const char *arg, ...) 加载并执行程序,自动搜索PATH环境变量查找程序路径;参数以NULL结尾,无需手动指定完整路径 - fileconst char*,程序名(如"ls"),自动搜索PATH环境变量
- arg...:同execl
成功:不返回
失败:返回-1,并设置errno
<unistd.h> 1. 区别于execl:无需指定完整路径,自动搜索PATH(如execlp("ls", "ls", "-l", NULL)
2. 若file/,则按路径查找(同execl
int system(const char *command) 创建子进程执行指定的系统命令,父进程阻塞等待命令执行完毕;命令输出默认到标准输出 - commandconst char*,要执行的系统命令字符串(如"ls -l" 成功:返回命令的退出状态(需用WEXITSTATUS解析)
失败:返回-1,并设置errno
<stdlib.h> 1. 内部创建子进程执行命令,父进程阻塞等待
2. 命令执行结果输出到标准输出(屏幕)
3. 不适用于需交互的命令(如"vi"
FILE *popen(const char *command, const char *type) 创建管道和子进程,执行系统命令;通过管道实现父进程与子进程的通信(读命令输出或写命令输入) - commandconst char*,系统命令字符串
- typeconst char*,管道方向:
- "r":读取命令的输出(子进程stdout -> 父进程)
- "w":向命令输入数据(父进程 -> 子进程stdin)
成功:返回指向管道的文件指针(FILE*)
失败:返回NULL,并设置errno
<stdio.h> 1. 创建管道和子进程,执行命令,返回文件指针用于读写
2. 需用pclose关闭,pclose会等待命令执行完毕
3. 示例:FILE *fp = popen("ls -l", "r");读取ls -l的输出
int pclose(FILE *stream) 关闭popen创建的管道文件指针,等待子进程(命令)执行完毕,回收子进程资源 - streamFILE*popen返回的文件指针 成功:返回命令的退出状态
失败:返回-1,并设置errno
<stdio.h> 1. 关闭管道,等待子进程退出
2. 不可用fclose替代(fclose不等待子进程)
void exit(int status) 终止当前进程,刷新所有打开的流缓冲区,关闭文件,释放进程资源;调用终止处理函数 - status:int,进程退出状态(0表示正常,非0表示异常) 无返回值 <stdlib.h> 1. 刷新所有打开的流缓冲区,关闭文件,释放资源
2. 调用注册的终止处理函数(atexit注册)
3. 区别于_exit_exit不刷新缓冲区,直接终止
void _exit(int status) 立即终止当前进程,不刷新缓冲区,不调用终止处理函数,直接释放内核资源 - status:int,退出状态 无返回值 <unistd.h> 1. 立即终止进程,不刷新缓冲区,不调用终止处理函数
2. 常用于子进程(避免刷新父进程的缓冲区)

示例

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>int main() {printf("父进程启动,PID=%d\n", getpid());// 创建子进程pid_t pid = fork();if (pid < 0) {perror("fork失败");exit(1);}// 子进程逻辑if (pid == 0) {printf("子进程启动,PID=%d,父进程PID=%d\n", getpid(), getppid());// 子进程执行任务(示例:休眠2秒后退出)sleep(2);printf("子进程执行完毕,即将退出\n");exit(0); // 子进程退出,返回状态码0}// 父进程逻辑(继续执行)printf("父进程等待子进程(PID=%d)退出...\n", pid);int status;// 阻塞等待子进程退出,回收资源(避免僵尸进程)waitpid(pid, &status, 0);// 解析子进程退出状态if (WIFEXITED(status)) {printf("父进程:子进程正常退出,退出码=%d\n", WEXITSTATUS(status));}printf("父进程执行完毕,退出\n");return 0;
}

线程操作函数

函数原型 功能描述 参数说明 返回值说明 头文件 关键注意事项
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) 创建新线程,指定线程执行函数和参数;新线程与主线程并发执行,共享进程资源 - threadpthread_t*,存储新线程的TID(线程ID)
- attrconst pthread_attr_t*,线程属性(NULL表示默认属性)
- start_routinevoid*(*)(void*),线程函数指针(函数返回void,参数为void
- arg:void*,传递给线程函数的参数(需强制类型转换)
成功:返回0
失败:返回错误码(非-1,需用strerror打印错误)
<pthread.h> 1. 编译需加-lpthread选项(如gcc test.c -o test -lpthread
2. 线程函数返回的void*需为全局/堆变量(避免栈变量销毁)
3. 线程默认joinable(需pthread_join回收)
void pthread_exit(void *retval) 终止当前线程,释放线程的栈资源;返回值通过pthread_join传递给回收线程 - retvalvoid*,线程返回值(传递给pthread_join 无返回值 <pthread.h> 1. 终止当前线程,释放线程资源(但进程资源需pthread_join回收)
2. retval不可为栈变量(线程退出后栈释放)
int pthread_join(pthread_t thread, void **retval) 阻塞等待指定线程退出,回收线程资源,获取线程返回值;仅支持joinable状态的线程 - thread:pthread_t,要回收的线程TID
- retval:void**,存储线程返回值(pthread_exit的参数);若为NULL,不关心返回值
成功:返回0
失败:返回错误码
<pthread.h> 1. 阻塞等待:调用线程暂停,直到thread线程退出
2. 仅能回收joinable状态的线程;detach状态的线程不可join
3. 示例:pthread_join(tid, (void**)&ret);获取线程返回值ret
int pthread_detach(pthread_t thread) 将指定线程设置为detach状态,线程退出后自动释放资源,无需pthread_join回收 - thread:pthread_t,要设置为detach状态的线程TID 成功:返回0
失败:返回错误码
<pthread.h> 1. 设置线程为detach状态,退出后自动释放资源(无需pthread_join
2. 不可对已join的线程调用(会失败)
3. 也可在创建时通过属性设置detach(pthread_attr_setdetachstate
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) 初始化互斥锁,用于保护多线程共享的临界资源,避免线程竞争导致的数据不一致 - mutex:pthread_mutex_t*,互斥锁变量
- attrconst pthread_mutexattr_t*,互斥锁属性(NULL为默认属性)
成功:返回0
失败:返回错误码
<pthread.h> 1. 互斥锁用于保护临界资源(多线程共享数据)
2. 也可静态初始化:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int pthread_mutex_lock(pthread_mutex_t *mutex) 获取互斥锁,若锁已被占用则阻塞等待;成功获取后进入临界区,确保临界区代码独占执行 - mutex:pthread_mutex_t*,互斥锁变量 成功:返回0(获取锁)
失败:返回错误码
<pthread.h> 1. 阻塞等待:若锁已被占用,线程暂停,直到锁释放
2. 临界区代码需放在lockunlock之间,避免竞争
int pthread_mutex_unlock(pthread_mutex_t *mutex) 释放互斥锁,允许其他等待锁的线程竞争获取;仅持有锁的线程可释放 - mutex:pthread_mutex_t*,互斥锁变量 成功:返回0(释放锁)
失败:返回错误码
<pthread.h> 1. 仅持有锁的线程可释放(其他线程释放会失败)
2. 释放后,等待锁的线程竞争获取

示例

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>// 共享资源(临界资源)
int shared_num = 0;
// 互斥锁(保护共享资源)
pthread_mutex_t mutex;// 线程函数:累加共享变量
void* thread_func(void* arg) {int thread_id = *(int*)arg;for (int i = 0; i < 5000; i++) {// 加锁:进入临界区(独占访问共享资源)pthread_mutex_lock(&mutex);shared_num++;// 解锁:退出临界区(释放锁允许其他线程访问)pthread_mutex_unlock(&mutex);}printf("线程%d执行完毕,当前shared_num=%d\n", thread_id, shared_num);return NULL;
}int main() {pthread_t tid1, tid2;int id1 = 1, id2 = 2;// 初始化互斥锁pthread_mutex_init(&mutex, NULL);// 创建两个线程pthread_create(&tid1, NULL, thread_func, &id1);pthread_create(&tid2, NULL, thread_func, &id2);// 等待线程执行完毕pthread_join(tid1, NULL);pthread_join(tid2, NULL);// 销毁互斥锁pthread_mutex_destroy(&mutex);printf("主线程:最终shared_num=%d(预期10000)\n", shared_num);return 0;
}

管道操作函数

函数原型 功能说明 参数说明 返回值 头文件 关键注意事项
int pipe(int fd[2]); 创建匿名管道,生成读/写两个文件描述符 - fd[2]:整型数组(固定长度2)
- fd[0]:管道读端(仅用于read
- fd[1]:管道写端(仅用于write
成功返回0
失败返回-1(设置errno
<unistd.h> 1. 需在fork()前创建,子进程继承管道描述符;
2. 不能多进程同时写(数据可能覆盖);
3. 管道无定位功能(仅支持顺序读写,不可用lseek
ssize_t read(int fd, void *buf, size_t count); 从管道读端读取数据 - fd:管道读端描述符(fd[0]
- buf:接收数据的缓冲区
- count:缓冲区最大字节数
成功返回实际读取字节数;
0 = 管道写端关闭;
失败返回-1
<unistd.h> 1. 默认阻塞:管道为空时,读进程挂起等待;
2. 非阻塞模式下,管道为空返回-1errno=EAGAIN
ssize_t write(int fd, const void *buf, size_t count); 向管道写端写入数据 - fd:管道写端描述符(fd[1]
- buf:待写入数据的缓冲区
- count:待写入字节数
成功返回实际写入字节数;
失败返回-1
<unistd.h> 1. 默认阻塞:管道满时,写进程挂起等待;
2. 单个写操作≤PIPE_BUF(通常4096字节)时保证原子性;
3. 若读端已关闭,写操作会触发SIGPIPE信号(进程默认终止)
int close(int fd); 关闭管道的读端/写端 - fd:需关闭的描述符(fd[0]fd[1] 成功返回0
失败返回-1
<unistd.h> 1. 需主动关闭无用端(如父进程写后关fd[1],避免子进程读阻塞);
2. 两端均关闭后,管道资源被内核回收
int mkfifo(const char *pathname, mode_t mode); 创建具名管道文件(仅需一次) - pathname:管道文件路径(如/tmp/myfifo
- mode:文件权限(八进制,如0666
成功返回0
失败返回-1(如路径已存在)
<sys/types.h>
<sys/stat.h>
1. 不可创建在Windows共享文件夹(不支持管道文件);
2. 实际权限 = mode - umask(需提前调整umask,如umask(0));
3. 创建后需用open打开才能读写
int open(const char *pathname, int flags); 打开已创建的具名管道 - pathname:管道文件路径(mkfifopathname
- flags:打开模式(必选+可选)
- 必选:O_RDONLY(读)/ O_WRONLY(写)
- 可选:O_NONBLOCK(非阻塞)
成功返回文件描述符;
失败返回-1
<fcntl.h> 1. 默认阻塞:仅读端打开时,写端需等待读端;反之亦然;
2. 用O_RDWR打开可避免阻塞(但失去单向通信意义);
3. 多进程可同时打开(支持多写一读,依赖写入原子性)
ssize_t read(int fd, void *buf, size_t count); 从具名管道读取数据 同匿名管道的read(参数/返回值一致) 同匿名管道的read <unistd.h> 1. 写入原子性:单个写操作≤PIPE_BUF时,数据不被分割(适用于日志系统等多进程写场景);
2. 其他特性同匿名管道read
ssize_t write(int fd, const void *buf, size_t count); 向具名管道写入数据 同匿名管道的write(参数/返回值一致) 同匿名管道的write <unistd.h> 1. 多进程同时写时,≤PIPE_BUF的操作保证原子性(数据不覆盖);
2. 其他特性同匿名管道write
int close(int fd); 关闭具名管道的文件描述符 - fdopen返回的管道描述符 成功返回0
失败返回-1
<unistd.h> 1. 所有进程关闭后,管道文件仍存在(需手动rm删除);
2. 关闭后描述符不可再用

匿名管道(父子进程通信)示例

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>int main() {int pipe_fd[2]; // 管道描述符:pipe_fd[0]读端,pipe_fd[1]写端// 创建匿名管道if (pipe(pipe_fd) == -1) {perror("pipe创建失败");return 1;}pid_t pid = fork();if (pid < 0) {perror("fork失败");return 1;}// 子进程:从管道读数据if (pid == 0) {close(pipe_fd[1]); // 子进程不写,关闭写端char buf[100] = {0};// 读管道(阻塞等待数据)ssize_t read_len = read(pipe_fd[0], buf, sizeof(buf)-1);if (read_len > 0) {printf("子进程收到数据:%s\n", buf);}close(pipe_fd[0]); // 关闭读端return 0;}// 父进程:向管道写数据close(pipe_fd[0]); // 父进程不读,关闭读端const char* msg = "Hello from 父进程!";write(pipe_fd[1], msg, strlen(msg));printf("父进程发送数据:%s\n", msg);close(pipe_fd[1]); // 关闭写端(子进程read会返回0)waitpid(pid, NULL, 0); // 等待子进程return 0;
}

具名管道(FIFO,任意进程通信)示例
写端程序(fifo_write.c)

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>#define FIFO_PATH "/tmp/my_fifo" // 命名管道路径int main() {// 创建命名管道(若不存在)if (mkfifo(FIFO_PATH, 0666) == -1) {perror("mkfifo失败(可能已存在)");}// 打开管道(写模式,阻塞等待读端)int fd = open(FIFO_PATH, O_WRONLY);if (fd == -1) {perror("open失败");return 1;}// 向管道写数据const char* msg = "Hello from 命名管道写端!";write(fd, msg, strlen(msg));printf("写端发送:%s\n", msg);close(fd);return 0;
}

读端程序(fifo_read.c)

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>#define FIFO_PATH "/tmp/my_fifo"int main() {// 打开管道(读模式,阻塞等待写端)int fd = open(FIFO_PATH, O_RDONLY);if (fd == -1) {perror("open失败");return 1;}// 从管道读数据char buf[100] = {0};ssize_t read_len = read(fd, buf, sizeof(buf)-1);if (read_len > 0) {printf("读端收到:%s\n", buf);}close(fd);return 0;
}

信号操作函数

函数原型 功能描述 参数说明 返回值说明 头文件 关键注意事项
typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler) 为指定信号注册处理函数,定义信号的响应方式(忽略、默认处理、自定义处理) - signum:int,信号值(如SIGINT(2)、SIGCHLD(17))
- handler:sighandler_t,信号处理函数:
- SIG_IGN:忽略该信号
- SIG_DFL:默认处理(如SIGINT默认终止进程)
- 自定义函数:void func(int sig)(sig为信号值)
成功:返回之前的信号处理函数指针
失败:返回SIG_ERR(-1),并设置errno
<signal.h> 1. 常用信号:
- SIGINT(2):Ctrl+C触发,默认终止
- SIGCHLD(17):子进程退出触发,默认忽略
- SIGKILL(9)、SIGSTOP(19):不可捕获、忽略
2. 自定义处理函数执行时,会自动屏蔽当前信号(避免重入)
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset) 修改进程的信号阻塞集,实现信号的屏蔽(暂不处理)或解除屏蔽(恢复处理) - how:int,操作类型:
- SIG_BLOCK:将set中的信号添加到阻塞集
- SIG_UNBLOCK:从阻塞集中删除set中的信号
- SIG_SETMASK:用set替换阻塞集
- set:const sigset_t,要操作的信号集;若为NULL,仅获取当前阻塞集
- oldset:sigset_t
,存储原阻塞集;若为NULL,不保存
成功:返回0
失败:返回-1,并设置errno
<signal.h> 1. 信号集操作需配合以下函数:
- sigemptyset:清空信号集
- sigaddset:添加信号到集
- sigismember:检查信号是否在集
2. 阻塞的信号不会被丢弃,解除阻塞后会被处理
int sigemptyset(sigset_t *set) 初始化信号集,将信号集清空(不包含任何信号),为后续添加信号做准备 - set:sigset_t*,要清空的信号集 成功:返回0
失败:返回-1,并设置errno
<signal.h> 初始化信号集为空(无任何信号)
int sigaddset(sigset_t *set, int signum) 将指定信号添加到信号集中,用于构建需要操作的信号集合(如阻塞、解除阻塞) - set:sigset_t*,信号集
- signum:int,要添加的信号值
成功:返回0
失败:返回-1,并设置errno
<signal.h> 向信号集中添加指定信号
int sigismember(const sigset_t *set, int signum) 检查指定信号是否包含在信号集中,用于判断信号是否处于阻塞或待处理状态 - set:const sigset_t*,信号集
- signum:int,要检查的信号值
成功:
- 信号在集中:返回1
- 信号不在集中:返回0
失败:返回-1,并设置errno
<signal.h> 判断信号是否在指定信号集中

示例 1:自定义信号处理函数(捕获 Ctrl+C)

#include <stdio.h>
#include <signal.h>
#include <unistd.h>// 自定义信号处理函数(捕获SIGINT信号)
void sigint_handler(int sig) {printf("\n收到信号%d(Ctrl+C),程序不退出,3秒后继续运行...\n", sig);sleep(3); // 模拟处理耗时
}int main() {// 注册SIGINT信号的处理函数(默认处理是终止进程)if (signal(SIGINT, sigint_handler) == SIG_ERR) {perror("signal register failed");return 1;}printf("程序运行中,按Ctrl+C测试信号处理(输入q退出)...\n");char c;while ((c = getchar()) != 'q') {// 循环等待,直到输入q退出}printf("程序正常退出\n");return 0;
}

示例 2:信号阻塞与解除阻塞

#include <stdio.h>
#include <signal.h>
#include <unistd.h>void sigint_handler(int sig) {printf("收到信号%d(Ctrl+C)\n", sig);
}int main() {sigset_t sig_set, old_set;// 1. 注册信号处理函数signal(SIGINT, sigint_handler);// 2. 初始化信号集并添加SIGINTsigemptyset(&sig_set); // 清空信号集sigaddset(&sig_set, SIGINT); // 添加SIGINT到信号集// 3. 阻塞SIGINT信号(期间收到该信号会暂存,不处理)if (sigprocmask(SIG_BLOCK, &sig_set, &old_set) < 0) {perror("sigprocmask block failed");return 1;}printf("SIGINT信号已阻塞,接下来5秒内按Ctrl+C无响应...\n");sleep(5);// 4. 解除SIGINT信号阻塞(暂存的信号会被处理)if (sigprocmask(SIG_UNBLOCK, &sig_set, NULL) < 0) {perror("sigprocmask unblock failed");return 1;}printf("SIGINT信号已解除阻塞,按Ctrl+C测试...\n");// 等待信号sleep(10);return 0;
}

互斥锁、读写锁操作函数

函数原型 功能说明 参数说明 返回值 头文件
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); 初始化互斥锁 - mutex:互斥锁指针
- attr:属性(默认NULL)
成功返回0,失败返回错误码 <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex); 销毁互斥锁 - mutex:互斥锁指针 成功返回0,失败返回错误码 <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex); 阻塞获取互斥锁(临界区入口) - mutex:互斥锁指针 成功返回0,失败返回错误码 <pthread.h>
int pthread_mutex_trylock(pthread_mutex_t *mutex); 非阻塞获取互斥锁 - mutex:互斥锁指针 成功返回0,失败返回错误码 <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex); 释放互斥锁(临界区出口) - mutex:互斥锁指针 成功返回0,失败返回错误码 <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); 初始化读写锁 - rwlock:读写锁指针
- attr:属性(默认NULL)
成功返回0,失败返回错误码 <pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); 阻塞获取读锁(共享锁) - rwlock:读写锁指针 成功返回0,失败返回错误码 <pthread.h>
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); 阻塞获取写锁(排他锁) - rwlock:读写锁指针 成功返回0,失败返回错误码 <pthread.h>
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); 释放读写锁 - rwlock:读写锁指针 成功返回0,失败返回错误码 <pthread.h>

互斥锁示例(多线程安全访问共享变量)

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>// 共享变量(临界资源)
int g_count = 0;
// 互斥锁(全局变量,确保多线程可见)
pthread_mutex_t g_mutex;// 线程函数:循环累加共享变量
void *thread_func(void *arg) {int id = *(int *)arg;for (int i = 0; i < 10000; i++) {// 1. 加锁:进入临界区(独占访问共享资源)pthread_mutex_lock(&g_mutex);g_count++;// 2. 解锁:退出临界区(释放锁,允许其他线程访问)pthread_mutex_unlock(&g_mutex);}printf("线程%d执行完毕,g_count = %d\n", id, g_count);return NULL;
}int main() {pthread_t tid1, tid2;int id1 = 1, id2 = 2;// 3. 初始化互斥锁(默认属性)pthread_mutex_init(&g_mutex, NULL);// 创建两个线程pthread_create(&tid1, NULL, thread_func, &id1);pthread_create(&tid2, NULL, thread_func, &id2);// 等待线程执行完毕pthread_join(tid1, NULL);pthread_join(tid2, NULL);// 4. 销毁互斥锁pthread_mutex_destroy(&g_mutex);printf("主线程:最终g_count = %d(正确结果应为20000)\n", g_count);return 0;
}

读写锁示例(多读少写场景优化)

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>int g_data = 10;
pthread_rwlock_t g_rwlock;// 读线程:共享访问数据(无修改)
void *read_thread(void *arg) {int id = *(int *)arg;while (1) {// 加读锁(多个读线程可同时获取)pthread_rwlock_rdlock(&g_rwlock);printf("读线程%d:g_data = %d\n", id, g_data);pthread_rwlock_unlock(&g_rwlock);sleep(1); // 模拟读操作耗时}return NULL;
}// 写线程:排他访问数据(修改数据)
void *write_thread(void *arg) {int id = *(int *)arg;while (1) {// 加写锁(仅一个写线程可获取,读线程需等待)pthread_rwlock_wrlock(&g_rwlock);g_data++;printf("=== 写线程%d:修改g_data为%d ===\n", id, g_data);pthread_rwlock_unlock(&g_rwlock);sleep(3); // 模拟写操作耗时}return NULL;
}int main() {pthread_t tid[4];int ids[4] = {1,2,3,4};pthread_rwlock_init(&g_rwlock, NULL);// 创建2个读线程、2个写线程pthread_create(&tid[0], NULL, read_thread, &ids[0]);pthread_create(&tid[1], NULL, read_thread, &ids[1]);pthread_create(&tid[2], NULL, write_thread, &ids[2]);pthread_create(&tid[3], NULL, write_thread, &ids[3]);// 等待线程(实际中可按需求终止)for (int i = 0; i < 4; i++) {pthread_join(tid[i], NULL);}pthread_rwlock_destroy(&g_rwlock);return 0;
}

POSIX信号量操作函数

函数原型 功能说明 参数说明 返回值 头文件
int sem_init(sem_t *sem, int pshared, unsigned int value); 初始化匿名信号量 - sem:信号量指针
- pshared:0=线程间使用,非0=进程间使用
- value:信号量初始值(资源数量)
成功返回0,失败返回-1 <semaphore.h>
int sem_destroy(sem_t *sem); 销毁匿名信号量 - sem:信号量指针 成功返回0,失败返回-1 <semaphore.h>
int sem_post(sem_t *sem); V操作(释放资源,信号量+1) - sem:信号量指针 成功返回0,失败返回-1 <semaphore.h>
int sem_wait(sem_t *sem); P操作(申请资源,信号量-1,阻塞) - sem:信号量指针 成功返回0,失败返回-1 <semaphore.h>
int sem_trywait(sem_t *sem); P操作(非阻塞版,资源不足返回失败) - sem:信号量指针 成功返回0,失败返回-1 <semaphore.h>
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value); 创建/打开具名信号量(进程间用) - name:信号量名称(/dev/shm/下)
- oflag:打开标记(如O_CREAT)
- mode:文件权限(创建时需指定)
- value:初始值(创建时需指定)
成功返回信号量指针,失败返回SEM_FAILED <semaphore.h><fcntl.h>
int sem_close(sem_t *sem); 关闭具名信号量 - sem:信号量指针 成功返回0,失败返回-1 <semaphore.h>
int sem_unlink(const char *name); 删除具名信号量文件 - name:信号量名称 成功返回0,失败返回-1 <semaphore.h>

匿名信号量示例(线程间同步)

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>sem_t sem; // 匿名信号量(线程间共享)
int g_data = 0;// 线程A:生产数据(V操作释放资源)
void *thread_a(void *arg) {while (1) {g_data++;printf("线程A:生产数据=%d,发送信号\n", g_data);sem_post(&sem); // V操作:信号量+1(资源可用)sleep(2);}return NULL;
}// 线程B:消费数据(P操作申请资源)
void *thread_b(void *arg) {while (1) {sem_wait(&sem); // P操作:信号量-1(无资源则阻塞)printf("线程B:接收信号,消费数据=%d\n", g_data);sleep(1);}return NULL;
}int main() {pthread_t tid1, tid2;// 初始化信号量:线程间使用(pshared=0),初始值=0sem_init(&sem, 0, 0);pthread_create(&tid1, NULL, thread_a, NULL);pthread_create(&tid2, NULL, thread_b, NULL);pthread_join(tid1, NULL);pthread_join(tid2, NULL);sem_destroy(&sem); // 销毁信号量return 0;
}

具名信号量示例(进程间同步)

#include <stdio.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>int main() {// 创建具名信号量:名称"/my_sem",权限0666,初始值0sem_t *sem = sem_open("/my_sem", O_CREAT, 0666, 0);if (sem == SEM_FAILED) {perror("sem_open failed");return 1;}int data = 1;while (1) {printf("进程A:生产数据=%d,释放信号量\n", data);sem_post(sem); // V操作data++;sleep(3);}sem_close(sem);sem_unlink("/my_sem"); // 最后退出的进程删除信号量return 0;
}

条件量操作函数

函数原型 功能说明 参数说明 返回值 头文件
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); 初始化条件量 - cond:条件量指针
- attr:属性(默认NULL)
成功返回0,失败返回错误码 <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond); 销毁条件量 - cond:条件量指针 成功返回0,失败返回错误码 <pthread.h>
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); 阻塞等待条件满足(自动释放互斥锁) - cond:条件量指针
- mutex:关联的互斥锁
成功返回0,失败返回错误码 <pthread.h>
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); 限时等待条件满足 - cond:条件量指针
- mutex:关联的互斥锁
- abstime:超时时间(绝对时间)
成功返回0,超时返回ETIMEDOUT,失败返回错误码 <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond); 唤醒一个等待的线程 - cond:条件量指针 成功返回0,失败返回错误码 <pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cond); 广播唤醒所有等待的线程 - cond:条件量指针 成功返回0,失败返回错误码 <pthread.h>

条件量示例(生产者 - 消费者模型)

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>#define BUF_SIZE 3 // 缓冲区大小
int g_buf[BUF_SIZE]; // 共享缓冲区
int g_idx = 0; // 缓冲区当前索引pthread_mutex_t g_mutex; // 保护缓冲区的互斥锁
pthread_cond_t g_not_full; // 缓冲区非满条件(生产者等待)
pthread_cond_t g_not_empty; // 缓冲区非空条件(消费者等待)// 生产者线程
void *producer(void *arg) {int data = 1;while (1) {pthread_mutex_lock(&g_mutex);// 缓冲区满则等待(释放互斥锁,避免死锁)while (g_idx == BUF_SIZE) {pthread_cond_wait(&g_not_full, &g_mutex);}// 生产数据到缓冲区g_buf[g_idx++] = data;printf("生产者:生产数据%d,缓冲区索引=%d\n", data, g_idx);data++;pthread_mutex_unlock(&g_mutex);pthread_cond_signal(&g_not_empty); // 唤醒消费者(缓冲区非空)sleep(1);}return NULL;
}// 消费者线程
void *consumer(void *arg) {while (1) {pthread_mutex_lock(&g_mutex);// 缓冲区空则等待while (g_idx == 0) {pthread_cond_wait(&g_not_empty, &g_mutex);}// 消费缓冲区数据int data = g_buf[--g_idx];printf("消费者:消费数据%d,缓冲区索引=%d\n", data, g_idx);pthread_mutex_unlock(&g_mutex);pthread_cond_signal(&g_not_full); // 唤醒生产者(缓冲区非满)sleep(2);}return NULL;
}int main() {pthread_t tid_prod, tid_cons;// 初始化互斥锁和条件量pthread_mutex_init(&g_mutex, NULL);pthread_cond_init(&g_not_full, NULL);pthread_cond_init(&g_not_empty, NULL);pthread_create(&tid_prod, NULL, producer, NULL);pthread_create(&tid_cons, NULL, consumer, NULL);pthread_join(tid_prod, NULL);pthread_join(tid_cons, NULL);// 销毁资源pthread_mutex_destroy(&g_mutex);pthread_cond_destroy(&g_not_full);pthread_cond_destroy(&g_not_empty);return 0;
}

UDP通信操作函数

函数原型 功能说明 参数说明 返回值 头文件
int socket(int domain, int type, int protocol); 创建网络通信套接字(UDP/TCP通用) - domain:通信协议(AF_INET=IPv4)
- type:套接字类型(SOCK_DGRAM=UDP)
- protocol:协议控制(默认0)
成功返回文件描述符,失败返回-1 <sys/socket.h>
ssize_t sendto(int sockfd, const void buf[], size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); UDP发送数据 - sockfd:套接字描述符
- buf:发送数据缓冲区
- len:数据长度
- flags:特殊标记(默认0)
- dest_addr:目标地址结构体
- addrlen:地址长度
成功返回发送字节数,失败返回-1 <sys/socket.h>
ssize_t recvfrom(int sockfd, void buf[], size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); UDP接收数据 - sockfd:套接字描述符
- buf:接收数据缓冲区
- len:缓冲区大小
- flags:特殊标记(默认0)
- src_addr:源地址结构体
- addrlen:地址长度(输入输出型)
成功返回接收字节数,失败返回-1 <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 绑定套接字与地址(UDP接收端必需) - sockfd:套接字描述符
- addr:本地地址结构体
- addrlen:地址长度
成功返回0,失败返回-1 <sys/socket.h>
int inet_aton(const char *cp, struct in_addr *inp); 字符串IP转网络字节序整型 - cp:点分十进制IP字符串
- inp:存储结果的in_addr结构体指针
成功返回1,失败返回0 <arpa/inet.h>
in_addr_t inet_addr(const char *cp); 字符串IP转网络字节序整型(简化版) - cp:点分十进制IP字符串 成功返回网络字节序整型,失败返回INADDR_NONE <arpa/inet.h>
char *inet_ntoa(struct in_addr in); 网络字节序整型转字符串IP - in:in_addr结构体(含网络字节序IP) 成功返回IP字符串指针(静态缓冲区) <arpa/inet.h>
uint32_t htonl(uint32_t hostlong); 主机字节序32位整数转网络字节序 - hostlong:主机字节序32位整数 返回网络字节序32位整数 <arpa/inet.h>
uint16_t htons(uint16_t hostshort); 主机字节序16位整数转网络字节序 - hostshort:主机字节序16位整数 返回网络字节序16位整数 <arpa/inet.h>
uint32_t ntohl(uint32_t netlong); 网络字节序32位整数转主机字节序 - netlong:网络字节序32位整数 返回主机字节序32位整数 <arpa/inet.h>
uint16_t ntohs(uint16_t netshort); 网络字节序16位整数转主机字节序 - netshort:网络字节序16位整数 返回主机字节序16位整数 <arpa/inet.h>

UDP 服务器端(接收端)示例

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#define PORT 65000 // 绑定的端口号
#define BUF_SIZE 128 // 缓冲区大小int main() {// 1. 创建UDP套接字int udp_fd = socket(AF_INET, SOCK_DGRAM, 0);if (udp_fd < 0) {perror("socket create failed");return 1;}// 2. 配置本地地址(服务器端必须绑定端口)struct sockaddr_in local_addr = {.sin_family = AF_INET, // IPv4协议.sin_port = htons(PORT), // 主机字节序转网络字节序(端口).sin_addr.s_addr = INADDR_ANY // 绑定所有网卡IP(INADDR_ANY=0.0.0.0)};// 3. 绑定套接字与地址if (bind(udp_fd, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {perror("bind failed");close(udp_fd);return 1;}printf("UDP服务器启动,监听端口%d...\n", PORT);// 4. 循环接收数据char buf[BUF_SIZE] = {0};struct sockaddr_in client_addr; // 存储客户端地址socklen_t client_addr_len = sizeof(client_addr);while (1) {bzero(buf, sizeof(buf)); // 清空缓冲区// 接收客户端数据(阻塞等待)ssize_t recv_len = recvfrom(udp_fd, buf, sizeof(buf)-1, 0,(struct sockaddr *)&client_addr, &client_addr_len);if (recv_len < 0) {perror("recvfrom failed");continue;}// 打印客户端信息和数据printf("收到客户端[%s:%d]的数据(%zd字节):%s\n",inet_ntoa(client_addr.sin_addr), // 网络字节序IP转字符串ntohs(client_addr.sin_port), // 网络字节序端口转主机字节序recv_len, buf);}// 5. 关闭套接字(实际中不会执行到)close(udp_fd);return 0;
}

UDP 客户端(发送端)示例

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#define SERVER_IP "127.0.0.1" // 服务器IP(本地回环地址)
#define SERVER_PORT 65000 // 服务器端口(需与服务器一致)
#define BUF_SIZE 128int main() {// 1. 创建UDP套接字int udp_fd = socket(AF_INET, SOCK_DGRAM, 0);if (udp_fd < 0) {perror("socket create failed");return 1;}// 2. 配置服务器地址struct sockaddr_in server_addr = {.sin_family = AF_INET,.sin_port = htons(SERVER_PORT),.sin_addr.s_addr = inet_addr(SERVER_IP) // 字符串IP转网络字节序};// 3. 循环发送数据char buf[BUF_SIZE] = {0};while (1) {bzero(buf, sizeof(buf));printf("请输入要发送的数据(输入q退出):");fgets(buf, sizeof(buf)-1, stdin);// 退出条件if (strcmp(buf, "q\n") == 0) {printf("客户端退出\n");break;}// 发送数据到服务器ssize_t send_len = sendto(udp_fd, buf, strlen(buf), 0,(struct sockaddr *)&server_addr, sizeof(server_addr));if (send_len < 0) {perror("sendto failed");continue;}printf("发送成功(%zd字节)\n", send_len);}// 4. 关闭套接字close(udp_fd);return 0;
}

其他基础函数

函数原型 功能描述 参数说明 返回值说明 头文件 关键注意事项
int printf(const char *format, ...) 按指定格式将可变参数数据输出到标准输出(屏幕),等价于fprintf(stdout, format, ...) - formatconst char*,格式控制字符串
- ...:可变参数,与format的格式符对应
成功:返回实际输出的字节数
失败:返回负数
<stdio.h> 1. 等价于fprintf(stdout, format, ...)
2. 标准输出默认行缓冲,加\nfflush(stdout)可刷新
int scanf(const char *format, ...) 按指定格式从标准输入(键盘)读取数据,存储到指定变量,等价于fscanf(stdin, format, ...) - formatconst char*,格式控制字符串
- ...:可变参数,需传变量地址(如&a
成功:返回成功赋值的参数个数
失败/EOF:返回EOF
<stdio.h> 1. 等价于fscanf(stdin, format, ...)
2. 读取字符串用%s,遇空白符停止;需确保缓冲区足够大
int getchar(void) 从标准输入(键盘)读取单个字符,等价于fgetc(stdin),支持字符级输入 无参数 成功:返回读取的字符(ASCII值)
失败/EOF:返回EOF
<stdio.h> 1. 等价于fgetc(stdin)
2. 每次读取1个字符,包括换行符\n
int putchar(int c) 向标准输出(屏幕)写入单个字符,等价于fputc(c, stdout),支持字符级输出 - c:int,要输出的字符(ASCII值) 成功:返回输出的字符
失败:返回EOF
<stdio.h> 1. 等价于fputc(c, stdout)
2. 每次输出1个字符
int access(const char *pathname, int mode) 检查指定文件是否存在,以及当前进程对文件的访问权限(读、写、执行) - pathnameconst char*,文件路径/名称
- mode:int,检查的权限:
- F_OK:检查文件是否存在
- R_OK:检查是否可读
- W_OK:检查是否可写
- X_OK:检查是否可执行
成功:所有检查的权限都满足,返回0
失败:至少一个权限不满足,返回-1,并设置errno
<unistd.h> 1. 检查当前进程对文件的权限(基于进程的UID/GID)
2. 示例:`access("test.txt", F_OK

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/969133.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB实现的基于压缩感知的图像处理

1. 参数设置 % 图像参数 imageSize = [256, 256]; % 图像大小 patchSize = [8, 8]; % 图像块大小 stepSize = 4; % 步长% 压缩感知参数 numAtoms = 256; % 字典中原子数量 numIterations = 10; % 稀疏分解迭代次数 lam…

AI变革,企业如何应用AI大模型重塑思考维度?

中国虽是多条AI赛道的领跑者,企业部署AI的速度却慢了一步“中国虽是多条AI赛道的领跑者,企业部署AI的速度却慢了一步。”这是一个不争的事实。 日常的AI应用场景千千万,不止于简单的检索信息、编写代码、生成表格,…

还是得要耐心--从淘宝数据线中考虑到的

还是得要耐心--从淘宝数据线中考虑到的真打脸,就是那个前脚刚说就是需要耐心一点,今天收到了淘宝上面买的曼柯洛希旗舰店里面买的两次的充电线。并没有插头,只有USB-Type C接口的线,但是没问题,本来我之前也有插头…

比较好的空气检测服务

摘要 随着室内空气污染问题日益受到关注,2025年空气检测行业迎来快速发展,家装和工装用户对健康环境的需求激增。本文基于行业数据和用户口碑,综合评估国内空气检测服务商,为您提供权威排名和选择指南。表单仅供参…

2025年建材连锁ERP软件前十名分析:四大主流系统评测

2025年建材连锁ERP软件前十名分析:四大主流系统评测寻找适合建材连锁的ERP软件?本文深入分析2025年市场上进入前十名行列的四款主流ERP系统,提供客观的优缺点对比,帮助建材企业做出合适的选择。2025年建材连锁企业…

2025年安徽合肥异味治理服务口碑推荐排行榜

摘要 随着人们对室内空气质量的日益重视,异味治理行业在2025年迎来了快速发展期。安徽省合肥市作为长三角城市群副中心,异味治理市场需求持续增长。本文基于行业数据分析和用户真实反馈,为您推荐合肥地区口碑优异的…

正规的甲醛检测平台推荐几家

摘要 随着室内空气质量问题日益受到关注,2025年甲醛检测行业迎来快速发展期。据统计,我国室内环境检测市场规模已突破200亿元,年均增长率达15%以上。本文基于权威数据分析和用户真实评价,为您推荐五家正规可靠的甲…

Kafka-配置SASL/SCRAM认证

1. 创建admin用户 如果选择SCRAM机制,首先需要创建用户凭证。假设要创建一个用户名为admin,密码为admin的用户。 # 进入Kafka的安装目录 cd /usr/local/kafka-3.7.0 bin/kafka-configs.sh --bootstrap-server …

2025年潜水泵厂家实力榜:轴流水泵、潜水轴流泵、轴流潜水泵、卧式混流水泵、品类五家企业凭技术与口碑出圈

随着城市给排水、农田灌溉、工业循环等领域需求的持续增长,水泵作为核心流体输送设备,其产品性能、可靠性与适配能力成为市场关注焦点。在潜水泵、轴流水泵、混流水泵等主流品类中,一批兼具技术创新能力与服务意识的…

QT中groupbox填满整个页面

在Qt Designer中可视化操作 如果您使用Qt Designer进行界面设计,操作会更加直观-9:将Group Box拖放到主窗体上。确保Group Box被选中,然后右键单击主窗体的空白区域。选择布局菜单,然后选择一个布局方式,例如水平…

视频编辑的新成果!港科大蚂蚁集团提出Ditto框架刷新SOTA!

论文标题:Scaling Instruction-Based VideoEditing with a High-Quality Synthetic Dataset作者团队:香港科大、蚂蚁集团、浙江大学、东北大学 发布时间:2025年10月17日 👉一键直达论文 [👉Lab4AI大模型实验室论…

2025年气体减压阀厂家实力榜:大流量气体减压阀,不锈钢氮气减压阀,不锈钢泄压阀,实验室气体减压阀、多品类阀门企业凭技术与口碑出圈

随着高端制造、生物医药等领域对流体控制精度要求的持续提升,气体减压阀作为核心控制部件,其安全性与稳定性成为市场关注焦点。在不锈钢减压阀、实验室减压阀等主流品类中,一批兼具研发能力与服务意识的企业脱颖而出…

2025年市场朋友圈计划平台榜单top10:权威解析与推荐

摘要 2025年,朋友圈计划平台行业随着数字健康和电商整合的浪潮迅猛发展,专注于大健康产业的服务商成为市场热点。本文基于行业数据和用户口碑,为您呈现2025年市场朋友圈计划平台排行榜前十强,并附上详细解析,帮助…

sub-1G收发芯片DP4330A低成本解决方案OOK /(G)FSK 等多种调制方式远距离 - 动能世纪

产品简介 DP4330A 是一款超低功耗、高集成度、高性能、适用于 Sub-1GHz 频段无线应用的射频收 发器。它具有 1.8V - 3.6V 较宽的输入电压范围,最大发射功率可达到 20dBm,最低灵敏度可达120dBm。它支持OOK 、(G)FSK…

2025年惠州青少年素质教育机构权威推荐榜单:青少年专门教育/感恩教育/沉迷游戏矫正源头机构精选

青少年行为矫正市场需求持续增长,其中科学的教育理念与专业的师资队伍已成为家长选择素质教育机构的核心考量因素。 随着社会对青少年心理健康重视程度的提高,专业素质教育机构通过心理辅导、行为矫正、感恩教育等多…

jQuery的.each()方法中return的坑

jQuery的.each()方法中return的坑

深入解析:文本描述驱动的可视化工具在IDE中的应用与实践

深入解析:文本描述驱动的可视化工具在IDE中的应用与实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas…

模型训练场景5090和4090的算力比较

测试下英伟达这款最新的消费级旗舰和上一代RTX 4090在模型训练场景下性能差异多大?5090的32G的容量比4090增加8G,显存带宽有大幅的提升,5090的算力比4090提升近30%。 基于Pytorch框架来训练ResNet-50模型,使用CIFA…

00.课程导学

00.课程导学视频课程:https://www.bilibili.com/video/BV1821CY8E2d/?spm_id_from=333.1387.search.video_card.click 0.1 课程设计1.基本语法2.面向对象3.常用API4.IO流5.多线程6.网络编程7.AI应用开发7.1GPT原理7.…

2025年羊毛地毯品牌哪家好?权威排行Top10推荐

摘要 羊毛地毯行业在2025年持续蓬勃发展,随着消费者对家居品质和环保需求的提升,手工编织、天然材质的羊毛地毯成为市场热点。本文基于行业数据、用户口碑和专家评测,为您呈现2025年评价高的羊毛地毯厂家Top10排名,…