内存移动的问题重点在于考虑内存重叠的区域处理。这是对内存地址空间和处理问题能力的综合考验。
我今天就遇到了这样一道面试题:重写strcpy(),题目是这样定义函数的:
char *strcpy(char *strDest, const char *strSrc);
要是以前对于我来说,直接就会这样写了:
char *strcpy(char *strDest, const char *strSrc)
{
int len = strlen(strSrc);
char *ret = strDest;
if(strDest == NULL || strSrc == NULL || strDest == strSrc)
return strDest;
while(len-- != 0)
*strDest++ = *strSrc++;
*strDest = '\0';
return ret;
}
但是现在我们要很认真地分析这个问题:
我们可以分成两部分来做,每一部分都考虑它的最极端的情况,根据这两种极端情况,我们可以对他们作出相应的处理。
(1)这种情况是strDest > strSrc, 但是strDest < strSrc+len-1.其中len=strlen(strSrc).用图形更好看:(地址从下往上:低到高)
假设strSrc 指向的内容是 "hello";
这种情况对于刚开始的那段程序显然结果是错误的。最后返回的是“hhhhh”。
这种强况强烈建议使用从末尾向开头的顺序复制,代码如下:
if(strDest > strSrc && strDest < (strSrc + len + 1)){
strDest = strDest + len -1;
strSrc = strSrc + len -1;
*(strDest+1) = '\0';
while(len-- != 0)
*strDest-- = *strSrc--;
return strDest;
}
其它情况我们可以很放心地进行从前向后的复制了,而且如果是以下这种情况我们必须从前向后复制:
即strDest<strSrc,这种情况我们一旦使用从后向前复制的话,就会是这样的结果:"ooooo".上面if的条件除外的其它条件是:
strDest < strSrc || strDest >= (strSrc + len +1).而这两种情况我们都可以使用从开头向末尾进行复制。代码如下:
else{
char *ret = strDest;
len = strlen(strSrc);
while(len-- != 0){
*strDest++ = *strSrc++;
}
*strDest = '\0';
return ret;
}
这样所用的情况都有了。在复制过程中就完全正确了!
下面是对以上问题的总结,方便记住什么情况我们该怎么做:
只要strDest(目标地址)在strSrc(源地址)的范围内,我们就使用从后向前复制即可。其它情况从前向后复制即可!
我今天就遇到了这样一道面试题:重写strcpy(),题目是这样定义函数的:
char *strcpy(char *strDest, const char *strSrc);
要是以前对于我来说,直接就会这样写了:
char *strcpy(char *strDest, const char *strSrc)
{
int len = strlen(strSrc);
char *ret = strDest;
if(strDest == NULL || strSrc == NULL || strDest == strSrc)
return strDest;
while(len-- != 0)
*strDest++ = *strSrc++;
*strDest = '\0';
return ret;
}
但是现在我们要很认真地分析这个问题:
我们可以分成两部分来做,每一部分都考虑它的最极端的情况,根据这两种极端情况,我们可以对他们作出相应的处理。
(1)这种情况是strDest > strSrc, 但是strDest < strSrc+len-1.其中len=strlen(strSrc).用图形更好看:(地址从下往上:低到高)
假设strSrc 指向的内容是 "hello";
. |
. |
. |
. |
\0 |
o |
l |
l |
strDest e |
strSrc h |
这种情况对于刚开始的那段程序显然结果是错误的。最后返回的是“hhhhh”。
这种强况强烈建议使用从末尾向开头的顺序复制,代码如下:
if(strDest > strSrc && strDest < (strSrc + len + 1)){
strDest = strDest + len -1;
strSrc = strSrc + len -1;
*(strDest+1) = '\0';
while(len-- != 0)
*strDest-- = *strSrc--;
return strDest;
}
其它情况我们可以很放心地进行从前向后的复制了,而且如果是以下这种情况我们必须从前向后复制:
. |
. |
. |
\0 |
o |
l |
l |
strSrc e |
strDest h |
strDest < strSrc || strDest >= (strSrc + len +1).而这两种情况我们都可以使用从开头向末尾进行复制。代码如下:
else{
char *ret = strDest;
len = strlen(strSrc);
while(len-- != 0){
*strDest++ = *strSrc++;
}
*strDest = '\0';
return ret;
}
这样所用的情况都有了。在复制过程中就完全正确了!
下面是对以上问题的总结,方便记住什么情况我们该怎么做:
只要strDest(目标地址)在strSrc(源地址)的范围内,我们就使用从后向前复制即可。其它情况从前向后复制即可!