C语言常见字符函数和字符串函数

[复制链接]
发表于 2025-9-12 08:13:00 | 显示全部楼层 |阅读模式
字符/字符串函数

01.求字符串长度

1.1strlen()函数原型
  1. size_t strlen(const char *str);
复制代码
参数: str:要计算长度的字符串的首地址
功能 从给定内存地址开始扫描,直到遇到第一个'\0'竣事符为止,统计这之间的字符数目。
返回值: 返回一个 size_t 类型的值,表示字符串中的字符数。(不包括空字符’\0’)
1.2模拟实现my_strlen()
  1. //非递归求字符串长度
  2. int My_Strlen(char* str){
  3.     int count = 0;//临时变量
  4.     while (*str!='\0'){//传递的是字符串首地址,,解引用即可
  5.         count++;
  6.         str++;//找下一个字符
  7.     }return count;
  8. }
  9. //递归
  10. int My_Strlen(char* str){
  11.     if (*str!='\0'){
  12.         return 1 + My_Strlen(str + 1);//加一个字符串的长度
  13.     }return 0;
  14. }
  15. int main(){
  16.     char arr[] = "zbc";//['z','b','c','\0']包括'\0'
  17.     int len = My_Strlen(arr);//传递的是数组的首地址过去
  18.     return 0;
  19. }
复制代码
1.3 sizeof()简述


  • sizeof 操作符在编译时求值,不会引起运行时开销
  • sizeof 可以用于任何数据类型,包括用户自界说类型
  • sizeof 的返回值类型是 size_t(无符号整数类型)
  • sizeof 可以利用两种语法情势: sizeof(类型名) 或 sizeof 表达式
1.4  深入解析 strlen() 与 sizeof ()的区别

一般情况下数组名表示首地址的地址,但是有特别情况sizeof(数组名)和&数组名(取出整个数组的地址,是一个随机值)表示的是整个数组的大小。strlen()计算字符数组的字符数,以"\0"为竣事判定,不计算为’\0’的数组元素。 而sizeof计算数据(包括数组、变量、类型、布局体等)所占内存空间,用字节数表示。
示例代码
  1. char text[100] = "Programming";
  2. printf("strlen: %zu\n", strlen(text));  // 11
  3. printf("sizeof: %zu\n", sizeof(text));  // 100
  4. -----
  5. char *ptr = "Hello World";
  6. printf("strlen: %zu\n", strlen(ptr));  // 11
  7. printf("sizeof: %zu\n", sizeof(ptr));  // 4或8(指针大小)
复制代码
内存布局:
  1. 示例字符串"Hello"的内存表示:
  2. +-----+-----+-----+-----+-----+-----+
  3. | 'H' | 'e' | 'l' | 'l' | 'o' | '\0'|
  4. +-----+-----+-----+-----+-----+-----+
  5. 0x00  0x01  0x02  0x03  0x04  0x05
  6. strlen结果:5(0x00-0x04)
  7. sizeof结果:6(整个数组大小)
复制代码

02.长度不受限定的字符串函数
  1. char *strcpy(char *dest, const char *src);//将源字符串复制到目标串中,并在目标串末尾添加空字符'\0'。
复制代码
2.1  strcpy()字符串拷贝

参数:  dest: 目标字符串地址  src: 源字符串地址
功能 将 src 指向的字符串(包括空字符 \0)复制到 dest 指向的内存中。
返回值: 返回 dest 的地址
2.1.1  模拟实现my_strcpy()
  1. char* My_Srecpy(char* dest, const char* src){
  2.     char *ret = dest;
  3.     assert(dest != NULL);
  4.     assert(src != NULL);
  5.     while(*dest != *src){
  6.         dest++;
  7.         src++;
  8.     }
  9.     return ret;
  10. }
复制代码

  1. char* strcat(char* dest, const char* src);
复制代码
2.2  strcat ()字符串拼接

