掌握标准库strings.h ,高效处理嵌入式内存操作和字符串处理全解析
目录
1. void *memchr(const void *s, int c, size_t n)
2. int memcmp(const void *s1, const void *s2, size_t n)
3. void *memcpy(void *__restrict dest, const void *__restrict src, size_t n)
4. void *memmove(void *dest, const void *src, size_t n)
5. void *memset(void *s, int c, size_t n)
1. char *strcat(char *__restrict dest, const char *__restrict src)
2. char *strchr(const char *s, int c)
3. int strcmp(const char *s1, const char *s2)
4. int strcoll(const char *s1, const char *s2)
5. char *strcpy(char *__restrict dest, const char *__restrict src)
6. size_t strcspn(const char *s, const char *reject)
8. size_t strlen(const char *s)
9. char *strncat(char *__restrict dest, const char *__restrict src, size_t n)
10. int strncmp(const char *s1, const char *s2, size_t n)
11. char *strncpy(char *__restrict dest, const char *__restrict src, size_t n)
12. char *strpbrk(const char *s, const char *accept)
13. char *strrchr(const char *s, int c)
14. size_t strspn(const char *s, const char *accept)
15. char *strstr(const char *haystack, const char *needle)
16. char *strtok(char *__restrict str, const char *__restrict delim)
strings.h 是 C 语言标准库中用于内存操作和字符串处理的核心头文件,包含的函数可分为两类:内存操作函数(mem 开头,按字节处理任意数据)和字符串操作函数(str 开头,处理以 '\0' 结尾的字符串)。以下是对这些高频函数的详细解析:
一、内存操作函数(mem 系列)
内存操作函数不依赖数据类型,直接按字节处理内存块,适用于任何数据(字符、整数、结构体等),需显式指定操作的字节长度。
1. void *memchr(const void *s, int c, size_t n)
- 功能:在内存块
s的前n个字节中,查找第一个值为c(取低 8 位,即c & 0xFF)的字节。 - 参数:
s:待查找的内存块起始地址(const 表示不修改原内存)。c:要查找的字符(以 int 传入,实际用低 8 位)。n:最大查找字节数。
- 返回值:找到时返回该字节的地址;未找到或
n=0时返回NULL。 - 示例:
char buf[] = "abc123"; char *p = memchr(buf, '1', 6); // p 指向 buf[3]('1' 的位置)
2. int memcmp(const void *s1, const void *s2, size_t n)
- 功能:比较内存块
s1和s2的前n个字节(按字节的 ASCII 码值比较)。 - 参数:
s1、s2:两个待比较的内存块。n:比较的字节数。
- 返回值:
- 0:前
n字节完全相同; - 正数:
s1中第一个不同字节 >s2中对应字节; - 负数:
s1中第一个不同字节 <s2中对应字节。
- 0:前
- 注意:与
strcmp不同,memcmp不关心'\0',严格比较n字节(即使包含'\0')。 - 示例:
char a[] = "abc", b[] = "abd"; memcmp(a, b, 3); // 返回 -1('c' < 'd')
3. void *memcpy(void *__restrict dest, const void *__restrict src, size_t n)
- 功能:从源内存块
src复制n字节到目标内存块dest。 - 参数:
dest:目标内存块(需有足够空间)。src:源内存块(const 表示不修改)。n:复制的字节数。__restrict:C99 关键字,表明dest和src无内存重叠(编译器可优化)。
- 返回值:目标内存块
dest的起始地址。 - 风险:若
dest和src内存重叠(如同一数组内复制),可能导致数据覆盖错误(需用memmove替代)。 - 示例:
int src[3] = {1,2,3}, dest[3]; memcpy(dest, src, 3*sizeof(int)); // dest 被复制为 {1,2,3}
4. void *memmove(void *dest, const void *src, size_t n)
- 功能:与
memcpy相同(复制n字节),但支持dest和src内存重叠。 - 实现逻辑:若内存重叠,会先将
src数据临时缓存(或从尾部向头部复制),避免覆盖,因此更安全,但效率略低于memcpy。 - 使用场景:当不确定
dest和src是否重叠时(如同一数组内移动数据),优先用memmove。 - 示例:
char buf[] = "abcdef"; memmove(buf+2, buf, 4); // 从 buf[0] 复制 4 字节到 buf[2],结果为 "ababcf"(安全)
5. void *memset(void *s, int c, size_t n)
- 功能:将内存块
s的前n字节全部设置为c(取低 8 位)。 - 参数:
s:目标内存块。c:要设置的字符(如0表示清零)。n:设置的字节数。
- 返回值:内存块
s的起始地址。 - 常见用途:初始化内存(如数组清零、缓冲区填充)。
- 注意:不能直接用于初始化非字符类型(如
float、int),因为按字节设置(如memset(arr, 1, 4)对 int 来说是0x01010101,而非1)。 - 示例:
char buf[10]; memset(buf, 0, 10); // 数组全部清零
二、字符串操作函数(str 系列)
字符串操作函数仅处理以 '\0' 结尾的字符串(遇到 '\0' 自动停止),无需显式指定长度,但需确保字符串正确终止(否则可能越界)。
1. char *strcat(char *__restrict dest, const char *__restrict src)
- 功能:将源字符串
src追加到目标字符串dest的末尾(覆盖dest原有的'\0',并在最后添加新'\0')。 - 参数:
dest:目标字符串(需有足够空间容纳src,且dest和src无重叠)。src:源字符串(const 表示不修改)。
- 返回值:目标字符串
dest的起始地址。 - 风险:若
dest空间不足,会导致缓冲区溢出(推荐用strncat替代)。 - 示例:
char dest[20] = "Hello, "; strcat(dest, "World!"); // dest 变为 "Hello, World!"
2. char *strchr(const char *s, int c)
- 功能:在字符串
s中查找字符c(取低 8 位)第一次出现的位置。 - 参数:
s:待查找的字符串。c:要查找的字符('\0'也会被查找)。
- 返回值:找到时返回该字符的地址;未找到返回
NULL。 - 与
memchr区别:strchr遇到'\0'停止,memchr按指定长度查找。 - 示例:
char *p = strchr("abcabc", 'b'); // p 指向第一个 'b'(索引 1)
3. int strcmp(const char *s1, const char *s2)
- 功能:比较两个字符串(逐个字符比较 ASCII 码,直到遇到
'\0'或不同字符)。 - 返回值:
- 0:两字符串完全相同;
- 正数:
s1中第一个不同字符 >s2中对应字符; - 负数:
s1中第一个不同字符 <s2中对应字符。
- 与
memcmp区别:strcmp依赖'\0'终止,memcmp需指定长度。 - 示例:
strcmp("apple", "app"); // 返回正数("apple" 更长,且前 3 字符相同)
4. int strcoll(const char *s1, const char *s2)
- 功能:类似
strcmp,但比较规则依赖当前语言环境(locale)(如多语言排序)。 - 场景:需要按本地化规则比较字符串时使用(如德语、法语的特殊字符排序),默认 locale 下与
strcmp效果一致。
5. char *strcpy(char *__restrict dest, const char *__restrict src)
- 功能:将源字符串
src复制到目标dest(包括'\0')。 - 风险:若
dest空间不足(无法容纳src及'\0'),会导致缓冲区溢出(推荐用strncpy替代)。 - 示例:
char dest[10]; strcpy(dest, "test"); // dest 为 "test\0..."(剩余字节未初始化)
6. size_t strcspn(const char *s, const char *reject)
- 功能:计算字符串
s中连续不包含reject中任何字符的最大长度(从开头算起)。 - 返回值:满足条件的长度(若
s开头就有reject中的字符,返回 0)。 - 示例:
strcspn("abc123", "123"); // 返回 3(前 3 个字符 'a','b','c' 不在 reject 中)
7. char *strerror(int errnum)
- 功能:根据错误码
errnum(如errno)返回对应的错误信息字符串(如 "Permission denied")。 - 注意:返回的字符串可能是静态缓冲区,线程不安全(线程安全版本为
strerror_r)。 - 示例:
#include <errno.h> printf("%s\n", strerror(ENOENT)); // 输出 "No such file or directory"
8. size_t strlen(const char *s)
- 功能:计算字符串
s的长度(不包含终止符'\0')。 - 返回值:字符个数(遇到
'\0'停止,若字符串无'\0',会越界访问)。 - 示例:
strlen("hello"); // 返回 5('h','e','l','l','o')
9. char *strncat(char *__restrict dest, const char *__restrict src, size_t n)
- 功能:与
strcat类似,但最多追加n个字符(从src取前n个,或到src的'\0'为止),最后自动添加'\0'。 - 安全点:限制追加长度,避免溢出(
dest需至少strlen(dest) + n + 1字节)。 - 示例:
char dest[20] = "Hello, "; strncat(dest, "World!!!", 5); // 追加前 5 字符 "World",dest 为 "Hello, World\0"
10. int strncmp(const char *s1, const char *s2, size_t n)
- 功能:类似
strcmp,但最多比较前n个字符(或遇到'\0'停止)。 - 安全点:避免长字符串比较的性能问题或越界风险。
- 示例:
strncmp("apple", "apples", 5); // 返回 0(前 5 字符相同)
11. char *strncpy(char *__restrict dest, const char *__restrict src, size_t n)
- 功能:复制
src的前n个字符到dest(若src长度 <n,剩余部分用'\0'填充;若src长度 ≥n,不自动添加'\0')。 - 注意:
- 若
src长度 ≥n,dest可能没有'\0',需手动添加(否则不是有效字符串)。 - 比
strcpy安全,但仍需确保dest长度 ≥n。
- 若
- 示例:
char dest[10]; strncpy(dest, "test", 10); // dest 为 "test\0\0\0\0\0\0"(剩余 6 字节补 '\0')
12. char *strpbrk(const char *s, const char *accept)
- 功能:在
s中查找第一个属于accept中任意字符的位置。 - 返回值:找到的字符地址;未找到返回
NULL。 - 示例:
strpbrk("abc123", "xyz1"); // 返回指向 '1' 的指针('1' 在 accept 中)
13. char *strrchr(const char *s, int c)
- 功能:与
strchr类似,但查找字符c在s中最后一次出现的位置。 - 示例:
strrchr("abcabc", 'b'); // 返回指向最后一个 'b'(索引 4)的指针
14. size_t strspn(const char *s, const char *accept)
- 功能:与
strcspn相反,计算s中连续包含accept中字符的最大长度(从开头算起)。 - 示例:
strspn("aabbcc", "abc"); // 返回 6(所有字符都在 accept 中)
15. char *strstr(const char *haystack, const char *needle)
- 功能:在字符串
haystack中查找子串needle第一次出现的位置(needle为空串时返回haystack)。 - 返回值:子串起始地址;未找到返回
NULL。 - 示例:
strstr("hello world", "lo"); // 返回指向 "lo world" 中 'l' 的指针
16. char *strtok(char *__restrict str, const char *__restrict delim)
- 功能:分割字符串
str为多个子串,分隔符为delim中的任意字符。 - 使用规则:
- 第一次调用:
str传入待分割字符串(会被修改,用'\0'替换分隔符)。 - 后续调用:
str传NULL,继续分割上一次的字符串。 - 内部使用静态变量记录分割位置,线程不安全(线程安全版本为
strtok_r)。
- 第一次调用:
- 返回值:当前分割到的子串地址;无更多子串返回
NULL。 - 示例:
char str[] = "a,b,c"; char *p = strtok(str, ","); // p = "a" p = strtok(NULL, ","); // p = "b" p = strtok(NULL, ","); // p = "c"
三、关键区别与使用建议
-
内存函数 vs 字符串函数:
- 内存函数(
mem*):处理任意内存块,需指定长度,不依赖'\0'。 - 字符串函数(
str*):仅处理'\0'结尾的字符串,自动停止,无需指定长度。
- 内存函数(
-
安全问题:
- 避免使用
strcpy、strcat(无长度限制,易溢出),改用strncpy、strncat(需手动处理'\0')。 - 内存重叠时用
memmove而非memcpy。
- 避免使用
-
线程安全:
strtok线程不安全,多线程环境用strtok_r(POSIX 标准)。
掌握这些函数的细节,能有效处理嵌入式开发中的内存和字符串操作,避免常见的缓冲区溢出、越界访问等问题。
更多推荐


所有评论(0)