实现memmove、memcpy、strcpy、strncpy、strcmp和strlen:简单但细节很多

目录

1:strcpy

2. strncpy

3.strlen 

4.strcat

5.memcpy 

6.memmove

指向源字符串的指针是const:1是为了避免无意修改源字符串2是如果源字符串是"hello world"这种字符串字面值也能奏效。
string.h里面定义了str和mem开头的函数,除了memmove以外,其他函数都没有定义重叠对象间的复制行为

1:strcpy

注意:    源指针指向的值要用const修饰,防止修改,同时可以指向字符串字面值;

                目标指针指向的值要修改所以不能为const;

                如果src为nullptr,返回dest即可;如果dest为nullptr,返回nullptr;

                如果src == dest,那么直接返回dest;

                用ret保存dest的值,后面需要返回它,这样可支持链式表达式,如:

                        int len = strlen(strcpy(strA,strB));

                依次拷贝源指针指向的每个字符到目标指针,然后二个指针移动,最后如果遇到'\0'后就结束;

char* myStrcpy(char *dest,const char* src){
     assert(dest && src);
    if(dest == src) return dest;
    char* ret = des;
    while ((*dest++ = *src++) !='\0');
     //退出循环时:*dest == '\0'
    return ret;
}

2. strncpy

char * myStrncpy(char *dest,const char * src,int n){
    char * tmp = dest;
     assert(dest,src);
    if(dest == src || n<=0) return dest;
    while (n-- && (*tmp ++ = *src++) != '\0');
    *tmp = '\0'; 
//n--为0后推出循环,但是'\0'还没有拷贝,最后不要忘记加上字符串结尾标记
    return   dest;
}

3.strlen 

int myStrlen(const char * str){
    int len = 0;
    if(str == nullptr ) return  len;
    while (*str != '\0'){
        ++str;
        ++len;
    }
    return len;
}

4.strcat

char* myStrcat(char * dest,const char *src){ //在dest字符串末尾添加字符串src
    //调用者必须保证dest有足够的空间去将src放进去,本程序不提供保证。
    //在vc++上面测试,strcat源指针和目标指针相同的情况下也可以实现拼接
    assert(dest,src);
    char* tmp_str = dest;
    while (*tmp_str!='\0')tmp_str++; //这个就是strlen实现方式
//    char * tmp_str = dest  + myStrlen(dest); //指针移动到dest的末尾,调用strlen
    while ((*tmp_str++ = *src++) !='\0');
    //循环退出时:*tmp_str = '\0';
    return dest;
}

5.memcpy 

memcpy不考虑内存重叠问题,所以有安全问题;
memmove考虑内存重叠,所以比memcpy安全,但效率比memcpy差一点

void* myMemcpy(void* dest,const void* src,int n){

    if(dest == nullptr || src == nullptr ) return nullptr;
    if(dest == src) return dest; //二个指针指向相同,直接返回
    void* ret = dest; //ret指向dest,后面直接返回ret
    char* pdest = (char*)dest;
    const char* psrc = (const char*)src;
    while (n--){
        *pdest++ = *psrc++;
    }
    return  ret;
}

6.memmove

目标dest不能是const,因为要赋值;源src加const保护
memmove可以处理内存重叠的情况,而memcpy不能,所以memmove更安全,但如果确定没有内存重叠则memcpy效率高;

void* myMemmove(void* dest,const void* src,int  n ){

    if(dest == nullptr || src == nullptr ) return nullptr;
    if(dest == src) return  dest; //二指针指向相同,直接返回
    char* pdest = (char*)dest;
    void* ret = dest; //ret指向dest,后面直接返回
    const char* psrc = (const char *)src;
    if(pdest<=psrc || pdest>=psrc+n){//不存在内存重叠的2种问题,则从起始处开始逐一拷贝
        while (n--){
            *pdest++ = *psrc++;
        }
    } else{//可能发生内存重叠的1种情况:src<dest
        pdest+=n;//先移动n个字节,然后从后往前拷贝
        psrc+=n;
        while (n--){
            *--pdest = *--psrc;//先移动一个字节再拷贝
        }
    }
    return ret;
}

