Skip to the content.

strcpy,memcpy,memmove, atoi 函数实现

Contact me

本系列博客主页及相关见此处


strcpy函数的实现

来自https://www.cnblogs.com/chenyg32/p/3739564.html

char * strcpy(char *dst,const char *src)   //[1]
{
    assert(dst != NULL && src != NULL);    //[2]

    char *ret = dst;  //[3]

    while ((*dst++=*src++)!='\0'); //[4]

    return ret;
}
  1. const修饰,源字符串参数用const修饰,防止修改源字符串。
  2. 空指针检查,
    • 不检查指针的有效性,说明答题者不注重代码的健壮性。
    • 检查指针的有效性时使用assert(!dst && !src); char *转换为bool即是类型隐式转换,这种功能虽然灵活,但更多的是导致出错概率增大和维护成本升高。
    • 检查指针的有效性时使用assert(dst != 0 && src != 0); 直接使用常量(如本例中的0)会减少程序的可维护性。而使用NULL代替0,如果出现拼写错误,编译器就会检查出来。
  3. 返回目标地址
    • 忘记保存原始的strdst值。
  4. ‘\0’
    • 循环写成while (dst++=src++);明显是错误的。
    • 循环写成while (src!=’\0’) *dst++=src++; 循环体结束后,dst字符串的末尾没有正确地加上’\0’。

为什么要返回char *?

返回dst的原始值使函数能够支持链式表达式。链式表达式的形式如:

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

又如:

char * strA=strcpy(new char[10],strB);

返回strSrc的原始值是错误的:

假如考虑dst和src内存重叠的情况,strcpy该怎么实现

char s[10]="hello";

strcpy(s, s+1); //应返回ello,

//strcpy(s+1, s); //应返回hhello,但实际会报错,因为dst与src重叠了,把'\0'覆盖了

所谓重叠,就是src未处理的部分已经被dst给覆盖了,只有一种情况:src<=dst<=src+strlen(src)

C函数memcpy自带内存重叠检测功能,下面给出memcpy的实现my_memcpy。

char * strcpy(char *dst,const char *src)
{
    assert(dst != NULL && src != NULL);

    char *ret = dst;

    my_memcpy(dst, src, strlen(src)+1);

    return ret;
}

my_memcpy的实现如下

char *my_memcpy(char *dst, const char* src, int cnt)
{
    assert(dst != NULL && src != NULL);

    char *ret = dst; 

    if (dst >= src && dst <= src+cnt-1) //内存重叠,从高地址开始复制
    {
        dst = dst+cnt-1;
        src = src+cnt-1;
        while (cnt--)
            *dst-- = *src--;
    }
    else    //正常情况,从低地址开始复制
    {
        while (cnt--)
            *dst++ = *src++;
    }
    
    return ret;
}

memcpy函数的实现

来自https://blog.csdn.net/goodwillyang/article/details/45559925

void *memcpy(void *dest, const void *src, size_t count)
{
    char *tmp = dest;
    const char *s = src;

    while (count--)
        *tmp++ = *s++ ;

    return dest;
}

现在是一个字节一个字节的拷贝,改进为按照cpu位宽来拷贝:

void * memcpy(void *dst,const void *src,size_t num)
{
	int nchunks = num/sizeof(dst);   /*按CPU位宽拷贝*/
	int slice =   num%sizeof(dst);   /*剩余的按字节拷贝*/
	
	unsigned long * s = (unsigned long *)src;
	unsigned long * d = (unsigned long *)dst;
	
	while(nchunks--)
	    *d++ = *s++;
	    
	while (slice--)
	    *((char *)d++) =*((char *)s++);
	    
	return dst;
}

如果复制的区域和目标区域有重叠怎么办?

void *memcpy(void *dest, const void *src, size_t count)
{
    char *d;
    const char *s;

    if (dest > (src+size)) || (dest < src))
    {
        d = dest;
        s = src;
        while (count--)
            *d++ = *s++;        
    }
    else /* overlap */
    {
        d = (char *)(dest + count - 1); /* offset of pointer is from 0 */
        s = (char *)(src + count -1);
        while (count --)
            *d-- = *s--;
    }

    return dest;
}

memmove函数的实现

来自https://www.cnblogs.com/dupuleng/articles/4538699.html,有了上面的基础,下面的代码就很好理解了。

void *my_memmove( void *dest , const void *src , size_t count)
{
    // check parameter 
    if(0 == count) return NULL;
    if(NULL == dest || NULL == src )  return NULL;
    char *dest_ ;
    char *src_ ;
    if(dest < src )
    {
        dest_ =(char*) dest; src_ = (char*)src;
        while( count-- )
        {
            *dest_++ = *src_++;
        }
    }
    else if( dest > src )
    {
        dest_ = (char*)dest + count;
        src_ = (char*)src + count;
        while(count -- )
        {
            *--dest_ = *--src_;
        }
    }
    return dest;
}

atoi函数的实现

来自https://blog.csdn.net/lanzhihui_10086/article/details/39995869

int atoi_my(const char *str)
{
	int s=0;
	bool falg=false;
	
    // 找到非空字符
	while(*str==' ')
	{
		str++;
	}
    // 处理符号
	if(*str=='-'||*str=='+')
	{
		if(*str=='-') falg=true;
		str++;
	}
    // 循环处理
	while(*str >= '0' && *str <= '9')
	{
		s= s * 10 + *str - '0';
		str++;
        // 溢出
		if(s < 0)
		{
			s = 2147483647;
			break;
		}
	}
    // 添加符号
	return s * (falg ? -1 : 1);
}