1.1.1 C语言常用的一些函数(持续更新)

总框架见(0. 总框架-CSDN博客
(1)socket

(a)分配fd;(b)分配tcp控制块(tcb)

cpp 复制代码
int socket(int domain, int type, int protocol);

       AF_INET             IPv4 Internet protocols          ip(7)
       AF_INET6            IPv6 Internet protocols          ipv6(7)
       AF_IPX              IPX - Novell protocols
(2)bind

把fd和ip绑定到tcp控制块

cpp 复制代码
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
(3)listen

开始监听fd

cpp 复制代码
int listen(int sockfd, int backlog);
(4)accept

(a)为客户端分配fd;(b)分配tcp控制块(tcb)

cpp 复制代码
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
(5)recv

从内核copy数据到用户空间

cpp 复制代码
 ssize_t recv(int sockfd, void *buf, size_t len, int flags);
(6)send

从用户空间copy数据到内核

cpp 复制代码
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
(7)connect

connect客户端发送连接请求

cpp 复制代码
 int connect(int sockfd, const struct sockaddr *addr,
                   socklen_t addrlen);
(8)epoll_create
cpp 复制代码
int epoll_create(int size);
(9)epoll_ctl
cpp 复制代码
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

    EPOLL_CTL_ADD       EPOLLIN        EPOLLLT 
    EPOLL_CTL_MOD       EPOLLOUT       EPOLLET
    EPOLL_CTL_DEL
(10)epoll_wait
cpp 复制代码
int epoll_wait(int epfd, struct epoll_event *events,
                      int maxevents, int timeout);
(11)poll
cpp 复制代码
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
(12)select
cpp 复制代码
int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

       void FD_CLR(int fd, fd_set *set);
       int  FD_ISSET(int fd, fd_set *set);
       void FD_SET(int fd, fd_set *set);
       void FD_ZERO(fd_set *set);
(13)read
cpp 复制代码
ssize_t read(int fd, void *buf, size_t count);

参数说明
int fd
文件描述符,表示要读取的文件、管道、套接字或设备。
通常由系统调用(如 open()、socket() 等)返回。
void *buf
指向接收读取数据的缓冲区指针。
系统调用会将读取的数据写入到此缓冲区。
size_t count
要读取的最大字节数,指定缓冲区的大小。

返回值
成功时:
返回读取的字节数(可能小于请求的字节数 count)。
返回 0 表示已到达文件末尾(EOF)。
失败时:
返回 -1,并设置全局变量 errno 来指示错误原因
(14)write
cpp 复制代码
ssize_t write(int fd, const void *buf, size_t count);

参数说明
int fd
文件描述符,表示数据要写入的目标。
通常由 open() 或 socket() 等函数返回。
const void *buf
指向包含要写入数据的缓冲区的指针。
size_t count
指定要写入的字节数

返回值
成功时:
返回实际写入的字节数(可能小于请求的字节数 count)。
失败时:
返回 -1,并设置全局变量 errno 表示错误原因。
(15)fork

创建的新进程,它是父进程的一个副本,几乎所有的数据(变量、文件描述符等)都会被复制。

cpp 复制代码
返回值
父进程中:fork() 返回子进程的 PID(正整数)。
子进程中:fork() 返回 0。
出错时:返回 -1,同时设置 errno
(16)perror

读取系统定义的全局变量 errno,然后通过查找对应的错误码输出一个与其相关联的错误消息

cpp 复制代码
int main() {
    int fd = open("nonexistent_file.txt", O_RDONLY);
    if (fd == -1) {
        perror("Error opening file");
    }
    return 0;

输出:
Error opening file: No such file or directory
(17)strerror

如果需要获取错误描述并在代码中使用,而不是直接打印,可以使用 strerror(errno)。

cpp 复制代码
#include <string.h>
printf("Error: %s\n", strerror(errno));
(18)atoi

是 C 标准库中用于将字符串转换为整数的函数。atoi 是 ASCII to Integer 的缩写。

cpp 复制代码
int atoi(const char *str);

参数
str
指向需要转换的字符串(应以空字符 \0 结束)。

返回值
如果字符串可以成功解析为整数,则返回该整数值。
如果字符串不包含有效的数字,则返回值可能为 0(不安全,推荐使用 strtol 替代)。

int main() {
    char str1[] = "   -456";
    char str2[] = "+789";

    printf("Converted number 1: %d\n", atoi(str1)); 
    // Output: -456
    printf("Converted number 2: %d\n", atoi(str2)); 
    // Output: 789
    return 0;
}
(19)strcmp

是 C 标准库中的一个函数,用于比较两个字符串的大小(基于字典序)。

cpp 复制代码
int strcmp(const char *str1, const char *str2);

参数解释
str1
指向第一个字符串的指针。
str2
指向第二个字符串的指针

返回值
小于 0
如果 str1 的字典序小于 str2。
等于 0
如果 str1 和 str2 内容完全相同。
大于 0
如果 str1 的字典序大于 str2

int main() {
    char str1[] = "apple";
    char str2[] = "banana";

    int result = strcmp(str1, str2);
    printf("Result: %d\n", result); 
    // Output: Result: negative value (e.g., -1)
    return 0;
}
(20)memset

是 C 标准库中的一个函数,主要用于对一块内存区域进行初始化或设置。

cpp 复制代码
void *memset(void *s, int c, size_t n);

参数说明
void *s
指向要初始化的内存区域的起始地址。
int c
用于设置的值,会被解释为一个 unsigned char(0 到 255),然后复制到内存区域。
size_t n
要设置的字节数。

返回值
返回指向内存区域 s 的指针。
功能
将指定的值填充到连续的内存区域中。
常用于数组或结构体的初始化。

常见用途
功能1:初始化数组
使用 memset 将数组清零或设置为某个默认值。
int arr[10];
memset(arr, 0, sizeof(arr)); // 初始化为 0

功能2:清空结构体中的所有成员变量。
struct Data {
    int a;
    char b[20];
} data;
memset(&data, 0, sizeof(data)); // 将结构体清零
(21)memcpy

是 C 标准库中的一个函数,将内存块中的数据从一个位置复制到另一个位置。

cpp 复制代码
void *memcpy(void *dest, const void *src, size_t n);

参数说明
void *dest
目标内存地址,表示复制数据的目的地。
const void *src
源内存地址,表示复制数据的来源。
size_t n
要复制的字节数。

返回值
返回目标内存地址 (dest) 的指针。

基本用法
int main() {
    char src[] = "Hello, World!";
    char dest[20];
    memcpy(dest, src, strlen(src) + 1);  
    // 复制 src 到 dest
    printf("Source: %s\n", src);
    printf("Destination: %s\n", dest);
    return 0;
}

输出:
Source: Hello, World!
Destination: Hello, World!

int main() {
    int src[5] = {1, 2, 3, 4, 5};
    int dest[5];
    memcpy(dest, src, 5 * sizeof(int));  // 复制 5 个整型值
    for (int i = 0; i < 5; i++) {
        printf("dest[%d] = %d\n", i, dest[i]);
    }
    return 0;
}

输出:
dest[0] = 1
dest[1] = 2
dest[2] = 3
dest[3] = 4
dest[4] = 5

应用场景
字符串操作:复制字符串的原始字节数据(与 strcpy 的主要区别是 memcpy 可以复制非空终止的二进制数据)。
数组复制:处理任意类型的数组,例如 int 或 float。
内存初始化:与 memset 配合使用,分配和初始化内存。
结构体复制:在需要字节级拷贝时,处理复杂结构体数据。
(22)strncpy

复制字符串的指定长度

cpp 复制代码
char *strncpy(char *dest, const char *src, size_t n);

参数说明
char *dest
目标字符数组的指针,复制后的字符串将存储在这里。
const char *src
源字符串的指针,要被复制的字符串内容。
size_t n
要复制的最大字符数。如果 src 长度小于 n,则目标字符串会填充空字符(\0);如果 src 长度大于或等于 n,则目标字符串不会被空字符终止。

返回值
返回 dest 指针,即目标字符串的指针。

功能
将源字符串 src 复制到目标字符数组 dest 中,最多复制 n 个字符。
如果源字符串长度小于 n,strncpy 会用空字符(\0)填充目标字符串的剩余部分;如果源字符串长度大于或等于 n,目标字符串没有终止符(\0)。

与 strcpy 的对比
strcpy:直接复制整个字符串,直到遇到终止符 \0。无法防止溢出。
例如:strcpy(dest, src);
strncpy:复制指定数量的字符,并会根据情况使用终止符 \0 填充目标字符串。
更安全,因为可以限制复制的字符数,防止溢出

int main() {
    char src[] = "Hello, World!";
    char dest[20];
    // 将最多 10 个字符从 src 复制到 dest
    strncpy(dest, src, 10);
    dest[10] = '\0';  // 确保终止符
    printf("Copied string: %s\n", dest);  
    // 输出: Hello, Wo
    return 0;
}

代码解析
strncpy(dest, src, 10);:最多复制 10 个字符。
然后手动添加终止符 dest[10] = '\0';,这是因为源字符串可能没有包含终止符(在字符串更长的情况下)。
结果是 dest 中的内容为 "Hello, Wo",因为 src 前 10 个字符被复制。
(23)strlen
cpp 复制代码
size_t strlen(const char *str);

功能
strlen 用于计算字符串的长度(不包括终止符 \0)。
它会遍历字符串直到遇到第一个空字符 \0 为止,并返回已遍历的字符数。
参数说明
const char *str
指向以空字符 \0 结尾的字符串。
返回值
返回字符串的长度(不包括终止符 \0)的大小,以 size_t 类型表示。

int main() {
    char str[] = "Hello, World!";
    size_t length = strlen(str);
    printf("The length of the string is: %zu\n", length); 
    // 输出: 13
    return 0;
}

代码解析
字符串 str[]:
包含 "Hello, World!",长度为 13(不包括终止符 \0)。
strlen(str):
遍历字符串,直到遇到终止符 \0。
计算字符数:'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!'。
返回值:
返回 13,表示字符串的长度

与 sizeof 的对比
strlen运行时计算字符串长度。适用于动态字符串。不包括终止符 \0。
sizeof编译时计算数组大小(字节数)。适用于固定大小的字符数组。包括终止符 \0 的大小。
示例:
char str1[] = "Hello";
char *str2 = "Hello";
printf("strlen(str1): %zu\n", strlen(str1));  // 输出 5
printf("sizeof(str1): %zu\n", sizeof(str1));  // 输出 6
printf("strlen(str2): %zu\n", strlen(str2));  // 输出 5
printf("sizeof(str2): %zu\n", sizeof(str2));  // 输出 8 (指针大小)
(24)snprint

用于将格式化的数据写入字符串,并确保不会溢出字符串缓冲区。它是 sprintf 的更安全版本,避免了可能的缓冲区溢出问题。

cpp 复制代码
int snprintf(char *str, size_t size, const char *format, ...);

参数说明
char *str
指向要写入格式化输出的字符数组。
size_t size
指定目标字符串的最大大小,包括结尾的 '\0'(空字符)。snprintf 确保总输出长度不超过这个值。
const char *format
格式化字符串,与 printf 的格式化字符串类似,例如 %d, %s, %f 等。
... (可变参数)
需要插入到格式化字符串中的数据

返回值
返回写入的字符数,不包括终止的 \0 字符:
如果 size 足够大,返回值是实际写入的字符数。
如果 size 不够大,返回值是本应该写入的字符数(截断的字符串长度)。

缓冲区不足的情况
int main() {
    char buffer[10];
    int num = 123456;
    int written = snprintf(buffer, sizeof(buffer), "Number: %d", num);
    printf("Formatted string: %s\n", buffer);  // 输出截断的内容
    printf("Characters written: %d\n", written);  // 返回未截断的实际字符数
    return 0;
}

输出:
Formatted string: Number: 1
Characters written: 12
说明:
缓冲区 buffer 长度为 10,无法容纳完整字符串 "Number: 123456"。
结果字符串被截断为 "Number: 1",但 snprintf 的返回值是实际所需的字符数 12
(25)malloc

堆上分配内存,并返回指向分配内存块的指针。

cpp 复制代码
void *malloc(size_t size);

参数说明
size
请求分配的内存大小(以字节为单位)。size 必须大于 0。

返回值
返回分配的内存的起始地址,类型是 void*,即通用指针。
如果内存分配失败(比如系统没有足够的内存),malloc 返回 NULL。

特性
动态内存分配
malloc 函数从程序的堆内存区域(Heap)分配指定大小的内存。在堆上分配的内存空间不会随着函数调用结束而销毁,必须通过 free 显式释放。

基本用法
int main() {
    int *arr = (int *)malloc(5 * sizeof(int));  // 动态分配 5 个整数的空间
    if (arr == NULL) {
        printf("Memory allocation failed!\n");
        return 1;
    }
    for (int i = 0; i < 5; i++) {
        arr[i] = i + 1;
        printf("%d ", arr[i]);
    }
    printf("\n");
    free(arr);  // 释放内存
    return 0;
}

输出:
1 2 3 4 5
(26)free

用于释放由动态内存分配函数(如 malloc、calloc 或 realloc)分配的内存。将之前分配的动态内存归还给操作系统或内存管理器。释放后,该内存块可以被再次分配和使用。

cpp 复制代码
void free(void *ptr);

参数说明
void *ptr
动态分配的内存块的指针,该指针通常是通过 malloc、calloc 或 realloc 返回的。
如果 ptr 是 NULL,free 不会进行任何操作。

基本用法
int main() {
    int *arr = (int *)malloc(5 * sizeof(int));  // 动态分配 5 个整数的空间
    if (arr == NULL) {
        perror("malloc failed");
        return 1;
    }
    for (int i = 0; i < 5; i++) {
        arr[i] = i + 1;
        printf("%d ", arr[i]);
    }
    printf("\n");
    free(arr);  // 释放内存
    arr = NULL; // 避免悬空指针
    return 0;
}

输出:
1 2 3 4 5

常见问题
1. 为什么释放未分配的内存是危险的?
如果尝试 free 一个未分配的指针,可能会导致程序崩溃或者未定义行为,因为内存管理器试图释放一个它没有跟踪的内存区域。
2. 为什么要将指针置为 NULL?
避免悬空指针(Dangling Pointer)。
悬空指针是指指向已释放内存区域的指针,如果不小心使用它(如读写操作),可能会导致不可预测的错误。
3. 始终配对 malloc 和 free,避免内存泄漏和悬空指针。
相关推荐
寻星探路4 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
七夜zippoe7 小时前
CANN Runtime任务描述序列化与持久化源码深度解码
大数据·运维·服务器·cann
盟接之桥7 小时前
盟接之桥说制造:引流品 × 利润品,全球电商平台高效产品组合策略(供讨论)
大数据·linux·服务器·网络·人工智能·制造
会员源码网8 小时前
理财源码开发:单语言深耕还是多语言融合?看完这篇不踩坑
网络·个人开发
米羊1218 小时前
已有安全措施确认(上)
大数据·网络
Fcy6488 小时前
Linux下 进程(一)(冯诺依曼体系、操作系统、进程基本概念与基本操作)
linux·运维·服务器·进程
袁袁袁袁满8 小时前
Linux怎么查看最新下载的文件
linux·运维·服务器
代码游侠9 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
主机哥哥9 小时前
阿里云OpenClaw部署全攻略,五种方案助你快速部署!
服务器·阿里云·负载均衡
Harvey9039 小时前
通过 Helm 部署 Nginx 应用的完整标准化步骤
linux·运维·nginx·k8s