2006年8月1日

犯下C++低级错误

在完成新版的LTP的Socket访问模式的过程中,有一个结果不稳定的错误一直困扰着我。那就是socket返回的结果不稳定,对于短小文本结果多数时候正确,但是会偶尔出现返回结果开头字符变成乱码的情况;对于长文本几乎都不能正确返回结果。打印即将的返回值到文本文件中,每次查看又都是正确的。采用先存为文件,然后将文件内容读取到char *[]中的方法返回却又能够得到完全正确的结果。呜呜……,这个问题真的很大,一直萦绕在我的头顶,真是吃饭睡觉都在想着这个问题。

真正解决这个问题,是在我不断的缩小查错范围后发现到可能情形的。在偶像陈儒的指点下才恍然大悟,自己犯下了C++中的一种常见的错误:函数返回局部变量的地址。

原先在我的程序中,一个大函数末尾有如下一段代码(大函数返回值类型为 char*)):

string strTemp = "";
strTemp = Processed(); // 这里Processed()是举例说明,这里返回一个字符串
return (char*)strTemp.c_str();

经过多次的跟踪和调试,我找到了是最后那句return出现了问题。起初我还以为是(char*)strTemp.c_str()对于strTemp的长度有所限制。经过陈儒帮我验证,发现并没有这样的限制。等到我把上面这段代码发送给陈儒,他非常直觉的告诉我可能是返回了一个局部变量的内存地址。这个局部变量的在函数运行结束后会被释放,其内容可能会被其他程序刷新。听到这个,我才恍然大悟,结果的不稳定原因就在这里。对于短字符串,内容被刷新的可能性比较小,而长字符串(比如上M)被刷新的可能性较大,使得程序运行起来出现前面提到的文本越长结果越不稳定的情况。

真是呜呜……,这种错误在C++编程里面是很低级的错误。但是回想自己犯下这种错误的原因,我分析是以前重来没有考虑过领事申请的一个string会去return它的地址,以前的直接return内容从来没有错过的。呵呵,socket模式下要求返回char *[]使得我犯下了下这个错误。不过,还算好,算是经验积累了,以后就不会再犯这样的错误了。

针对上面的代码,我修改为如下代码:

string strTemp = "";
strTemp = Processed();
int len = strTemp.size();
char* str = new char[len];
strcpy(str, strTemp.c_str() );
return str;

这样修改之后程序终于结束了结果不稳定的情况。感谢陈儒!

呵呵,算来自己从2000年学习C语言,2003年进入实验室后开始学习C++,C/C++编程的经验已经有好几年了。但是仔细想想自己现在的C/C++水平真是不怎么样,当初自己学习C++ Primer的时候只是学习了一半,现在看来那后一半有非常大的必要性仔细学习。呵呵,俺会认真的补上这课的。这不,俺刚才又发现随着函数调用次数的增多,程序占用的内存也逐渐增多了。这是程序中有内存泄漏的表现,还需要明天认证诊断呀!


1 条评论:

Bill Lang 说...

Comment's author: jnwang
09/06/2006 03:54:27 PM
string strTemp = "";
strTemp = Processed();
int len = strTemp.size();
char* str = new char[len];
strcpy(str, strTemp.c_str() );
return str;

str 释放了吗?