字符串操作函数的模拟实现strlen;strcpy,strncpy;strcmp,strncmp;strcat,strncat;strstr

一、字符操作函数的模拟实现
strlen();strcpy(),strncpy();strcmp(),strncmp();strcat(),strncat();strstr()
//需要注意的地方有①不要忘记断言;②保留原字符串的起始地址,内存拷贝函数不存在这种情况
1.模拟实现strlen(),strlen()是用来求解字符串长度的函数,当遇到’\0’时停止计数,因此strlen()所求的字符串长度不包括’\0’的长度。

//1.1模拟实现strlen,计数器法模拟实现strlen()
int my_strlen1(const  char* str)//const防止字符串被改变
{
    assert(str != NULL);//断言,防止传入空指针,如果是空指针,会抛出异常,空指针不能进行解引用
    int count = 0;
    while(*str != '\0')//对字符串进行解引用,得到字符串里面的值然后与字符串的结尾标志'\0'进行比较
    {
        str++;
        count++;
    }
    return count;
}
//1.2用指针减指针的方法模拟实现strlen
int my_strlen2(const char *str)
{
    assert(str != NULL);
    char *p = str;
    while (*p != '\0')//同样,对指针进行解引用得到字符串里面的真实值然后与'\0'进行比较,知直到将p指针加到字符串的最后一个位置
    {
        p++;
    }
    return p - str;
}
//1.3、用函数递归的方法模拟实现strlen
int my_strlen3(const char *str)
{
    assert(str != NULL);
    if (*str == '\0')
        return 0;
    else
        return 1 + strlen(str + 1);
}

2.模拟实现strcpy(),strncpy()
①strcpy()是一种c语言的标准库函数,把以src为起始地址切含有’\0’的字符串拷贝到以dest为起始地址的空间内,当遇到’\0’时,拷贝结束。模拟实现时,需要手动将’\0’拷贝进去。
②strncpy()解决了strcpy()的溢出问题,strcpy()只是一个字符串拷贝函数,对拷贝的字节数没有限制,strncpy()可以选择一段字符进行输出。
③一般情况下,使用strncpy()时,建议将n置为dest串长度,复制完毕后,为保险起见,将dest串最后一字符置NUL。

//2.1模拟实现strcpy()
char* my_strcpy(char *dest, const char *src)//为了保证源字符串不被改变,需要在定义字符串之前加上const修饰;在这里需要注意,目标字符串必须有足够大的空间
{
    assert(dest != NULL&&src != NULL);
    char * address = dest;//保存目标字符串的起始地址,为了从起始地址开始返回拷贝之后的字符串
    while ((*dest++ = *src++))//后置++,先使用,后++,先把源字符串的第一个字符拷到目标字符串中,然后依次向后拷贝,最后再与'\0'进行比较,当指针走到'\0'时,while语句不成立,结束循环
    {
        ;
    }
    *dest = '\0';//需要将'\0'也拷贝进去
    return address;

}
//2.2模拟实现strncpy
//为了避免strcpy造成的溢出现象,可以考虑使用strncpy,srncpy是将源字符串src的n个字符复制到目标dest字符串当中,
//模拟实现strncpy要注意字符串中的'\0',因为它是将字符串中的n个字符拷贝到另一个字符串中,所以并不能确定是否将'\0'拷贝进去
char* my_strncpy(char *dest, const char *src, int n)
{
    assert(dest!=NULL&&src!=NULL);
    char *ret = dest;//保存原始字符串的地址,保存返回值
    while (n)//拷贝n个字符串
    {
        *dest++ = *src++;
        n--;
    }
    if ((*dest - 1) != '\0')//判断是否将'\0'拷贝进去
        *dest = '\0';
        return ret;
}
//3.1模拟实现strcmp(),strcmp()是一个字符串比较函数,s1==s2,返回0;s1
//s1>s2,返回正数,最终结果是返回二者的SASCII值之差
int my_strcmp1(const char *str1, const char* str2)
{
    assert(str1 != NULL);
    assert(str2 != NULL);
    while (*str1 == *str2)
    {
        if (*str1 == '\0')
            return 0;
        str1++;
        str2++;
    }
    return *str1 - *str2;//注意在这块对指针进行解引用,得到ASCII值相减的结果
}

3.模拟实现strcmp,strncmp这两个函数都是字符串比较函数,比较的结果是用相同位置上原字符串src上的字符所对应的ASCII减去目标字符串dest上的字符所对应的ASCII