参数: dest: 目标字符串地址src: 源字符串地址
功能 将 src 指向的字符串追加到 dest 的末尾(覆盖 dest 的 \0)。
返回值: 返回 dest的地址
注意: 两常量字符串能拼接说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。在str为NULL的情况下调用strcpy和strcat,试图往空指针指向的内存空间写入数据,这会导致步伐崩溃。
2.2.1  模拟实现My_Strcat()
  1. char* My_Strcat(char* dest, const char* src){
  2.     char *ret = dest;
  3.     assert(dest != NULL);
  4.     assert(src != NULL);
  5.     while(*dest !=NULL){
  6.         dest++;
  7.     }
  8.     while((*dest++ = *src++)){
  9.       ;
  10.     }
  11.     return ret;
  12. }
复制代码

  1. int strcmp(const char* str1, const char* str2);
复制代码
2.3  strcmp()字符串比力

参数:  str1: 字符串1地址;str2: 字符串2地址
功能: 比力 str1 和 str2 的字典次序(按ASCII值逐字符比力)。
返回值: 返回整数:(str1 < str2),返回负值,(str1 == str2),返回0,若 (str1 > str2),返回正值
2.3.1 模拟实现My_Strcmp()
  1. int strcmp(const char* str1, const char* str2){//比较的是ascii码值,需要转换,逐字符比较
  2.     int ret = 0;
  3.     assert(dest != NULL);
  4.     assert(src != NULL);
  5.     while(*str1 != '\0' && *str2 != '\0' && *str1 == *str2){
  6.         srt1++;
  7.         str2++;
  8.         }
  9.     return (*str1 - *str2)
  10. }
复制代码

03.长度受限定的字符串介绍
  1. char *strncpy(char *dest, const char *src, size_t n);
复制代码
3.1  strncpy ()字符串n拷贝

参数:
dest:目标字符串的地址,它需要有足够空间容纳源字符串n字符和空字符’\0’
src: 源字符串的地址,以’\0’竣事。
n: 需要复制的字节数
功能: strncpy 将 src 的前 n 个字符复制到 dest:若 src 长度不足 n,剩余部门用 \0 填充;若 src 长度 ≥ n,则只复制前 n 个字符且不主动补 \0,需手动添加以确保字符串合法。
返回值:  返回指向目标字符串的dest 指针。
注意:

  • dest 必须足够大(至少 n 字节),否则可能溢出。
  • 不会主动补 \0(当 n ≤ strlen(src) 时),需手动处理:
  • 性能较低(如果 n 远大于 strlen(src),会填充大量 \0)。
  • 不适合直接用于字符串操作(除非手动处理 \0)。
代码示例:
  1. int main() {
  2.     char dest[10];
  3.     const char *src1 = "Hello";
  4.     const char *src2 = "World12345";
  5.     // 当 src < n(自动补 \0)
  6.     strncpy(dest, src1, 10);
  7.     printf("Case 1: %s\n", dest);  // 输出 "Hello"(后面填充 \0)
  8.     // 当 src ≥ n(不补 \0)
  9.     strncpy(dest, src2, 5);
  10.     dest[5] = '\0';  // 手动补余 \0
  11.     printf("Case 2: %s\n", dest);  // 输出 "World"
  12.     return 0;
  13. }
复制代码

  1. char *strncat(char *dest, const char *src, size_t n);
复制代码
3.2  strncat ()字符串n拼接

参数:
dest:目标字符串的地址,它需要有足够空间容纳拼接后的字符串和空字符’\0’
src:源字符串的指针的首地址
n:最多追加的字符数(不包括主动添加的 \0)
功能: 将 src 的前 n 个字符(或遇到 \0 时停止)追加到 dest 的末尾,并主动在最终结果后补 \0。能够防止dest溢出,安全拼接字符串(比 strcat 更安全)。
**返回值:**返回指向目标字符串的dest 指针。
注意:

  • dest 必须有足够的剩余空间(至少 strlen(dest) + n + 1)。
  • dest 必须以\0开头(否则行为未界说)。
  • n 仅限定 src 的字符数,strncat 始终会补 \0(即使 n 个字符后没有 \0)。
  • 不会检查 dest 缓冲区是否足够大,需步伐员自行确保。
