模擬實現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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章