//3.1模拟实现strcmp,strcmp是一个字符串比较函数,s1==s2,返回0;s1
//s1>s2,返回正数,最终结果是返回二者的SASCII值之差
int my_strcmp1(const char *str1, const char* str2)
{
    assert(str1 != NULL);
    assert(str2 != NULL);
    while (*str1 == *str2)
    {
        if (*str1 == '\0')
            return 0;
        str1++;
        str2++;
    }
    return *str1 - *str2;//注意在这块对指针进行解引用,得到ASCII值相减的结果
}
//3.2模拟实现strcmp
int my_strcmp2(const char *str1, const char *str2)
{
    assert(str1 != NULL);
    assert(str2 != NULL);
    while ((*str1 == *str2) && (*str1 != '\0'))
    {
        str1++;
        str2++;
    }
    return *str1 - *str2;
}
//3.3模拟实现strncmp(),strncmp()是比较两个字符串中前n个字符是否相等,只需要用while语句控制前n个字符即可
int my_strncmp(const char*dest, const char*src,int n)
{
    assert(dest);
    assert(src);
    while (n--)
    {
        if(*dest == *src)//在这里要注意用if-else语句,不用的话就只将第一个字符进行了比较
        {
            dest++;
            src++;
        }
        else 
          return *dest - *src;
    }

}

4.模拟实现strcat(),strncat()这是一组字符串追加函数,strcat是将原字符串src追加到目标字符串dest的后面,二strncat是将源字符串src的n个字符追加到目标字符串dest的后面。

//4.1 模拟实现字符串追加函数strcat(),strcat()是一个字符串连接函数,是将字符串str2连接到字符串str1的后面,
//并覆盖str1后面的'\0'
char* my_strcat(char *dest, const char *src)
{
    char *ret = dest;//保存原始字符串的起始地址
    while (*dest != '\0')//在追加字符串之前,需要先把原字符串先便利一遍,找到原字符串的结尾,遍历到'\0'时,循环退出
    {
        dest++;
    }
    while (*dest++ = *src++)
    {
        ;
    }
    return ret;
}
//4.2模拟实现字符串追加函数strncat(),这里是指追加字符串的前n个字符
//用两个while循环,第一个用来遍历目标字符串,找到原字符串的最后一个指针,
//第二个字符串用来完成原字符串向目标字符串的赋值(要注意指针的动态增长)
//在这里要定义一个ret指针,用来记录目标字符串的起始位置,用来准确返回
char* my_strncat(char* dest, const char*src, int n)
{
    assert(dest);
    assert(src);
    char *ret = dest;
    while (*dest)
    {
        dest++;
    }
    while (n--)
    {
        *dest++ = *src++;
    }
    *dest = '\0';
    return ret;
}

5.模拟实现strstr(),这个函数用来判断你要查找的字符串是否在原有的字符串当中,如果有,返回字符串在原有字符串中的位置,如果没有,则返回空
函数实现的整体思路如下:
①设置两个指针str,substr,分别指向两个字符串的头部,然后对两个指针进行解引用
②比较两个解引用后的两个字符是否相等,如果不相等,str继续往后走,substr不动;
③当两个指针相等时,两个指针同时向后走。另外,要注意一种特殊情况:str:abbbcdef substr:bbcd,如果用上面的方法就会出现错误,因此当遇到两个指针不想等时,str需要返回到起始位置的下一个位置,所以这里需要设置一个cp指针记录起始位置,同时,也要让substr回到起始位置
下来用图来解释以下上面出现的两种情况:
第一种情况:在字符串”abcdef”中查找”bcd”,思路如下:
字符串操作函数的模拟实现strlen;strcpy,strncpy;strcmp,strncmp;strcat,strncat;strstr_第1张图片
显然这种方法对于特殊情况是存在问题的,比如在字符串”abbbcdef”中查找”bbcd”,

字符串操作函数的模拟实现strlen;strcpy,strncpy;strcmp,strncmp;strcat,strncat;strstr_第2张图片如果按照传统的方法,就不会返回一个错误指针


char* my_strstr(const char* dest, const char *src)
{
    assert(dest);
    assert(src);
    char *str = (char*)dest;//,原字符串指针,这里需要强制类型转换
    char *substr = (char*)src;
    char *cp = (char*)dest;//用来保存原字符串的起始地址
    while (*cp)//保证需要比较的原字符串不为空
    {
        str = cp;
        while ((str != '\0') && (substr != '\0') && (*str == *substr))//判断条件是否成立
        {
            str++;
            substr++;
        }
        if (*substr == '\0')//判断字串是否比较完
        {
            return cp;
        }
        substr = src;//当两个指针不相等时,子串需要回到起始位置重新进行比较
        cp++;//原字符串回到起始位置的下一个位置再次进行比较
    }
}

你可能感兴趣的:(c语言)