为什么在调用_tcscpy_s后用delete释放new分配的内存会调试出错?

keyskey 2008-01-03 12:02:47
void nottmp(LPTSTR FilePatch)
{
…………
LPTSTR File_LocalPatch;
File_LocalPatch = new TCHAR[_tcslen(FilePatch)];
_tcscpy_s( File_LocalPatch, _tcslen(File_LocalPatch), FilePatch);
…………
delete [] File_LocalPatch;
}
用malloc()和free()同样出错。
错误信息是:
其原因可能是堆被损坏,这也说明 test.exe 中或它所加载的任何 DLL 中有 bug。
不是用_tcsXXX之类的函数就什么问题没有,望高手解惑。
...全文
468 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
sevendog 2010-10-27
  • 打赏
  • 举报
回复
??????????????????????????
evergreendream 2010-06-24
  • 打赏
  • 举报
回复
学习了
keyskey 2008-01-03
  • 打赏
  • 举报
回复
_tcscpy_s( File_LocalPatch, _tcslen(File_LocalPatch), FilePatch);
是不是这句访问越界了??
望大大们解答下。
keyskey 2008-01-03
  • 打赏
  • 举报
回复
多谢,第一次问问题,给分没搞错吧
kevinlynx 2008-01-03
  • 打赏
  • 举报
回复
今天看来丢脸不少啊。。。。终于还是把楼主的程序自己实验了下,例子程序如下:

wchar_t *ss = L"疯了疯了";
wchar_t *s = new wchar_t [_tcslen( ss )+1];//如果不+1,就出错

_tcscpy_s( s, _tcslen( s ), ss );

delete [] s;


为什么如果不加1就出错呢?简单地说就是因为在拷贝数据到s时(_tcscpy_s),s无法容纳为ss中的所有内容,因为_tcslen(s) 通常都是个很大的数,因为在你分配的内存里找不到\0结束符。那么,_tcscpy_s除了拷贝ss内容外,还会自动拷贝一些\0字符,但是s只够容纳ss的内容(不包括\0),从而就导致程序崩溃。

那么,LZ的代码可以修改为:

void nottmp(LPTSTR FilePatch)
{
…………
LPTSTR File_LocalPatch;
File_LocalPatch = new TCHAR[_tcslen(FilePatch)+1]; //+1保存\0
// _tcslen( FilePatch ) + 1 而不是_tcslen( File_LocalPatch )
_tcscpy_s( File_LocalPatch, _tcslen(FilePatch)+1, FilePatch);//+1是为了拷贝进\0
…………
delete [] File_LocalPatch;
}



这回应该没错了。。。唉。。。下次回答问题小心点。。
kevinlynx 2008-01-03
  • 打赏
  • 举报
回复
疯了,这可能是我回的最多的帖子了。。。LZ抱歉,原来:_tcscpy_s接收的三个参数,你是正确的,提供例子代码如下:

wchar_t *s = new wchar_t [200];
wchar_t *ss = L"疯了疯了";

_tcscpy_s( s, _tcslen( ss ) + 1, ss );

delete [] s;


kevinlynx 2008-01-03
  • 打赏
  • 举报
回复
要弄就要完全弄正确:

纠正下我之前所描述的不确定结论,以下结论为我的最终结论:
1.虽然File_LocalPatch指向的内存区域里的内容是随机的,_tcslen找不到\0字符串结束符,该函数可能会访问到其他内存区域,但是因为这里是访问,所以程序不会出错。
以下程序可以验证:

wchar_t *s = new wchar_t [200];

printf( "%d", _tcslen( s ) );



2.LZ的_tcscpy_s函数确实不接受三个参数,也就是不接受拷贝的长度,_tcsncpy函数则接受拷贝长度(MSDN for vs2005查阅所得),大致原型为:

wchar_t *wcsncpy( wchar_t *strDest, const wchar_t *strSource, size_t count );

_tcsncpy 本身是一个宏,会根据程序使用的是UNICODE还是narrow character来决定是否调用UNICODE版本,所以这里拿wcsncpy为例。该函数第一个参数是目标内存区域,第二个参数为原字符串,第三个为拷贝的长度,拷贝的长度最好为_tcslen( strSource ) + 1,这样可以拷贝\0结束符。
例如:

_tcsncpy( File_LocalPatch, FilePatch, _tcslen( FilePatch ) + 1 );


完毕。楼主把分全给我吧。


kevinlynx 2008-01-03
  • 打赏
  • 举报
回复
根据LZ代码的意思,我帮你改写下吧:

void nottmp(LPTSTR FilePatch)
{
…………
LPTSTR File_LocalPatch;
File_LocalPatch = new TCHAR[_tcslen(FilePatch) + 1];// + 1是为了保存\0结束符
//_tcscpy_s( File_LocalPatch, _tcslen(File_LocalPatch), FilePatch);
_tcscpy_s( File_LocalPatch, FilePath ); //据我了解的这个函数似乎不需要传入拷贝数据的长度
// 如果LZ使用这个函数没错误,即如果要传入长度,那么就这样:
// _tcscpy_s( File_LocalPatch, _tcslen( FilePatch ), FilePatch );
…………
delete [] File_LocalPatch;
}

kevinlynx 2008-01-03
  • 打赏
  • 举报
回复
很简单,_tcslen以及strlen之类的函数是返回一个字符串的长度的,例如:"abc"返回的就是3,如何返回这个长度呢?这个函数就是通过字符串的结尾符,也就是\0来判定字符串结束的。

在你的代码里,File_LocalPatch (也许你是想写File_LocalPath)指向了刚分配的内存,但是这段内存的内容是随机的,因为new分配的内存默认情况下里面的内容是随机的。那么,_tcslen判断File_LocalPatch这个字符串时(高手容我这样简单地描述),就找不到\0这个结束符,那么_tcslen返回的值可能很大,也可能是_tcslen在查找\0过程中访问到了不可访问的内存(会导致错误)

64,643

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