手写strcpy函数和memcpy函数以及两者区别

特点及函数原型

strcpy和memcpy都是标准c库函数,它们有如下特点:

strcpy提供了字符串的复制。即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符。strcpy的函数原型是:char* strcpy(char* dest,const char*src);

memcpy提供了一般内存的复制。从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。即memcpy对于需要复制的内容没有限制,因此用途更广。memcpy的函数原型是void *memcpy(void dest,const voidstr,size_t count);

strcpy函数

char* my_strcpy(char* dest, const char* src){
	if(dest == NULL || src == NULL) return NULL;
	char* res = dest;
	while(*dest != '\0'){
		*dest++ = *src++;
	}
	return res;

memcpy函数

void* my_memcpy(void* memdest, const void* memsrc, size_t size){
	if(memdest == NULL || memsrc == NULL) return NULL;
	char* mem_dest = (char*)memdest;
	const char* mem_src = (char*)memsrc;
	while(size-- > 0){
		*mem_dest++ = *mem_src++;
	}
	return memdest;

上面代码是错的,哪里错了呢,我们已经考虑memcpy可以拷贝任何数据类型的对象,如果dest和src的指针类型不一样,也需要处理,不能直接++使地址自增(例如: int* p和 charq, p++指针的值是4个4个加(0,4,8),q++是1个1个加(0,1,2,3,4))。所以统一强制转换为char类型
但是还有一点我们没有考虑到如果dest本身就有数据,执行memcpy()之后会覆盖原有的数据,所以src和dest所指向的内存区域不能有重叠
重叠就是dest在src的后面,而且src+count<=dest,那么后面得到的src已经被dest修改过了
在这里插入图片描述
这两种情况在memcpy中都是不允许出现的,需要在代码中处理以避免。为了处理上面这两种情况,后来又提供了另一个函数memmove,在不需要保留原来内存区域的数据的时候可以使用memmove。
所以当出现内存覆盖的时候,我们应该从后向前复制,那么我们才能得到正确的copy结果。我们可以将src和dest都移动 n-1个位置。这其实就是memmove的实现

void* my_memspy(void* memdest, const void* memsrc, size_t count){
	if(memdest == NULL || memsrc == NULL){
		return NULL;
	}
	char* mem_dest = (char*)memdest;
	const char* mem_src = (char*)memsrc;
	//没有产生内存重叠的情况
	//1.即使有重叠也不会复制错误的信息
	//2.src+要复制的位数 <=dest,那就是没有重叠
	if(mem_dest <= mem_src || mem_dest >= mem_src+count){
		while(count-- > 0){
			*mem_dest++ = *mem_src++;
		}
	}
	else{
		mem_dest = mem_dest + count - 1;
		mem_src = mem_src + count - 1;
		while(count-- > 0){
			*mem_dest-- = *mem_src--;
		}
	}
	return memdest;

memmove

memmove用于拷贝字节,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,但复制后源内容会被更改。但是当目标区域与源区域没有重叠则和memcpy函数功能相同。

不同点

strcpy和memcpy主要有以下3个方面的区别。

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C/C++面试之算法系列--几个典型的内存拷贝及字符串函数实现 写一个函数,完成内存之间的拷贝。[考虑问题是否全面,是否考虑内存重叠问题] 返回void *支持链式操作,参数类型是void *以支持任意类型的指针,输入参数加上const修饰,最好加上assert对输入输出指针进行非NULL判断 void* memcpy( void *dest, const void *src, size_t count ) { char* pdest = static_cast<char*>( dest ); const char* psrc = static_cast<const char*>( src ); // 依次从前拷贝,目的地址覆盖了源地址的数,此时从后往前拷贝 if( (pdest>psrc) && (pdest<(psrc+count))) //能考虑到这种情况就行了 { for( size_t i=count-1; i!=-1; --i ) pdest[i] = psrc[i]; } else { for( size_t i=0; i<count; ++i ) pdest[i] = psrc[i]; } return dest; } int main( void ) { char str[] = "0123456789"; memcpy( str+1, str+0, 9 ); cout << str << endl; memcpy( str, str+5, 5 ); cout << str << endl; system( "Pause" ); return 0; // 0012345678 // 4567845678 } strcmp(): Int simple_strcmp (const char *s1, const char *s2) { int ret; while ((ret = *(unsigned char *) s1 - *(unsigned char *) s2++) == 0 && *s1++); return ret; } memcmp(): int simple_memcmp (const char *s1, const char *s2, size_t n) { int ret = 0; while (n--&& (ret = *(unsigned char *) s1++ - *(unsigned char *) s2++) == 0); return ret; } strcmp只判断s1的‘/0’,没有长度的控制;memcmp有长度参数n的控制 memcpy(): char *simple_memcpy (char *dst, const char *src, size_t n) { char *ret = dst; while (n--) *dst++ = *src++; return ret; } 直接的内存之间的copy,不处理内存重叠的情况。 strcpy(): char *simple_strcpy (char *dst, const char *src) { char *ret = dst; while ((*dst++ = *src++) != '\0'); //相当简约,一句话即搞定 return ret; } 与memcpy区别就是对'\0'作为结束符 strncpy(): char *simple_strncpy (char *dst, const char *src, size_t n) { char *ret = dst; while (n--) { if ((*dst++ = *src++) == '\0') { while (n--) *dst++ = '\0'; return ret; } } return ret; } n和‘\0'都作为结束的控制符。如果n过大,则后面全补'\0'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值