代码示例:
  1. int main(){
  2.         char dest[20] = "Hello";
  3.     const char *src = ", World!";
  4.     strncat(dest, src, 5);  // 只追加 ", Wor"(5 个字符)
  5.     printf("%s\n", dest);   // 输出 "Hello, Wor"(自动补 \0)
  6.     return 0;
  7. }
复制代码

  1. int strncmp(const char *s1, const char *s2, size_t n);
复制代码
3.3  strncmp ()字符串n比力

参数:
s1:要比力的第一个字符串
s2:要比力的第二个字符串
n:最多比力的字符数(比力前 n 个字符)
功能: 逐字符比力 str1 和 str2 的前 n 个字符(或直到遇到 \0)。
返回值:

  • 前n个字符相同 → 返回0
  • 比力中s1字符 < s2字符 → 返回负值
  • 比力中s1字符 > s2字符 → 返回正值
注意:

  • 不会主动检查字符串长度,n 不可超过缓冲区大小。
  • 遇到 \0 会提前终止比力(即使 n 未用完)。
  • 不适用于非字符串数据(如二进制数据,应利用 memcmp)。
代码示例:
  1. int main() {
  2.     const char *s1 = "Hello";
  3.     const char *s2 = "Hellx";
  4.     const char *s3 = "Ha";
  5.     printf("strncmp(s1, s2, 4): %d\n", strncmp(s1, s2, 4));  // 0  
  6.     printf("strncmp(s1, s2, 5): %d\n", strncmp(s1, s2, 5));  //-11 <0('o' < 'x')
  7.     printf("strncmp(s1, s3, 2): %d\n", strncmp(s1, s3, 2));  // 4 >0('e' > 'a')
  8.     return 0;
  9. }
复制代码

04.字符串查找
  1. char *strstr(const char *main_str, const char *sub_str);
复制代码
4.1 strstr()字符串匹配

参数:
功能: 在主串中查找子串首次出现的位置,返回指向该位置的指针;若未找到,返回NULL。  具体实现可接纳暴力算法(逐字符匹配)和kmp算法(优化查找)
返回值:

  • 找到子串时:返回子串在haystack中的起始地址,后续字符可通过指针访问。
  • 未找到子串时:返回NULL。
  1. char str = "abcdefg";  
  2. char *result = strstr(str, "cde");  
  3. printf("%s\n", result); // 输出:cdefg  
复制代码

  1. char *strtok(char *str, const char *sep);
复制代码
4.2 strtok()字符串切割

参数:  str是原字符串,sep是分隔符字符串(集合)
功能: 字符串切割,按照 sep字符串(可称为集合)指向的字符串中的字符,切割 指向的字符串。其实就是在 str 指向的字符串中发现了 sep字符串中的字符,就将其变成\0调用一次strtok 只切割一次,切割一次之后,再去切割的时间strtok 的第一个参数传NULL,意思是接着上次切割的位置继续切下去。
注意: 如果 str字符串中出现了连续的几个 sep,中的字符,则只将第一个字符变成”\0
返回值: 返回的是切出来的字符串的首地址
  1. charstr[100]="lucy:yuxin,hanbing,xiaoyang:xueyang,zhanghu:yongheng";
  2.     char *p[8];
  3.         int i=0,j;
  4.         printf("str:号s\n",str);
  5.         p[i]= strtok(str,",:;");//首次切割返回的是lucy\0,把:替换成了'\0'
  6. while (p[i]!-NULL){
  7.      i++:
  8.          p[i]=strtok(NULL,".:;");//第二次切割(比较特殊)开始第一个参数传NULL告诉它我从上一个被置为'\0'的位置开始切割
  9. }
  10. for (j=0 ;j<i;j++)
  11.         printf("p[各d]:号s\n",j,p[j]);
复制代码

05.错误信息报告
  1. char *strerror(int errnum);
复制代码
5.1 strerror()

参数: errnum错误码
这个错误码一般传递的是 errno 这个变量的值,在C语言有一个全局的变量叫: errno ,当库函数的调用发生错误的时间,就会把本次错误的错误码存放在 errno 这个变量中,利用这个全局变量需要包含一个头文件errno.h 。

