【C语言】特性描述及模拟实现strlen、strcpy、strcat、strchr、strstr、strcmp、memcpy、memmove

特性描述及模拟实现strlen、strcpy、strcat、strchr、strstr、strcmp、memcpy、memmove

  在学习C语言的过程中,不可避免的会经常接触一些库函数,那么有没有小伙伴想过这些库函数怎么实现的呢?
  往往这些库函数都是用最精炼最高效的方式写出的,观摩并模拟出库函数的实现,有利于我们对C语言的深入理解。
  今天我将我总结的字符串操作函数及其对应的一些小特性告诉大家,共勉。

特性描述及模拟实现

strlen函数

(测量字符串中到第一个’\0’之前字符的总长度)

特性

//strlen需要目标字符串中有’\0’。
//标准函数库中strlen函数的返回值是size_t类型(也就是无符号整形),也就是unsigned int型。因此在比较两个字符串长度是用到两个strlen相减是不对的。

实现

//非递归

#include <stdio.h>
#include <assert.h>

int my_strlen(const char* str)
{
    int count = 0;
    assert(str);

    while(*str != '\0')
    {
        count++;
        str++;
    }

    return count;
}

int main()
{
    int ret = my_strlen("hello bit");
    printf("%d\n", ret);

    return 0;
}

//递归

#include <stdio.h>
#include <assert.h>

int my_strlen(const char* str)
{
    assert(str);
    if(*str)
        return 1 + my_strlen(str + 1); 
    else
        return 0;
}
int main()
{
    int ret = my_strlen("hello");
    printf("%d\n", ret);

    return 0;
}

//指针相减

#include <stdio.h>
#include <assert.h>

int my_strlen(const char* str)
{
    assert(str);
    const char* p = str;

    while(*p)
        p++;

    return p - str;
}

int main()
{
    int ret = my_strlen("hello ");
    printf("%d\n", ret);

    return 0;
}

strcpy函数

(将第二个参数中字符串内容粘贴到第一个参数字符串中,包括’\0’)

特性

//strcpy不考虑目标空间的大小,即使目标字符串空间不够,也会将原字符串拷贝至目标中。
//strcpy需要原字符串中有’\0’。
//strcpy不要求目标字符串中有’\0’,拷贝时会将原字符串中的’\0’也拷贝至目标字符串中。
//strcpy第一个参数不能是常量字符串等不能进行写入的形式。例:将strcpy(“hello”, “hi”);

实现

#include <stdio.h>
#include <assert.h>

char* my_strcpy(char* dest, const char*src)
{
    assert(dest && src);
    char* p = dest;

    while(*p++ = *src++) ;   

    return dest;
}

int main()
{
    char str[10];
    my_strcpy(str, "abcdef");
    printf("%s\n", str);

    return 0;
}

strcat函数

(将第二个参数中字符串内容追加到第一个参数字符串中,将第一个参数字符串末尾的’\0’抹去,并在追加后给末尾加上’\0’)

特性

//strcat不考虑目标空间的大小,即使空间不够,也会将原字符串追加至目标后面。
//strcat需要目标字符串中有’\0’。
//strcat需要原字符串中有’\0’。
//追加时会将目标字符串中的’\0’覆盖掉,同时会将原字符串中的’\0’追加至目标字符串末尾。
//strcat第一个参数不能是常量字符串等不能进行写入的形式。例:将strcat(“hello “, “world”);

实现

#include <stdio.h>
#include <assert.h>

char* my_strcat(char* dest, const char* src)
{
    assert(dest && src);
    char* str = dest;

    while(*str)
        str++;

    while(*str++ = *src++); 

    return dest;
}

int main()
{
    char str[8] = "hello ";
    my_strcat(str, "bit");
    printf("%s\n", str);

    return 0;
}

strchr函数

(在第一个参数字符串中查找是否出现第二个参数字符)

特性

//strchr会返回目标字符串中第一次出现目标字符的地址
//如果strchr没有没有找到改字符,则会返回NULL
//strchr第一个参数可以是常量字符串。

