大家一般认为名不见经传strcpy函数实现不是很难,流行的strcpy函数写法是:
char *my_strcpy(char *dst,const char *src)
{
assert(dst != NULL);
assert(src != NULL);
char *ret = dst;
while((* dst++ = * src++) != '\0')
;
return ret;
}
如果注意到:
1,检查指针有效性;
2,返回目的指针des;
3,源字符串的末尾 '\0' 需要拷贝。
写出上面实现函数就不在话下。
然而这样的实现没有考虑拷贝时内存重叠的情况,下面的测试用例就能使调用my_strcp函数的程序崩溃:
[cpp] view plaincopy
char str[10]="abc";
my_strcpy(str+1,str);
然而调用系统的strcpy函数程序正常运行,打印str结果为“aabc”!可见系统strcpy函数的实现不是这样的。
strcpy的正确实现应为:
char *my_strcpy(char *dst,const char *src)
{
assert(dst != NULL);
assert(src != NULL);
char *ret = dst;
memcpy(dst,src,strlen(src)+1);
return ret;
}
memcpy函数实现时考虑到了内存重叠的情况,可以完成指定大小的内存拷贝,它的实现方式建议查看文章“卓越的教练是如何训练高手的?”,会获益良多,这里仅粘帖函数memcpy函数的实现:
真正的
char *strncpy(char *dst, const char *src, size_t len)
{
assert(dst != NULL && src != NULL);
char *res = dst;
if (dst >= src && dst <= src + len - 1)//重叠,从后向前复制
{
dst = dst + len - 1;
src = src + len - 1;
while (len--)
*dst-- = *src--;
}
else
{
while (len--)
*dst++ = *src++;
}
return res;
}
那么,如果要处理内存重叠,该怎么办?如果内存重叠和src的长度小于len这两种情况同时出现,又如何处理?
见图,假设红色部分为src,黄色为dst。如果出现内存重叠,我们很容易想到:从后往前拷贝。如果src的长度小于len,则在后面补NUL。
char *strncpy(char *dst, const char *src, size_t len) { assert(dst != NULL && src != NULL); char *res = dst; int offset = 0; char *tmp; if (strlen(src) < len)//src长度小于len { offset = len - strlen(src); len = strlen(src); } if (dst >= src && dst <= src + len - 1)//重叠,从后向前复制 { dst = dst + len - 1; src = src + len - 1; tmp = dst; while (len--) *dst-- = *src--; } else { while (len--) *dst++ = *src++; tmp = dst; } while (offset--) { *tmp++ = '\0'; } return res; }
内存重叠:拷贝的目的地址在源地址范围内。所谓内存重叠就是拷贝的目的地址和源地址有重叠。
在函数strcpy和函数memcpy都没有对内存重叠做处理的,使用这两个函数的时候只有程序员自己保证源地址和目标地址不重叠,或者使用memmove函数进行内存拷贝。
memmove函数对内存重叠做了处理。
函数原型:
1.memcpy和memmove相同点
|
实现strstr
leetcode 28
class Solution {
public:
int strStr(string haystack, string needle) {
if (needle.empty()) return 0;
int m = haystack.size(), n = needle.size();
if (m < n) return -1;
for (int i = 0; i <= m - n; ++i) {
int j = 0;
for (j = 0; j < n; ++j) {
if (haystack[i + j] != needle[j]) break;
}
if (j == n) return i;
}
return -1;
}
};