下面的程序会造成内存泄露吗?如果是的话,应该如何改进?

acqy 2005-06-16 09:09:22
char *LeftStr(const char *_str, int _pos)
{
char *buffer;
if (_pos <= 0 || _pos >= strlen(_str))
{
return (char *)_str;
}
buffer = new char[strlen(_str) + 1];
strncpy (buffer, _str, _pos);
return buffer;
}
...全文
213 20 打赏 收藏 举报
写回复
20 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
yhbttfile 2005-06-19
问题非常严重。
1、改函数的返回值怎么处理?
因为返回的字符串可能是一个字符串的引用,可能是堆上的数据。怎么使用都会导致内存泄漏。
如:
char szName[100] = "1111";
char *pszName = LeftStr(szName, 1);
...// 后续怎么处理这个pszName?使用delete pszName[]?去释放堆栈上的内存会是什么后果?

2、函数的语义实现也有问题:
1 char *LeftStr(const char *_str, int _pos)
2 {
3 char *buffer;
4 if (_pos <= 0 || _pos >= strlen(_str))
5 {
6 return (char *)_str;
7 }
8 buffer = new char[strlen(_str) + 1];
9 strncpy (buffer, _str, _pos);
10 return buffer;
11 }
从_pos的名称看,应该是position,不应该是len吧?所以,函数体的实现就可能是错误的,如:
其中,第6行是否应该:
return (char *)_str + _pos


3、由于你是使用的是C++语言,这样的C-STRING实现难免会出问题。建议使用std::string。
所以,函数就可以是这样的了:
std::string LeftStr(std::string &sstr, std::string::size_type _pos)
{
if(_pos >= sstr.size()) return "";
std::string tmpstr(sstr, _pos);
return tmpstr;
}
注:我把_pos理解位开始位置,而不是长度。

  • 打赏
  • 举报
回复
yhbttfile 2005-06-19
这里的_pos还要注明不是绝对位置(相对位置是从0开始的)。
其实,位置的问题还是应该是相对的好。还是改回原来的吧:
std::string RightStr(std::string &sstr, std::string::size_type _pos)
{
if(_pos >= sstr.size()) return "";
std::string tmpstr(sstr, _pos);
return tmpstr.c_str();
}

如果是取左边的,则修改为:
std::string LeftStr(const std::string &sstr, std::string::size_type _pos)
{
if(_pos >= sstr.size()) return "";
string tmpstr(sstr, 0, _pos); // 这里省去了多个临时对象,比直接调用substr好。
return tmpstr.c_str();
}



  • 打赏
  • 举报
回复
yhbttfile 2005-06-19
to CSDNWW(中国软件WW):
呵呵,大侠厉害。
这个程序我前面有假设,假设是位置右边的字符串。可能我对楼主的理解有误。

另,我犯了一个倏忽性的错误。
应该是_pos-1才对。

应该修改为:
std::string RightStr(std::string &sstr, std::string::size_type _pos)
{
if(_pos >= sstr.size()) return "";
std::string tmpstr(sstr, _pos - 1);
return tmpstr;
}

另,我这里还要提醒的是,目前有很多厂商的STL对string实现都存在多线程问题。如果不考虑效率,且存在多线程问题,至少SGI的存在问题(已经证明过),RW的也存在问题(还没有找到证据)。
这里可以做一个改进:
std::string RightStr(std::string &sstr, std::string::size_type _pos)
{
if(_pos >= sstr.size()) return "";
std::string tmpstr(sstr, _pos - 1);
return tmpstr.c_str();
}
“return tmpstr.c_str();”的目的是不希望做引用计数方式的复制,而是做深复制。
  • 打赏
  • 举报
回复
CSDNWW 2005-06-19
#include<string>
#include <iostream>
using namespace std;

std::string LeftStr(const std::string &sstr, std::string::size_type _pos)
{
if(_pos >= sstr.size()) return "";
string tmpstr2 = sstr.substr(0, _pos);
return tmpstr2;
}

void main()
{
//取到第三个
std::string a = LeftStr("asdfsadfsadf", 3);
cout<<a<<endl;

}
  • 打赏
  • 举报
回复
CSDNWW 2005-06-19
>>>std::string LeftStr(std::string &sstr, std::string::size_type _pos)
{
if(_pos >= sstr.size()) return "";
std::string tmpstr(sstr, _pos);
return tmpstr;
}

竞然是取字符串右边, 怎么这样命名:LeftStr()
  • 打赏
  • 举报
回复
yhbttfile 2005-06-19
to heguosheng(何国胜):
这里可是C++的BBS,不是C。如果是C,则会有另外的解法。
不过,STL移植到嵌入式系统也很容易。自己构建一个默认的内存分配器(也就是内存池),使用自己的内存分配策略,也可以解决问题。
并不是嵌入式就不能使用STL了。这点很重要。
  • 打赏
  • 举报
