C 字符串 API <string.h>
1. 概述
1.1 关于 <string.h>
<string.h>
中提供了很多字符串操作函数和字符串检验函数。
1.2 关于字符串
- 空终止字节字符串 (Null-terminated byte string, NTBS)
- 空终止多字节字符串 (Null-terminated multibyte string, NTMBS)
1.3 字典序
2. 字符串检验
字符串长度
strlen()
定义:
csize_t strlen( const char* str );
用途:计算
str
所指的空终止字节字符串的长度(不包括末尾的终止符)。示例:
c#include <stdio.h> #include <string.h> int main(void) { const char *s = "mdr"; printf("%zu\n", strlen(s)); }
可能输出为
3
字符串比较
strcmp()
定义:
cint strcmp( const char* lhs, const char* rhs );
用途:按照 字典序 比较
lhs
和rhs
所指的空终止字节字符串。- 如果
lhs
先于rhs
,返回值为 负数; - 如果
lhs
等于rhs
,返回值为 零: - 如果
lhs
后于rhs
,返回值为 正数。
- 如果
示例:
c#include <stdio.h> #include <string.h> void demo(const char* lhs, const char* rhs) { const int rc = strcmp(lhs, rhs); const char* rel = rc < 0 ? "先于" : rc > 0 ? "后于" : "等于"; printf("[%s] %s [%s]\n", lhs, rel, rhs); } int main(void) { const char* string = "Hello World!"; demo(string, "Hello!"); demo(string, "Hello"); demo(string, "Hello there"); demo("Hello, everybody!" + 12, "Hello, somebody!" + 11); }
可能输出为:(空格 32,感叹号 33)
txt[Hello World!] 先于 [Hello!] [Hello World!] 后于 [Hello] [Hello World!] 先于 [Hello there] [body!] 等于 [body!]
字符查找
strchr()
定义:
cchar* strchr( const char* str, int ch );
用途:在
str
所指的空终止字节字符串中查找字符ch
。返回值:如果在
str
中找到了ch
,则返回指向找到的第一个字符的指针,否则返回空指针。示例:
c#include <stdio.h> #include <string.h> int main(void) { const char *str = "Try not. Do, or do not. There is no try."; char target = 'o'; const char *result = str; while ((result = strchr(result, target)) != NULL) { printf("找到 '%c' 起始于 '%s'\n", target, result); ++result; // result 自增,否则我们会找到相同位置的目标 } }
可能输出为:
txt找到 'o' 起始于 'ot. Do, or do not. There is no try.' 找到 'o' 起始于 'o, or do not. There is no try.' 找到 'o' 起始于 'or do not. There is no try.' 找到 'o' 起始于 'o not. There is no try.' 找到 'o' 起始于 'ot. There is no try.' 找到 'o' 起始于 'o try.'
字符查找
strrchr()
同上strchr()
,只不过查找字符最后一次出现的位置。子串查找
strstr()
定义:
cchar* strstr( const char* str, const char* sub );
用途:查找字符串
str
中首次出现子字符串sub
的位置。返回值:如果找到,则返回指向
str
中首次出现子字符串sub
的位置的指针;否则返回空指针。示例:
c#include <string.h> #include <stdio.h> void find_str(char const* str, char const* substr) { char const* pos = strstr(str, substr); if(pos == nullptr){ printf("没有在 [%s] 中找到 [%s]\n", str, substr); } else { printf("找到字符串 [%s] 位于 [%s] 的位置 %td\n", substr, str, pos - str); } } int main(void) { char const* str = "one two three"; find_str(str, "two"); find_str(str, ""); find_str(str, "nine"); find_str(str, "n"); return 0; }
可能输出为:
txt找到字符串 [two] 位于 [one two three] 的位置 4 找到字符串 [] 位于 [one two three] 的位置 0 没有在 [one two three] 中找到 [nine] 找到字符串 [n] 位于 [one two three] 的位置 1
3. 字符串操作
字符串复制
strcpy()
定义:
cchar* strcpy( char* restrict dest, const char* restrict src );
用途:把
src
所指的空终止字节字符串复制到dest
所指的字符数组。返回值:
dest
的副本。使用此函数的时候,出现以下情况为 UB:
dest
所指的字符数组空间不足;- 字符串和字符数组重叠(不满足
restrict
); dest
不是指向字符数组的指针 或src
不是指向空终止字节字符串的指针。
示例:
c#include <stdio.h> #include <string.h> int main(void) { const char *s1 = "mdr"; // char s2[strlen(s1)]; 数组空间不足 char s2[strlen(s1) + 1]; strcpy(s2, s1); printf("%s\n", s2); return 0; }
可能输出为
mdr
字符串复制
strncpy()
定义:
cchar* strncpy( char* restrict dest, const char* restrict src, size_t count );
用途:把
src
所指的字符数组中指定数量的字符复制到dest
所指的字符数组。如果src
所指的字符数组中不足count
个字符(即在复制字符的数量达到count
之前遇到了空终止字符),则以'\0'
补全。返回值:
dest
的副本。使用此函数的时候,出现以下情况为 UB:
- 两个字符数组重叠(不满足
restrict
); dest
或src
不是指向字符数组的指针;src
所指向的数组大小小于count
且它不含空字符(当然会继续越界访问);dest
所指的字符数组空间不足。
- 两个字符数组重叠(不满足
示例:
c#include <stdio.h> #include <string.h> int main(void) { const char *s1 = "mdr"; char s2[strlen(s1)]; strncpy(s2, s1, 3); // {'m', 'd', 'r'} // printf("%s\n", s2); // 无空终止字符 char s3[strlen(s1) + 1]; strncpy(s3, s1, 4); // {'m', 'd', 'r', '\0'} printf("%s\n", s3); // OK char s4[8]; // strncpy(s4, s2, 6); // UB: s2 空间为3,小于6 strncpy(s4, s3, 8); // {'m', 'd', 'r', '\0', '\0', '\0', '\0', '\0'} for (size_t n = 0; n < sizeof s2; ++n) { char c = s2[n]; c ? printf("'%c' ", c) : printf("'\\0' "); } putchar('\n'); for (size_t n = 0; n < sizeof s3; ++n) { char c = s3[n]; c ? printf("'%c' ", c) : printf("'\\0' "); } putchar('\n'); for (size_t n = 0; n < sizeof s4; ++n) { char c = s4[n]; c ? printf("'%c' ", c) : printf("'\\0' "); } return 0; }
可能输出为:
txtmdr 'm' 'd' 'r' 'm' 'd' 'r' '\0' 'm' 'd' 'r' '\0' '\0' '\0' '\0' '\0'