• 字符串和内存函数


    目录

    strlen

    模拟实现

    长度不受限字符串函数 

    strcpy

    模拟实现

    ​编辑 strcat

    模拟实现

     strcmp

     模拟实现

    长度受限字符串函数

    strncpy

    模拟实现

    strncat

    strncmp

    strstr 

    模拟实现

     strtok

    strerror

    perror

    字符分类函数

    字符转换

    示例:

    ​编辑内存函数

    memcpy

    模拟实现 

    memmove

     模拟实现

    memcmp

     memset


    strlen

    功能:统计字符串中\0之前的字符个数。

    注意:如果没有\0则返回一个随机值

    易错: 

     

    strlen的返回值为size_t,也就是无符号整形,使用时要注意这点。 

    模拟实现

    1. #include
    2. size_t my_strlen(const char* str)
    3. {
    4. assert(str);
    5. const char* start = str;
    6. const char* end = str;
    7. while (*end != '\0')
    8. {
    9. end++;
    10. }
    11. return end - start;
    12. }

    长度不受限字符串函数 

    strcpy

    功能:将一个源头字符串拷贝到一个目标字符串中

    注意:如果源头字符串没有\0则会报错。目标空间要足够大,且可变

     易错:

    1. char* p = "hello";//常量字符串
    2. char arr[] = "world";
    3. strcpy(p, arr);

    模拟实现

    1. char* my_strcpy(char* dest, const char* src)
    2. {
    3. assert(dest);
    4. assert(src);
    5. char* str = dest;
    6. while (*dest++ = *src++)\\取巧写法,注意后置++不会对程序产生影响
    7. {
    8. ;
    9. }
    10. return str;//能够被接收
    11. }

    测试结果: 

     strcat

    功能:在一个字符串后面追加另一个字符串。

    注意:目标空间要足够大,且可变。都需要包含\0

    易错:

     追加位置在\0处:

    模拟实现

    1. char* my_strcat(char* dest, const char* src)
    2. {
    3. assert(dest);
    4. assert(src);
    5. char* str = dest;
    6. while (*dest)//\0处追加,循环体内++
    7. {
    8. dest++;
    9. }
    10. while (*dest++ = *src++)
    11. {
    12. ;
    13. }
    14. return str;
    15. }

    注意不要利用strcat去追加自身,否则会造成死循环!

     strcmp

    功能:比较字符串对应位置的ascii码大小

    注意:都要包含\0。

     模拟实现

    1. //写法1
    2. int my_strcmp(const char* s1, const char* s2)
    3. {
    4. assert(s1 && s2);
    5. while (*s1 == *s2)
    6. {
    7. if (*s1 == '\0')//全等
    8. {
    9. return 0;
    10. }
    11. s1++;
    12. s2++;
    13. }
    14. if (*s1 > *s2)
    15. return 1;
    16. else
    17. return -1;
    18. }
    1. //写法2
    2. int my_strcmp(const char* s1, const char* s2)
    3. {
    4. assert(s1 && s2);
    5. while (*s1 == *s2)
    6. {
    7. if (*s1 == '\0')
    8. {
    9. return 0;
    10. }
    11. s1++;
    12. s2++;
    13. }
    14. return *s1 - *s2;
    15. }

    长度受限字符串函数

    strncpy

    模拟实现

    模拟实现一次,后续不再模拟实现。

    具体逻辑是用一个无符号整数加入循环条件,如果需要拷贝的源头字符串超过了自身长度可以考虑给多余的地方拷贝\0。 

    1. char* my_strncpy(char* dest, const char* src,size_t size)
    2. {
    3. assert(dest);
    4. assert(src);
    5. char* str = dest;
    6. while (size && (*dest++ = *src++))//=优先级最低,所以加()
    7. {
    8. size--;
    9. }
    10. if(size) //超出源头字符串长度
    11. while (--size)
    12. {
    13. *dest++ = '\0';
    14. size--;
    15. }
    16. return str;
    17. }

    strncat

    将n个子串拷贝到目标字符串后,自动补\0,可以自己增添自己。

    strncmp

    比较n个子串的大小,大于返回正数,小于返回负数,等于返回0。

     

    strstr 

    查找一个字符串里的子串,返回首次匹配所有子串的目标字符串中相应字符串的首地址。

    模拟实现

    法一:我的逻辑是能不能用strncmp负责比较字符串,用一个指针去遍历目标数组,注意结束条件为\0。但这样做有个漏洞,一次性比较多个字符串势必有越界的情况,我们以\0为突破口,能不能用它们的地址进行比较?于是思路就出现了。

    1. char* my_strstr(const char* str1, const char* str2)
    2. {
    3. assert(str1);
    4. assert(str2);
    5. const char* ptr = str1;
    6. int len1 = strlen(str1);
    7. int len2 = strlen(str2);
    8. while (strncmp(str1, str2, len2)!=0 && str1)
    9. {
    10. if (str1 + len2 > ptr + len1)
    11. {
    12. return NULL;
    13. }
    14. str1++;
    15. }
    16. return (char*)str1;
    17. }

    法二:四指针遍历法。两指针负责移动,两指针负责记录。

    1. char* my_strstr(const char* str1, const char* str2)
    2. {
    3. assert(str1);
    4. assert(str2);
    5. const char* p = str1;
    6. const char* src = str2;
    7. while (*p)
    8. {
    9. str1 = p;
    10. str2 = src;
    11. while (*str1 != '\0' && *str2 != '\0' && * str1 == *str2)//注意\0
    12. {
    13. str1++;
    14. str2++;
    15. }
    16. if (*str2 == '\0')
    17. {
    18. return (char*)p;
    19. }
    20. p++;
    21. }
    22. return NULL;
    23. }

     strtok

    功能:分隔字符串,strtok函数找到str的下一个标记,并将其用\0替换,返回一个指向这个标记的指针。

    注意:strtok会改变原数据的内容!一般修改临时拷贝的内容。

     

    使用方法:

    • 第一个参数传字符串,第二个参数传字符串里分隔符
    • 第一个参数首次传递不为空,通过strtok函数找到指定分隔符位置后,将其替换成\0并记录下它的地址再返回回去,后面第一个参数一律为NULL(否则重置),从被保存的位置开始查找下一个分隔符所在位置。
    • 如果本次找不到分隔符,就返回NULL。

     测试:

     发现确实实现了分割并返回,但并不完全,我们可以写个循环:

    strerror

    功能:当函数调用失败时,将错误码(errno)转换成对应的错误信息或指向对应的地址。

    perror

    等价于printf + strerror函数,如需打印可以使用这个函数。

    字符分类函数

    1. int isalnum(int c):检查字符是否为数字或字母;(0~9,a~z,A~Z)
    2. int isalpha(int c):检查字符是否为字母;(a~z, A~Z)
    3. int iscntrl(int c):检查字符是否为控制字符;(八进制000~037以及177的字符)
    4. int isdigit(int c):检查字符是否为十进制数字;(0~9)
    5. int isgraph(int c):检查字符是否为图形表示,依赖于使用语言的环境;0~9,a~z,A~Z,以及标点符号)
    6. int islower(int c):检查字符是否为小写的字母;(a~z)
    7. int isprint(int c):检查字符是否为可打印的;(数字、字母、标点符号、空白字符)
    8. int ispunct(int c):检查字符是否为标点符号;(! ” # $ % & ’ ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~等)
    9. int isspace(int c):检查字符是否为空白字符;(TAB、换行、垂直TAB、换页、回车、空格)
    10. int isupper(int c):检查字符是否为大写字母;(A~Z)
    11. int isxdigit(int c):检查字符是否为十六进制数字;(0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f)

    字符转换

    1. int tolower(int c):转化字符为小写字母;
    2. int toupper(int c):转化字符为大写字母;

    示例:


    内存函数

    memcpy

    功能: 将一个内存空间的数据按字节复制到另一块空间。

    模拟实现 

    1. void* my_memcpy(void* dest, void* src, size_t num)
    2. {
    3. void* ret = dest;
    4. assert(dest);
    5. assert(src);
    6. while(num--)
    7. {
    8. *(char*)dest = *(char*)src;
    9. dest = (char*)dest + 1;
    10. src = (char*)src + 1;
    11. }
    12. return ret;
    13. }

    memmove

    使用memcpy拷贝空间出现重叠时分两种情况:

    memcpy显然只能从一方进行拷贝,如果出现另一种情况,则会存在内存覆盖现象。而memmove的作用就是对重叠空间进行拷贝。(有些编译器memcpy可以实现重叠拷贝)

    字符串重叠空间拷贝用memmove代替strncpy。

     模拟实现

    1. void* my_memmove(void* dest, void* src, size_t num)
    2. {
    3. assert(dest);
    4. assert(src);
    5. //(char*)dest++;不能这样写,强制暂时改变了类型,void*无法自增
    6. void* ret = dest;
    7. //从前往后
    8. if (src > dest)
    9. {
    10. while (num--)
    11. {
    12. *(char*)dest = *(char*)src;
    13. dest = (char*)dest + 1;
    14. src = (char*)src + 1;
    15. }
    16. }
    17. //从后往前
    18. else
    19. {
    20. while (num--)
    21. {
    22. *((char*)dest+num) = *((char*)src+num);
    23. }
    24. }
    25. return ret;
    26. }

     测试:

    memcmp

    内存比较函数,不多赘述。 

     memset

    字节初始化内存空间。

    测试: 

     

    由于小端的存储方式,我们修改前9个字节实则将前3个整形变量修改成了0。 

     

  • 相关阅读:
    Leetcode 791. 自定义字符串排序
    vscode右键菜单栏功能说明
    处理非线性分类的 SVM一种新方法(Matlab代码实现)
    C++ 构造函数不能是虚函数的原因
    IgH详解十四、igh添加总线链路状态监测功能
    Stable Diffusion8
    js中使用原型链增加方法后,遍历对象的key-value时会遍历出方法
    物联网水表电子阀工作原理是怎样的?
    LLM应用实战:当KBQA集成LLM
    为什么高精度机器人普遍使用谐波减速器而不是普通减速器?
  • 原文地址:https://blog.csdn.net/dwededewde/article/details/132887641