手动实现strcpy并考虑内存重叠
在没有内存重叠的风险时的操作如下:
char *strcpy_(char *dst,const char *src)
{
assert(dst!=NULL&&src!=NULL); //头文件是#include <cassert>
char *r=dst;
while((*dst++ = *src++)!='\0'); //dst指针一直在变,所以要首先保存该指针。
return r;
}
C语言库函数中关于strcpy:把含有'\0'结束符的字符串复制到另一个地址空间,返回值类型为char *.。src和dst所指内存区域不可以重叠,且dst必须有足够空间来容纳src的字符串。
代码解释:
(1)首先应该检查指针的有效性,查看指针是否为空,这里使用assert。其头文件是#include <cassert>
(2)因为dst指针在变化,而最后需要返回目的地址的起始地址,需要先保存目的地址的起始地址。
(3)一定不要忘记给dst最后的结尾加上'\0',这里由循环的结束条件看出已经自动添加。
(4)返回类型为char *,即dst的原始值。这样可以使函数支持链式表达式,增加了函数的附加值。
int length=strlen(strcpy(strA,strB));
char *strA=strcpy(new char[10],strB);
返回的是dst的原始值,返回src的原始值是没有意义的。而且为了保护原始字符串,已经使用const char *来修饰形参,把const char*作为char *来返回,类型不符。
当出现内存重叠的情况呢?也就是说src的内存区域和dst的内存区域有重叠。
下图说明了所有src和dst内存相对的位置。
上述3种情况依次如下:
(1)src+count<=dst或dst+count<=src即不重叠,这时正常从低字节依次赋值
(2)dst+count>src 这时部分重叠,但不影响赋值拷贝,也可以从低字节开始
(3)src+count>dst 这时也是部分重叠,但影响拷贝,应该从高字节逆序开始。
其实第1种的第二种情况和第二种同属于一类,dst<src即可。
所以其实可以分为2类
(1)src+count<=dst||dst<src
(2)src+count>dst
char *strcpy_imp(char *dst,const char *src,int length)
{
assert(dst!=NULL&&src!=NULL);
if(dst<src||src+length<=dst)
{
char *s=dst;
while(length--)
{
*dst++=*src++;
}
return s;
}
else
{
dst=dst+length-1;
src=src+length-1;
while(length--)
{
*dst-- = *src--;
}
return ++dst; //不要忘了++;
}
}