模拟实现strlen,strcpy,strcmp,strstr,strcat,memcpy,memmove,memset

strlen


实现的方法:

         使用 指针-指针 算出之间的差值,也就是这个字符串的真实长度
         (指针-指针的要求就是:两个指针是同一个类型)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

int My_Strlen(char *p)
{
    char *p1 = p;
    while( *p1 != '\0' )
    {
        *p1++;
    }
    /*while(*(++p1))
    {
        ;
    }*/
    return p1-p;
}

void testMy_strlen()
{
    char *p = "1234";
    printf("%d\n",My_Strlen(p));
}

strcpy


功能:字符串拷贝,把源字符串src,拷贝到目标空间dest中

实现过程:

     1. 目标空间( dest )足够大,足够容得下src字符串(包括\02. 目标字符串可修改,源字符串不能修改(类型前加const)

     3. 模拟实现strcpy返回值类型是char*,有返回值为了实现链式访问

     4. 把src中内容拷贝到dest中,直到src的'\0'拷贝过去结束
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

char* my_strcpy( char *dest,const char *src )
{
    char *ret = dest;
    assert(dest!=NULL);
    assert(src!=NULL);
    while( *ret++ = *src++ ) // 相当于 while( (*ret++ = *src) != '\0'  )
    {
        ;
    }
    return dest;
}

void testMy_strcpy()
{
    char p1[20] = "abcd"; // dest(目标空间)
    char *p2 = "efghi";   // src(源字符串)
    my_strcpy(p1,p2);
    // strcpy(p1,p2); 库函数的用法
    printf("%s\n",p1);
    printf("%d\n",strlen(my_strcpy(p1,p2)));
}

运行结果:

这里写图片描述

strcat


功能:字符串追加,把源字符串src,追加到目标空间dest中

实现过程:

        1. 目标空间( dest )足够大,足够容得下追加的src字符串(包括\02. 目标字符串可修改,源字符串不能修改(类型前加const)

        3.模拟实现strcat返回值类型是char*,有返回值为了实现链式访问

        4. 过程:

               首先要找目标空间dest中'\0',并且让源字符串src覆盖dest中'\0',
               然后开始追加,直到追加到src的'\0'结束  

           显然:

                strcat不能实现自己给自己追加,因为刚开始追加的时候,已经
                把'\0'覆盖,后面再去追加时(结束条件是:遇到'\0'),所以是无法实现的
char* My_Strcat(char *dest,const char *src)
{
    char *ret = dest;
    assert(dest && src);
    while( *dest != '\0' ) 
    {
        *dest++;
    }
    while( *dest++ = *src++ )
    {
        ;
    }
    return ret;
}

void testMy_strcat()
{
    char p1[20] = "abcd ";
    char *p2 = "efgh";
    // strcat(p1,p2); 库函数用法——p1是目标空间,p2是源字符串
    My_Strcat(p1,p2);
    printf("%s\n",p1);
}

运行结果:

这里写图片描述

strcmp


功能:字符串比较函数

实现过程:

      1. 首先s1和s2是固定字符串,要实现的是比较,所以都不能被修改
         因此必须加上const 修饰

      2. 先判断两个字符串长度是否相等,如果不相等,就没有必要再去遍历,直接返回-1

      3. 如果相等:一起遍历字符串,首先比较第一个字符:

         1. 两个字符的ASCII码值如果不相等,直接返回-1
         2. 两个字符的ASCII码值相等,继续遍历
      3. 直到遍历遇到'\0',结束遍历
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

int My_Strcmp(const char *dest,const char *src)
{
    int len1 = strlen(dest);
    int len2 = strlen(src);
    if( len1 != len2 )
        return -1;
    else
    {
        while( *dest && *src )
        {
            if( *dest == *src )
            {
                *dest++ ;
                *src++ ;
            }
            else
                return -1;
        }
        return 0;
    }
}

void testMy_strcmp()
{
    char *p1 = "hell0";  // 这里是零,结果比较就是不相等的
    char *p2 = "hello";

    int flag = My_Strcmp(p1,p2);
    if( flag == 0 )
    {
        printf("两个字符串相等\n");
    }
    else
    {
        printf("两个字符串不相等\n");
    }
}

运行结果:

这里写图片描述

strstr


功能:在字符串中查找子串,如果找到,输出第一次找到子串的开始位置

实现过程:

      1. 首先str和substr是固定字符串,要实现的是查找,所以都不能被修改
         因此必须加上const 修饰

      2. 要考虑到多种情况如下

             1."abcdef"中找"bcd"         返回b的地址,输出bcdef

             2."abcdef"中找""(空字符串)  没有必要找,直接把abcdef输出

             3.“abcbcd”中找"bcd"       

                 开始找str中b和substr中b相同,继续向后发现b和c不同,这时
                 substr应当退回去,从str中刚才开始匹配的下一个元素开始重新匹
                 配,也就是str第三个元素开始继续匹配,如此重复,直到匹配成功。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

char* My_Strstr( const char *str, const char *substr )
{
    char *cp = (char *)str;
    char *cur1 = (char *)str;
    char *cur2 = (char *)substr;
    assert(str);
    if( *substr == '\0' )
        return cp;
    while( *cp )
    {
        // cp是保存之前str的位置,cur1用来遍历的去比较字符串,
        // 万一没有匹配成功,cp++,重新开始匹配
        cur1 = cp;
        cur2 = (char *)substr;

        while( *cur1 && *cur2 && (*cur1 == *cur2) )
        {
            *cur1++;
            *cur2++;
        }
        if( *cur2 == '\0' )
            return cp;
        *cp++;
    }
    return NULL;
}

void testMy_strstr()
{
    char *p1 = "abcdbcd";
    char *p2 = "";
    printf("%s\n",My_Strstr(p1,p2));
}

运行结果:

这里写图片描述

char *p1 = "abcdbcd";
char *p2 = "bcd";

这里写图片描述

memcpy


功能:

   由src指向地址为起始地址的连续n个字节的数据复制到以dest指向地址为起始地址的空间内。    
   (src和dest内存不重叠)  

memcpystrcpy 的区别:

原型:

void *memcpy(void *memTo,const void *memFrom,size_t size)
char *strcpy(char *dst,const char *src);

相同点:

      strcpymemcpy都可以实现拷贝的功能

不同点:

1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容, 
   例如字符数组、整型、结构体、类等。

2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,  
   所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。

3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy

4、实现功能不同,strcpy主要实现字符串变量间的拷贝,memcpy主要是内存块间的拷贝。

5、操作对象不同,strcpy的操作对象是字符串,memcpy 的操作对象是内存地址,并不限于何种数据类型。

6、执行效率不同,memcpy最高,strcpy次之。
#include<stdlib.h>
#include<string.h>
#include<assert.h>
void *my_memcpy(void*dest, void*src, size_t n)
{
    char *p = (char *)dest;
    const char *p1 = (const char *)src;
    assert(dest && src);
    while(n--)
    {
        *p++ = *p1++;
    }
    return dest;
}
void testMy_Memcpy()
{
    char p1[20] = "abc";
    char *p2 = "abcdefg";
    // 库函数:memcpy(p1, p2, 5);
    my_memcpy(p1,p2,5);
    printf("%s\n",p1);
    //int p1[20] = {1,2,3};
    //int p2[6] = {1,2,3,4,5,6};
    // // 库函数:memcpy(p1, p2, 30); // 第三个参数是按照字节算的
    //my_memcpy(p1,p2,30);
    //printf("%d\n",p1[5]);
}

memmove


功能:
     由src指向地址为起始地址的连续n个字节的数据复制到以dest指向地址为起始地址的空间内。
     (src和dest内存重叠)

注意: 
     不重叠部分:从前向后拷贝
       重叠部分:从后向前拷贝
#include<stdlib.h>
#include<string.h>
#include<assert.h>

void * my_memmove( void *dest, const void * src, size_t count )
{
    void * ret = dest;
    if( dest <= src || (char *)dest >= (char *)src+count )
    {
        while( count-- )
        {
            *(char *)dest = *(char *)src;
            dest = (char *)dest + 1;
            src = (char *)src + 1;
        }
    }
    else
    {
        dest = (char *)dest + count-1;
        src = (char *)src + count -1;
        while(count--)
        {
            *(char *)dest = *(char *)src;
            dest = (char *)dest -1;
            src = (char *)src -1;
        }
    }
    return ret;
}

void testMy_Memmove()
{
    char p[] = "abcdefgh";
    // 库函数:memmove(p,p+2,7);
    my_memmove(p,p+3,5);
    printf("%s\n",p);
}

memset


功能:

    将s所指向的某一块内存中的前n个字节的内容全部设置为ch指定的ASCII值

1. 第一个参数为指定内存地址 

2. 块的大小由第三个参数指定

3. 这个函数通常为新申请的内存做初始化工作,其返回值为指向s的指针

void * my_memset(void*s, int ch, size_t n)
{
    assert(s);
    char *ret = (char *)s;
    while (n--)
    {
        *ret++ =(char) ch;
    }
    return s;
}
int main()
{
    char arr[10];
    int i;
    my_memset(arr, 0, 10*sizeof(char));
    for (i = 0; i < 10; i++)
    {
        printf("%d\n", arr[i]);
    }
    system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37941471/article/details/81479250
今日推荐