昨天探讨了关于strcpy函数的一般实现方式:
- </pre><pre name="code" class="cpp">char* Mystrcpy(char* dst, const char* src)
- {
- assert(dst != NULL && src != NULL);
- char* ret = dst;
- while((*dst++ = *src++) != '\0');
- return ret;
- }
以下内容依旧转自:博客园-Norcy
但是上述代码并没有考虑到dst和src内存重叠的情况,即
- char s[10] = "hello";
- Mystrcpy(s, s+1);//应返回ello
- //Mystrcpy(s+1, s);//应返回hhello,但实际会报错,因为dst与src重叠了,把'\0'覆盖了
C函数memcpy自带内存重叠检测功能,下面给出memcpy的的实现Mymemcpy
- char* Mymemcpy(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;
- }
- char* Mystrcpy(char* dst, const char* src)
- {
- assert(dst != NULL && src != NULL);
- char* ret = dst;
- Mymemcpy(dst, src, strlen(src) + 1);
- return ret;
- }
Mymemcpy函数传递了三个参数,目的字符串地址,源字符串地址,要复制的字节个数(字符串长度加一)
当进入到函数体内部时,首先还是要判断指针有效性,保存原来的目的字符串地址
接下来判断内存是否重叠,当目的字符串的地址在源字符串第一个元素和最后一个元素的地址之间时,处于内存发生重叠的状态下,这个时候如果还按照从前向后的顺序复制,则从逻辑上源字符串被复制过来的内容覆盖,从而导致了源字符串的内容被改变(并不是通过指针来修改源字符串所以编译能够通过),但运行时程序会出错(具体错误原因不晓得,以后再深入研究),这个时候我们就应该换一个思路——从后向前复制(这种思路让我自己想我估计也是很费劲才能想出来,o(︶︿︶)o 唉,有一种代码,叫做别人的代码……)
让src指向源字符串的最后一个元素,dst也指向其加上源字符串长度之后的位置,然后向前复制cnt个字节
当然如果不是内存重叠的情况下就还是直接从前向后复制就好了(我在想Mymemcpy函数就不用判断内存是否重叠直接从后向前复制是不是代码能够简洁点呢……当然学习的话还是判断一下好,还没想出不判断是否重叠直接采用从后向前的方式复制有什么不好的地方……)
而且笔试面试的时候往往题目中还要求不能够使用库函数,如果有这个要求的话应该不用考虑内存重叠的情况了吧,毕竟调用Mymencpy的时候调用了strlen这个函数
一般情况下用一般方式的实现就应该可以了
【本文转至】http://blog.csdn.net/a3789910/article/details/41450373