概述:
1:strncpy和strncpy主要是用于字符串的拷贝。
2:而memcpy()和memmove()则适用于所有的数据类型。
3: memcpy()和memmove()这两者的区别在于内存重叠的处理。
4:本文给出的代码都是基于函数的功能所写的代码,不一定就是官方的实现代码。但是实现的功能是一样的。
展开:
/*************************************************/
1.strcpy()函数
/*************************************************/
1 原型:
char *strcpy(char* dest, const char *src);
2 定义
把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间
3 拷贝终止条件
当src字符结束时,把src末尾的’\0’也拷贝过来,复制结束。
4 代码实现
自己取函数名为mystrcpy();
char * mystrcpy(char *dst,const char* src)
//源字符串不能改变,所以const修饰
{
assert(dst!=NULL&&src!=NULL);//断言方式确保指针不为空
char* p=dst;
while((*p++=*src++)!='\0');//逐个复制 直到*src='\0',注意src末尾的'\0'也要拷贝过来
return dst;//返回的是目标字符串的首地址dst,在这里不能返回指针p
}
/*************************************************/
2.strncpy()函数
/*************************************************/
1 原型
strncpy()的原型是
char* strncpy(char*dest, char*src, size_t n);
其中:n为指定的拷贝的字节长度。
2 定义
:(c/c++)复制字符串src中的内容(字符,数字、汉字….)到字符串dest中,复制多少由size_tn的值决定。如果src的前n个字符不含NULL字符,则结果不会以NULL字符结束。
如果n<src
的长度,只是将src的前n个字符复制到dest的前n个字符,不自动添加’\0’,也就是结果dest不包括’\0’,需要再手动添加一个’\0’。如果src的长度小于n个字节,则以NULL填充dest直到复制完n个字节。src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符长度+’\0’。
3 拷贝终止条件:
3-1:n<=strlen(src)+1,复制n个字符,不自动加'\0'
3-2: n>strlen(src)+1,复制完src之后,因为复制次数还没有达到n,所以后面的每一次都是往dst补零,直到复制次数到达n.
代码实现
char* mystrncpy(char* dst, const char*src ,unsigned int n)
{
assert(dst!=NULL&&src!=NULL);//断言
char *pdst=dst;
while(n&&(*pdst++=*src++)!='\0'){n--;}//注意此处n--不要放在while()的比较表达式里面。
if(n)
{
while(n--)
{
*pdst++='\0';
}
}
return dst;
}
/*************************************************/
3.memcpy()函数
/*************************************************/
1原型:
memcpy()的原型是
void *memcpy(void *dest, const void *src, size_t n);
其中:n为指定的拷贝的字节长度。
2定义
2-1 从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中.
2-2 注意:source和destin都不一定是数组,任意的可读写的空间均可
3拷贝终止条件:
复制次数达到n
4代码实现
void *mymemcpy(void *dst,const void *src,unsigned int num)//没有考虑内存重叠。
{
assert(dst!=NULL&&src!=NULL);
char*pdst=(char*)dst;
const char *psrc=(const char*)src;
while(num--)
{
*pdst++=*psrc++;
}
return dst;
}
/******************************************/
思考
/**********************************************/
上面的memcpy()看似没有什么问题,但是当dst与src发生内存重叠时,就会出现问题了。
(这里需要说明的是,有些IDE像vs2010等就已经考虑了这种情况了,所以你所调用的memcpy就是我们下文要说的memmove.但是c标准没有规定一定要对memcpy进行内存重叠的考虑。所以你可能会发现有的编译环境下memcpy考虑了内存重叠,有些则没有考虑。这里我们说的就是没有考虑的情况。)
举个例子。
char str[]="abbbb";
memcpy(str+2,str,3);
我们本意是将str后面的三个连续的字符拷贝到str[2]往后的三个字节里面。就是说我们期待着的结果是:str[]=“ababb”;
但是当你执行之后,就会发现运行结果是str="ababa";
原因很简单,内存发生了重叠了,原本的str[2]为’b’,在第一次拷贝时就被str[0]给替换成了’a’了,这就导致了最后一次拷贝时str[2]传递给str[4]的是’a’而不是‘b’。
什么时候会发生内存重叠呢?
满足 :
1:src<dst<=src+n
会发生重叠,需要反序拷贝。
2:当src>dst
或者dst<src+n
则不会发生内存重叠,此时 正序拷贝/反序拷贝皆可。
所以可以进一步简化为:
1:src>dst
正序拷贝
2:src<dst
反序拷贝
3:src=dst
不拷贝
【上面提供了两种方式,本文我们简单点,将会采用第二种方式进行代码实现。】
下面就是memmove的真正介绍了。
/*************************************************/
4.memmove函数
/*************************************************/
1原型:
void *memmove( void* dest, const void* src, size_t n );
其中:n为指定的拷贝的字节长度。
2定义
memmove用于从src拷贝n个字节到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。但复制后src内容会被更改。但是当目标区域与源区域没有重叠则和memcpy函数功能相同。
3拷贝终止条件:
已经复制了n个字节
4代码实现
void* mymemmove(void *dst,const void *src,unsigned int n)
{
assert(dst!=NULL&&src!=NULL);
char* pdst=(char*)dst;
const char* psrc=(const char*)src;
if(pdst<psrc)//正序
{
while(n--)
{
*pdst++=*psrc++;
}
}
else if(pdst>psrc)//反序
{
psrc=psrc+n-1;//边界要考虑好。
pdst=pdst+n-1;
while(n--)
{
*pdst--=*psrc--;
}
}
return dst;
}
以上就是关于这几个函数的简单介绍,不对之处欢迎指正交流。