实现


#include <stdio.h>
#include <assert.h>

char* my_strchr(const char* str, char ch) 
{
    assert(str);

    while(*str != ch && *str)
        str++;

    if(*str == ch) 
        return (char*)str;
    else
        return NULL;
}

int main()
{
    char str[] = "my name is LaoLi";
    printf("%s\n", my_strchr(str, 'L'));

    return 0;
}

strstr函数

(在第一个参数字符串中查找是否出现第二个参数字符串,也就是二字符串是否是一的子字符串)

特性

//strstr会返回目标字符串中第一次出现目标字符串的首字符的地址
//如果strstr没有没有找到改字符串,则会返回NULL
//如果第二个参数传递的是空字符串”\0”,strstr则会返回第一个参数的首地址。返回类型为(char*)
//strstr第一个参数可以是常量字符串。

实现

 include <stdio.h>
#include <assert.h>

char* my_strstr(const char* dest, const char* src)
{
    assert(dest && src);
    char* str = (char *)dest;
    char *s1, *s2;

    if(!*src)
        return (char *)dest;

    while(*str)
    {   
        s1 = str;
        s2 = (char *)src;

        while(*s1 && *s2 && (*s1 == *s2))
            s1++,s2++;

        if(!*s2)
            return str;

        str++;
    }   
}

strcmp函数

(对比一二字符串中每个字符的ASCII值,若一字符串中某字符大于二中对应位置字符,则返回正值,若两者字符都相等,则返回0值,否则,返回负值)

特性

//对比时,是在一二字符串中逐个字符比较,比较它们所对应的ASCII值大小
//在某些编译器下,比较得到的返回值是对应字符相减的大小,而VS编译器下比较得到的返回值是1,0,-1。

实现

#include <stdio.h>
#include <assert.h>

int my_strcmp(const char* str1, const char* str2)
{
    assert(str1 && str2);

    while(*str1 && *str2 && !(*str1 - *str2))
        str1++,str2++;

    return *str1 - *str2;

}

memcpy函数

(指定要拷贝字符串中字符的长度,拷贝到第一个参数字符串中,不可以拷贝自身)

特性

//由于是内存拷贝,故memcpy相比strcpy可以复制整形数组,结构体,类等。
//memcpy相对于strcpy不容易出现溢出现象,前者可以决定要拷贝的长度。
//内存拷贝时,第三个参数是你想拷贝的字节数。不要搞错了哦
//memcpy返回值为(void *)

实现

#include <stdio.h>
#include <assert.h>

void* my_memcpy(void* dest, const void* src, size_t n)
{
    assert(dest && src);
    char* str1 = (char *)dest;

    while(n--)
        *str1++ = *(char *)src++;

    return dest;
}

memmove函数

(拷贝指定字符串的指定长度到目标字符串中,可以拷贝自身)

特性

//memmove解决了memcpy不能自身拷贝自身的重叠覆盖问题
//其余特性几乎和memcpy一致
//memcpy与memmove实际功能对比如下:

memcpy

这里写图片描述

memmove

这里写图片描述

实现

#include <stdio.h>
#include <assert.h>

void* my_memmove(void *dest, const void* src, size_t n)
{
    assert(dest && src);
    char *pdest = (char *)dest;

    if (pdest < src)
    {
        //dest<src     左->右
        while (n--)
        {
            *pdest = *(char *)src;
            ++pdest;
            ++(char *)src;
        }
    }
    else
        //dest>=src     右->左
        while (n--)
            *(pdest + n) = *((char *)src + n);

    return dest;
}

int main()
{
    char str[] = "memmove can be very useful......";
    my_memmove(str+20, str+15, 11);
    puts (str);
    return 0;
}

注意:事实上在linux gcc编译器和vs2013编译器下memcpy和memmove实现方式是相同的,所以他俩的功能完全相同,即都可以解决自身拷贝自身的问题。

猜你喜欢

转载自blog.csdn.net/qq_41866437/article/details/80143951
今日推荐