前面, 我们说过, strcpy是一个非常不安全的函数, 如果大家在项目中还在用strcpy, 那是不是应该反思一下呢?  于是, 有了更好的strncpy.  

       但是, 有一次, 我在用strncpy的时候,我觉得很自然啊, 却犯了一个非常隐蔽的错误, 只是在当时的情况下, 该错误没有暴露出来。 在其他情况下, 肯定是有错误的。 原来实际是出现了内存重叠, 被某高人羡慕发现, 我心服口服啊。 

      看看有内存重叠的strcpy(为了简便起见, 我就不说strncpy的内存重叠了)

 

#include <iostream>
using namespace std;

int main()
{
	char str[100] = {0};
	strncpy(str, "abcdefghi", 100 - 1);

	strcpy(str + 2, str); // 内存重叠了, bug!!!
	cout << str << endl;

	return 0;
}

      我们期待的结果是:ababcdefghi,  但实际的结果是:ababcdcdghgh (在vc++6.0环境下),原来, strcpy/strncpy是没有考虑内存重叠的。 我不小心踩到了, 也算一种经历吧,  做软件开发就是这样, 犯错可以, 但不要犯相同的错误, 善于从错误中学习。

 

     

       那怎么办呢?

 

#include <iostream>
using namespace std;

int main()
{
	char str[100] = {0};
	strncpy(str, "abcdefghi", 100 - 1);
	cout << str << endl;

	char szTemp[100] = {0};
	strncpy(szTemp, str, sizeof(szTemp) - 1);

	strcpy(str + 2, szTemp);  // 这里是示意, 防止越界啊
	cout << str << endl;

	return 0;
}

     我们期待的结果是:ababcdefghi,  实际结果也是这样的。   

 

     

     微软啊微软, 你咋就没有提前解决这个bug呢? 下面, 我来尝试写一个, 不一定100%稳健, 希望大家提出其中可能存在的bug微笑.

 

#include <iostream>
using namespace std;

char *myStrCpy(char *dst, const char *src)
{
	if(NULL == dst || NULL == src)
	{
		return NULL;
	}

	int len = strlen(src);
	char *p = (char *)malloc(len + 1);
	if(NULL == p)
	{
		return NULL;
	}

	char *q = p;
	p[len] = '\0'; // 有必要
	while(*p++ = *src++)
	{
		;
	}

	p = q;
	while(*dst++ = *p++)
	{
		;
	}

	free(q); // 不是free(p);
	return dst;
}

int main()
{
	char str[100] = {0};
	strncpy(str, "abcdefghi", 100 - 1);

	myStrCpy(str + 2, str);
	cout << str << endl;

	return 0;
}

      结果:ababcdefghi, 和预期一致。 有bug的话, 欢迎大家拍砖, 共同进步羡慕

 

 

      另外, 在内存拷贝时候, strcat/strncat/memcpy也是不允许内存重叠的, 总之,  一定要注意内存重叠问题。 memcpy替代的解决方法是memmove.  原型是:

void *memmove( void* dest, const void* src, size_t count );  至于其他函数(如 strcpy/strncpy/strcat/strncat/)的替代方法, 就相对迂回了点, 需要自己多分配不重叠的内存去解决。


 

 


本文转载:CSDN博客