回复
heguosheng 2005-06-19
stl确实是个好东东。
为什么在看c代码的时候,都会有人推荐用stl,而不先问问实际代码运行的硬件环境呢?
假如在一个RAM和flash非常紧缺的嵌入式系统里,移植一个stl代价可能会比较大吧
  • 打赏
  • 举报
回复
brianlu 2005-06-16
感觉你就是在改写strncpy(),把传入的参数事先检察一边,再包装起来.
呵呵。
  • 打赏
  • 举报
回复
brianlu 2005-06-16
void LeftStr(const char *_str, int _pos, char *_buffer)
{
/**
if(_buffer == NULL)
{
return;
}
*/
if (_pos <= 0 || _pos >= strlen(_str))
{
return ;
}
if (_str == NULL)
{
return;
}
memset (_buffer, 0x00, strlen(_str) + 1);
strncpy (_buffer, _str, _pos);
}


strcpy(char * tar, const char *src)函数原型也是这样做的,
传入2个参数,都必须事先分配好内存空间。



  • 打赏
  • 举报
回复
brianlu 2005-06-16
char *LeftStr(const char *_str, int _pos, char *_buffer)
{
char *buffer; ------>>>>>>>>>>>>>>>>> //这里你定义了个非法指针哦,呵呵!
if (_pos <= 0 || _pos >= strlen(_str))
memset (_buffer, 0x00, strlen(_str) + 1);
strncpy (_buffer, _str, _pos);
return _buffer;
}
  • 打赏
  • 举报
回复
BluntBlade 2005-06-16
对待处女,谁污染,谁治理;
对待内存,谁分配,谁释放。
  • 打赏
  • 举报
回复
brianlu 2005-06-16
不好意思,写错了
delete [] ****;
一般不在函数里面用new的,这样设计的函数有问题,容易出现
忘记内存释放。
一般在构造函数里new,然后再析构函数里检察并释放
  • 打赏
  • 举报
回复
acqy 2005-06-16
to brianlu(-) & llf_hust()
我不知道这样做是否符合函数使用者的思想,因为对于一个函数使用者来说,他很难意识到在调用了LeftStr以后还需要delete,事实上,我现在的做法是:
char *LeftStr(const char *_str, int _pos, char *_buffer)
{
char *buffer;
if (_pos <= 0 || _pos >= strlen(_str))
{
return (char *)_str;
}
if (_str == NULL)
{
return NULL;
}
memset (_buffer, 0x00, strlen(_str) + 1);
strncpy (_buffer, _str, _pos);
return _buffer;
}
那么程序员在使用这个函数的时候,就必须:
char buffer[MAX_SIZE];
printf ("%s\n", LeftStr("Test", 3, buffer));
或者:
char *buffer = new char[MAX_SIZE];
printf ("%s\n", LeftStr("Test", 3, buffer));
delete buffer;
这样做就使得new和delete成对出现,不会让程序员感到困扰。
然而这样做,需要多定义一个buffer,就会比较麻烦了。所以请高手赐教。如何解决这个问题。
  • 打赏
  • 举报
回复
6spring 2005-06-16
自己写个字符串分配器 ^___^

所有字符串都通过它来分配,回收,释放

在某个适当时机用字符串分配器把所管理的字符串释放就不容易出现大问题
  • 打赏
  • 举报
回复
brianlu 2005-06-16
我是叫你在函数调用结束后再delete;
比如
char * temp = LeftStr(...);
什么时候不要用temp了,就delete(temp);
没叫你在函数里delete
  • 打赏
  • 举报
回复
llf_hust 2005-06-16
char s[]="abcdefg",*s1;
s1 = LeftStr(s,2);
delete []s1;
可以这样删除分配的内存空间
  • 打赏
  • 举报
回复
brianlu 2005-06-16
3 buffer 字符串的最后一位没有赋值'\0'
strncpy (buffer, _str, _pos);
buffer[pos] = '\0';
  • 打赏
  • 举报
回复
acqy 2005-06-16
我也这么认为,但是如果delete了的话,就没有办法返回这个值了。请高手赐教!
  • 打赏
  • 举报
回复
brianlu 2005-06-16
1 没有检察const char *_str,中_str指针指向的是否为NULL
strncpy(buffer, NULL, _pos)会是什么结果呢?

2 new出来的空间 没有在函数结束后 delete 掉
  • 打赏
  • 举报
回复
dlyy 2005-06-16
new的没有被delete吧
  • 打赏
  • 举报
回复
发帖
C++ 语言

6.2w+

社区成员

C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
帖子事件
创建了帖子
2005-06-16 09:09
社区公告
暂无公告