功能:

  • C 尺度库中用于将错误码转换为可读错误信息的函数。strerror 函数可以通过参数部门的 errnum 表示错误码,得到对应的错误信息,而且返回这个错误信息字符串首字符的地址。
  • strerror 函数只针对尺度库中的函数发生错误后设置的错误码的转换。
返回值: 函数返回通过错误码得到的错误信息字符串的首字符的地址,

06.字符操作


07.内存操作函数
  1. void *memcpy(void *dest, const void *src, size_t count);
复制代码
7.1 memcpy()内存拷贝

参数:  dest目标地址,src源地址,count拷贝字节数
功能: 将src指向的内存块逐字节复制count个字节到dest
注意:

  • 禁止内存重叠:dest和src所指空间重叠会导致未界说行为。
  • 目标空间足够大
模拟实现:
  1. void* my_memcpy(void* dest, const void* src, size_t count) {  
  2.     assert(dest && src);  
  3.    while(count--){
  4.        *(char *)dest=*(char *)src;
  5.        dest=*(char *)dest+1;
  6.        src=*(char *)src+1;
  7.    }
  8.     return dest;  
  9. }  
复制代码
利用场景:
  1. int src[5] = {1, 2, 3, 4, 5};
  2. int dest[5];
  3. memcpy(dest, src, sizeof(src));  //拷贝20字节
复制代码

  1. void *memmove(void *dest, const void *src, size_t count);  
复制代码
7.2 memmove() 安全拷贝

参数:   dest目标地址,src源地址,count拷贝字节数
功能: 与memcpy类似,但允许源和目标内存块重叠,通过判定 src 和 dest 的位置关系,决定拷贝方向(从前向后或从后向前)
模拟实现:
  1. void* my_memmove(void* dest, const void* src, size_t n) {
  2.     if (dest == NULL || src == NULL) return NULL;
  3.     char* d = (char*)dest;
  4.     const char* s = (const char*)src;
  5.     if (d < s) {  // 目的串小于原串,从前向后拷贝
  6.         for (size_t i = 0; i < n; i++) {
  7.             d[i] = s[i];
  8.         }
  9.     } else {
  10.         for (size_t i = n; i > 0; i--) {
  11.             d[i-1] = s[i-1];
  12.         }
  13.     }
  14.     return dest;
  15. }
复制代码
利用场景:
  1. char str[20] = "hello, world!";
  2. memmove(str + 7, str + 12, 5);  // 将 ", world!" 的 "world!" 前移
  3. // 结果:str 变为 "hello, !"
复制代码


  1. void *memset(void *dest, int value, size_t count);  
复制代码
7.3 memset() 内存填充

参数:   dest目标地址,value填充值,count拷贝字节数
功能: 将 src 指向的内存块的前 n 个字节设置为 value 的值
模拟实现:
  1. void* my_memset(void* dest, int value, size_t count) {  
  2.    
  3.     return ptr;  
  4. }
复制代码
利用场景:
  1. //数组元素置位0
  2. int arr[10];
  3. memset(arr, 0, sizeof(arr));
复制代码

  1. int memcmp(const void *ptr1, const void *ptr2, size_t count);  
复制代码
7.4  memcmp()内存比力

参数:  ptr1内存快1,ptr2内存快2,count拷贝字节数
功能: 比力(逐字节比力,遇到\0不终止)两个内存块的前count个字节
返回值: 相等返回0,否则返回顾个不匹配字节的差值
模拟实现:
  1. int my_memcmp(const void* ptr1, const void* ptr2, size_t count) {  
  2.     const char* p1 = (const char*)ptr1;  
  3.     const char* p2 = (const char*)ptr2;  
  4.     for (size_t i = 0; i < count; i++) {  
  5.         if (p1i != p2i) {  
  6.             return p1i - p2i;  
  7.         }  
  8.     }  
  9.     return 0;  
  10. }  
复制代码
利用场景:
  1. // 比较两个字符串
  2. unsigned char buf1[] = "dsahihdaoDD";
  3. unsigned char buf2[] = "dsahihdaoDd";
  4. int result = memcmp(buf1, buf2, sizeof(buf1)); //返回负数
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表