• 【C语言】字符函数和字符串函数


    目录

    一、函数介绍及其模拟实现

    1.strlen

    2.strcpy

    3.strcat

    4.strcmp 

    5.strncpy

    6.strncat

     7.strncmp

    8.strstr

     9.strtok

    10.strerror 

     11.其他字符串函数

    二、内存函数 

    1.memcpy

     2.memove

    3.memcmp


    前言

    在平时我们处理一些数据时,尤其是字符串,我们经常会用到库函数中的strlen、strcmp等,C语言本身是没有字符串类型的,字符串通常放在常量字符串和字符数组中。

    一、函数介绍及其模拟实现

    1.strlen

    (1)函数头部

    size_t strlen( const char *string );

    (2)注意事项

    • 字符串以 '\0'作为结束标志,strlen函数返回的是在字符串'\0'前面出现的字符的个数(不含\0)
    • 参数指向的字符串必须要以\0结束
    • 函数的返回值是类型是 size_t 这是无符号整型(易错)

    +

    (3)strlen的使用 

    1. #include
    2. #include
    3. int main()
    4. {
    5. char* str = "abcef";
    6. int len = strlen(str);//获取字符串的长度
    7. printf("%d",len);
    8. return 0;
    9. }

    (4)strlen的模拟实现

    1. //普通实现
    2. #include
    3. int my_strlen(char *str)
    4. {
    5. int count = 0;
    6. while (*str++)
    7. count++;
    8. return count;
    9. }
    10. int main()
    11. {
    12. char* str = "abcdef";
    13. int len = my_strlen(str);
    14. printf("%d",len);
    15. return 0;
    16. }

    //链式访问实现

    1. #include
    2. int my_strlen(char *str)
    3. {
    4. int count = 0;
    5. while (*str++)
    6. count++;
    7. return count;
    8. }
    9. int main()
    10. {
    11. char* str = "abcdef";
    12. printf("%d",my_strlen(str));//链式访问
    13. return 0;
    14. }

    //函数递归实现

    1. #include
    2. int my_strlen(char* str)
    3. {
    4. if (*str == '\0')
    5. return 0;
    6. else
    7. return (1 + my_strlen(str + 1));
    8. }
    9. int main()
    10. {
    11. char* str = "abcdef";
    12. int len = my_strlen(str);
    13. printf("%d",len);
    14. return 0;
    15. }

    //指针-指针实现

    1. //指针- 指针
    2. #include
    3. int my_strlen(char*str)
    4. {
    5. char* end = str;
    6. while (*end)
    7. end++;
    8. return end - str;
    9. }
    10. int main()
    11. {
    12. char* str = "abcdef";
    13. int len = my_strlen(str);
    14. printf("%d",len);
    15. return 0;
    16. }

    2.strcpy

    (1)函数头部

    char *strcpy( char *strDestination, const char *strSource ); 

    (2)注意事项

    • 源字符串以'\0'结束。
    • 会将源字符串的’\0‘拷贝的目标空间
    • 目标空间必须足够大,以保证能放下源字符串
    • 目标空间必须可变 

     (3)strcpy的使用

    1. #include
    2. #include
    3. int main()
    4. {
    5. char str1[20] = {0};
    6. char* str2 = "abcdef";
    7. strcpy(str1,str2);
    8. printf("%s",str1);
    9. return 0;
    10. }
    •  (4)strcpy的模拟
    1. #include
    2. #include
    3. char* my_strcpy(char* str1, const char* str2)
    4. {
    5. assert(str1&&str2);//断言避免指针为空
    6. char* ret = str1;
    7. while (*str1++ = *str2++)
    8. ;
    9. return ret;
    10. }
    11. int main()
    12. {
    13. char str1[20] = { 0 };
    14. char* str2 = "abcdef";
    15. printf("%s", my_strcpy(str1, str2));
    16. return 0;
    17. }

    3.strcat

    (1)函数头部

    char *strcat( char *strDestination, const char *strSource ); 

     (2)注意事项

    • 源字符必须以‘\0’结束
    • 目标空间必须有足够大能容纳下源字符串
    • 目标空间必须可以修改
    • strcat不能自己给自己追加

    (3)strcat的使用

    1. //strcat的使用
    2. #include
    3. #include
    4. int main()
    5. {
    6. char str1[20] = "abcdef";
    7. char* str2 = "112233";
    8. strcat(str1,str2);
    9. printf("%s",str1);
    10. return 0;
    11. }


    (4)strcat的模拟实现

    1. #include
    2. #include
    3. char* my_strcat(char*dest,const char*src)
    4. {
    5. char* ret = dest;
    6. while (*dest)
    7. dest++;
    8. while (*dest++ = *src++)
    9. ;
    10. return ret;
    11. }
    12. int main()
    13. {
    14. char str1[20] = "abcdef";
    15. char* str2 = "112233";
    16. my_strcat(str1, str2);
    17. printf("%s", str1);
    18. return 0;
    19. }

    4.strcmp 

    (1)函数头部

    int strcmp( const char *string1, const char *string2 );

    (2)注意事项

    • 根据标准规定
    • 第一个字符串 大于 第二个字符串,返回大于0的数字
    • 第一个字符串 等于 第二个字符串 ,返回0
    • 第一个字符串 小于 第二个字符串,返回小于0的数字 

    (3)strcmp的使用 

    1. #include
    2. #include
    3. int main()
    4. {
    5. char* str1 = "abcdef";
    6. char* str2 = "aaaaaa";
    7. int ret = strcmp(str1,str2);//可以知道 str1>str2
    8. printf("%d",ret);//编译器返回一个大于0的数字
    9. return 0;
    10. }

    (4)strcmp的模拟实现

    1. #include
    2. #include
    3. int my_strcmp(const char*str1,const char*str2)
    4. {
    5. assert(str1&&str2);
    6. while (*str1 == *str2)
    7. {
    8. if (*str1 == '\0')
    9. return 0;
    10. str1++;
    11. str2++;
    12. }
    13. return (*str1 - *str2);
    14. }
    15. int main()
    16. {
    17. char* str1 = "abcdef";
    18. char* str2 = "aaaaaa";
    19. int ret = my_strcmp(str1, str2);
    20. printf("%d", ret);
    21. return 0;
    22. }

    我们发现上述字符串函数 的字符串长度不受到限制

    接下来介绍几个长度受到限制的字符串函数


    5.strncpy

    (1)函数头部

    char *strncpy( char *strDest, const char *strSource, size_t count );

    (2)注意事项

    •  拷贝count个字符从源字符串到目标空间
    • 如果源字符小于count,则考完源字符串后,在目标的后面追加0,直到count个

    (3)strncpy的使用

    1. #include
    2. #include
    3. int main()
    4. {
    5. char str1[20] = "aa";
    6. char str2[] = "bbb";
    7. strncpy(str1,str2,5);
    8. printf("%s",str1);
    9. return 0;
    10. }

    接下来我们一下调试的内容

    6.strncat

    (1)函数头部

    char *strncat( char *strDest, const char *strSource, size_t count );

    (2)注意事项

    • 当源字符串小于count,并不会一直追加,而是追加完字符串的时候再加上‘\0’,目标是完成源字符串内容
    • 当等于count,会再追加一个上‘\0’
    • 没有额外追加

    (3)strncat的使用

    1. //strncat的使用
    2. #include
    3. #include
    4. int main()
    5. {
    6. char str1[20] = "aaa";
    7. char* str2 = "bbc";
    8. strncat(str1,str2,3);
    9. printf("%s",str1);
    10. return 0;
    11. }

     7.strncmp

    (1)函数头部

    int strncmp( const char *string1, const char *string2, size_t count );

    (2)注意事项

    • 比较到出现另一个字符不一样,或者一个字符串结束,或者count个字符全部比较完

    < 0   不匹配的第一个字符在 str1 中的值低于 str2 中的值

    0   两个字符串的内容相等 

    >0  第一个不匹配的字符在str1中的值比在str2中的值大

    (3) strncmp的使用

    1. //strncmp的使用
    2. #include
    3. #include
    4. int main()
    5. {
    6. char* str1 = "aaab";
    7. char* str2 = "abba";
    8. int len = strncmp(str1,str2,2);//比较前两个字符
    9. printf("%d",len);
    10. return 0;
    11. }


    8.strstr

    (1)函数头部

    char *strstr( const char *str1, const char *str2 );

    (2)注意事项

    在str1中找  str2在(str1)第一次出现的位置

    (3)strstr的使用
     

    1. #include
    2. #include
    3. int main()
    4. {
    5. char* str1 = "abcxaxad";
    6. char* str2 = "xax";
    7. char* ret = strstr(str1,str2);
    8. printf("%s",ret);
    9. return 0;
    10. }

    (4)strstr模拟实现

    1. //strstr的模拟实现
    2. #include
    3. #include
    4. char* my_strstr(const char* str1,const char* str2)
    5. {
    6. assert(str1&&str2);
    7. char* cp = str1;
    8. char* p1 = str1;
    9. char* p2 = str2;
    10. while (cp)
    11. {
    12. p1 = cp;//从cp指向的字符开始
    13. p2 = str2;//从子串的首字符开始
    14. while (*p1 == *p2 && *p1 && *p2)
    15. {
    16. p1++;
    17. p2++;
    18. }
    19. if (*p2 == '\0')
    20. return cp;
    21. cp++;
    22. }
    23. return NULL;
    24. }
    25. int main()
    26. {
    27. char* str1 = "abcxaxad";
    28. char* str2 = "xax";
    29. char* ret = my_strstr(str1,str2);
    30. printf("%s",ret);
    31. return 0;
    32. }

    图解:

    起始情况

    找到的时候

     

     9.strtok

    (1)函数头部

    char *strtok( char *str, const char *sep );

    (2)注意事项

    •  sep 参数是个字符串,定义了用作分隔符的字符集合
    • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割标记。
    • strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
    • strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置
    • strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记
    • 如果字符串中不存在更多的标记,则返回 NULL 指针

    (3)strtok的使用 ( 把字符串根据 分隔符  分隔开来)

    1. #include
    2. #include
    3. int main()
    4. {
    5. char* p = "aabbcc@112233.abc";
    6. const char* sep = "@.";
    7. char arr[30];
    8. char* str = NULL;
    9. strcpy(arr,p);//临时拷贝字符串
    10. for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
    11. printf("%s\n",str);
    12. return 0;
    13. }

    10.strerror 

    返回错误码,所对应的错误信息(这里是程序运行时的错误)

    在介绍其他知识:库函数在执行时,发生了错误,会将一个错误码存到errno这个变量中(全局变量)

    (1)函数头部

    char * strerror( int errnum );

    (2)strerror的使用

    1. #include
    2. #include
    3. #include
    4. int main()
    5. {
    6. int i = 0;
    7. for (i = 0; i < 10;i++)
    8. {
    9. printf("%d is %s\n",i,strerror(i));//打印错误码 0到9的错误信息
    10. }
    11. }


     11.其他字符串函数

    字符分类函数
    iscntr任何控制字符
    isspace

    空白字符: 空格 ' ',换页 ‘\f,换行 '\n',回车 '\r' ,制表符 ‘\t’,垂直制表符 ‘\v’

    isdigit十进制数字 0 - 9
    isxdigit十六进制数字 0 - 9 ,a - f
    islower小写字母 a- z
    isupper大写字母 A - Z
    isalpha字母 a - z , A - Z
    isalnum字母或者数字 a - z , A - Z,0 - 9
    ispunct标点符号,任何不属于字母和数字的图形字符
    isgragh任何图形字符
    isprint可以打印任何字符

    根据上述字符函数,【例如】islower(a) 如果圆括里面的是小写字母,该函数就返回真。

    二、内存函数 

    1.memcpy

    (1)函数头部 

    void *memcpy( void *dest, const void *src, size_t count );

    (2)注意事项

    • 函数memcpy从source的位置开始向后复制count个字节的数据到destination的内存位置
    • 这个函数在遇到 '\0' 的时候并不会停下来
    • 用来处理不重叠的内存拷贝,如果source和destination有任何的重叠,复制的结果都是未定义的
    • size_t  count 是 字节的个数

    (3)memcpy的使用

    1. #include
    2. #include
    3. int main()
    4. {
    5. int arr1[] = {1,2,3,4,5};
    6. int arr2[20] = {0};
    7. //将arr1中的内容拷贝到arr2中
    8. memcpy(arr2,arr1,20);
    9. int i = 0;
    10. for (i = 0; i < 20;i++)
    11. {
    12. printf("%d ",arr2[i]);
    13. }
    14. return 0;
    15. }

     (4)memcpy的模拟使用

    1. //memcpy的模拟实现
    2. #include
    3. #include
    4. void* my_memcpy(void* dest, const void *src ,size_t count)
    5. {
    6. assert(dest && src);
    7. void* ret = dest;
    8. while (count--)//count表示的是字节的个数
    9. {
    10. //因为char类型是占一个字节
    11. *(char*)dest = *(char*)src;
    12. dest = (char*)dest + 1;
    13. src = (char*)src + 1;
    14. }
    15. return dest;
    16. }
    17. int main()
    18. {
    19. int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    20. int arr2[20] = {0};
    21. my_memcpy(arr2,arr1,40);
    22. int i = 0;
    23. for (i = 0; i < 20;i++)
    24. {
    25. printf("%d ",arr2[i]);
    26. }
    27. return 0;
    28. }

     2.memove

    (1)函数头部

    void *memmove( void *dest, const void *src, size_t count );

    (2)注意事项

    • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的
    • 如果源空间和目标空间出现重叠,就是可以使用memmove进行处理​​​​​​
    • 用重叠的内存拷贝

    (3)memmove的使用

    1. #include
    2. #include
    3. int main()
    4. {
    5. //这里我们给str自己拷贝一个123
    6. char str[] = "web online 123";
    7. memmove(str, str + 11,3);//可以用于重叠内存拷贝
    8. printf("%s",str);
    9. return 0;
    10. }

     

      (4)memmove的模拟实现

    1. //memmove的模拟实现
    2. #include
    3. #include
    4. void* my_memmove(void* dest,const void* src,size_t num)
    5. {
    6. assert(dest&&src);
    7. void* ret = dest;
    8. //当地址src 小于 dest的时候
    9. if (dest < src)
    10. {
    11. //这里我们src从前到后移动
    12. //前->后
    13. while (num--)
    14. {
    15. *(char*)dest = *(char*)src;
    16. dest = (char*)dest + 1;
    17. src = (char*)src + 1;
    18. }
    19. }
    20. else
    21. {
    22. while (num--)
    23. {
    24. *((char*)dest + num) = *((char*)src + num);
    25. }
    26. }
    27. return ret;
    28. }
    29. int main()
    30. {
    31. int arr1[] = {1,2,3,4,5,6,7,8,9,10};
    32. my_memmove(arr1, arr1 + 2,12);//前->后
    33. //my_memmove(arr1+5,arr1+2,12);//后->前
    34. int i = 0;
    35. for (i = 0; i < 10;i++)
    36. {
    37. printf("%d ",arr1[i]);
    38. }
    39. return 0;
    40. }

    前->后 

    后->前

     

    情况1

    情况2

    3.memcmp

    (1)函数头部

    int memcmp( const void *buf1, const void *buf2, size_t count );

    (2)注意事项

    • 比较从buf1 和 buf2 指针开始的num个字节
    • The memcmp function compares the first count bytes of buf1 and buf2 and returns a value indicating their relationship.

    • 注意该函数的return value 

    (3)memcmp的使用

    1. //memcmp的使用
    2. #include
    3. #include
    4. int main()
    5. {
    6. char buf1[] = "aabbcc2210";
    7. char buf2[] = "aabbcc2211";
    8. int n = 0;
    9. n = memcmp(buf1,buf2,sizeof(buf1));
    10. if (n > 0)
    11. printf("buf1大于buf2");
    12. else if (n < 0)
    13. printf("buf1小于buf2");
    14. else
    15. printf("buf1等于buf2");
    16. return 0;
    17. }

  • 相关阅读:
    带你了解数据分布式存储原理
    从“草原牛”到“数字牛”:蒙牛的数字化转型之道
    【EXCEL自动化05】python批量合并excel(xlsx)文件
    PyTorch 2.0发布了,一行代码提速76%
    欧拉计划Python解法(第11题-第15题)
    EFK代替ELK方案7.17.3
    css实现一个炫酷动画loading(四)
    【hive基础】hive常见操作速查
    MySQL教程
    linux内核中list的实现
  • 原文地址:https://blog.csdn.net/qq_72505850/article/details/132661899