memcpy和memove的区别:

当没有内存重叠时,二者都可,但memcpy速度比memmove快一点;

当有内存重叠时候,memmove安全,memcpy不安全,要使用memmove;

当出现内存重叠时候,memmove保证源dest在被覆盖之前将重叠区域的字节拷贝到目标区域,但复制后src内容会被更改

strcpy和memcpy的区别:

1)复制的内容不同:strcpy用于拷贝字符串,还会复制字符串的末尾结束标记'\0';memcpy用于一般内存的复制,对需要复制的内容没有限制,用途更广。

2)复制的方式不同:strcpy复制时候不需要指定长度,通过判断是否遇到源字符串结束标记'\0'才结束,所以容易溢出;而memcpy需要第三个参数指定拷贝的长度,但出现内存重叠问题,则memcpy不安全,推荐使用memmove;

3)用途不同:通常复制字符串使用strcpy,复制其它数据类型使用memcpy;

memset常见用法:

1)初始化为0:  memset(a,0,sizeof a); 

2)初始化为-1: memset(a,-1,sizeof a); 

3)初始化为MAX: define MAX 0x3f3f3f3f  memset(a,0x3f,sizeof a);

        这样a数组里面的全部元素,就定义成了0x3f3f3f3f,这是个很好用的数字可以定义为无穷大,大概是1e9,算法题里面很多输入都没有超过它,并且二个相加也没有超过int的最大值

        经常看到定义最大值INF为0x7fffffff,这个十六进制数字是32-bit int的最大值,如果这个无穷大只适用于一般的比较,那么0x7fffffff是一个好的选择,但是有时候需要无穷大在加上一个数,那么这样0x7fffffff就会溢出了,所以可以使用INF=0x3f3f3f3f作为无穷大,它的十进制是1061109567,是10^9级别的(和0x7fffffff一个数量级),而一般场合下的数据都是小于10^9的,所以它可以作为无穷大使用而不致出现数据大于无穷大的情形。另一方面,由于一般的数据都不会大于10^9,所以当我们把无穷大加上一个数据时,它并不会溢出(这就满足了“无穷大加一个有穷的数依然是无穷大”),事实上0x3f3f3f3f+0x3f3f3f3f=2122219134,这非常大但却没有超过32-bit int的表示范围,所以0x3f3f3f3f还满足了我们“无穷大加无穷大还是无穷大”的需求。
 

strcmp实现:strcmp主要是用来判断二个字符串是否相等的库函数(判断相等时区分大小写)

(1)当str1==str2时,返回0

(2)当str1>str2时,返回大于0的整数

(3)当str1<str2时,返回小于0的整数

        编写实现的思路:首先判断参数入参有效性,参数错误则返回error,注意error提前宏定义为了-2,因为函数返回类型是int,所以即使参数错误返回也应该为int类型。循环的判断条件为(*str1!='\0')&&(*str1==*str2),实际上当str1或者str2为结束符'\0'或者str1和str2不再相等时,则退出循环。换种理解方式就是,当当前判断的字符不为'\0',并且相等两字符串当前的字符相等,则*str++后执行下一次判断,一旦不相等则进行比较大小。剩下的if就比较简单了,主要还是循环的判断条件要写对。

#include <stdio.h>

#define error -2

int mystrcmp(const char* str1, const char* str2)

{
    if((NULL == str1)||(NULL == str2)){
        return error;
    }
    while((*str1!='\0')&&(*str1==*str2))
    {
       str1++;
        str2++;
    }
    if(*str1>*str2){
        return 1;
    }
    else if(*str1<*str2){
        return -1;
    }else 
        return 0;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值