C++ 无法删除 char*,不断损坏堆
Posted
技术标签:
【中文标题】C++ 无法删除 char*,不断损坏堆【英文标题】:C++ can't delete char*, keeps corrupting heap 【发布时间】:2013-12-31 02:07:12 【问题描述】:语言:C++,编译器:MSVS (/Za) 和 g++(是的,它必须同时适用),级别:初学者
我正在尝试从 char* 中删除数据,以便重新分配它并继续我的程序。我创建了一个新的 char*,将命令行参数的值分配给它,进行一些验证,然后如果验证失败,它应该解除分配 char* 并让我将新数据分配给 var 但是我得到一个“堆检测到损坏”Visual Studio 中的错误。我很好奇我当前代码的修复以及可以更清晰/简洁地完成的任何其他方式。
在 main() 中:
//...
//make non constant versions to be messed with
char* ba = new char[ strlen(argv[4]) + 1 ];
char* num = new char[ strlen(argv[2]) + 1 ];
//make non constant versions of commandline stuff
nonConstant( argv[4], argv[2], ba, num );
//do the conversion and printing
convert( ba, num );
//...
convert 这样做:
//...
if( error )
getNew(ba, num, &error);
//...
这里是getNew:
void getNew( char* ba, char* num, bool error )
//if there's an error in their numbers let them input new stuff and check to see if that's valid
while( error )
//tell the user that the input was bad an prompt for more, use getline because strings are weird
//cin stuff here (this part works, no problems)
//free up base and num so I can reassign them
delete[] ba; //<--this line fails
delete[] num;
//set lengths = to lengths of input + 1 for \0
ba = new char[ inputBa.length() + 1 ];
num = new char[ inputNum.length() + 1 ];
//do the assignment of new input back to base and num
inputBa.copy( ba, inputBa.length(), 0 );
inputNum.copy( num, inputNum.length(), 0 );
//ensure that the input was good this time
validateInput( ba, num, error );
【问题讨论】:
编译时启用提示和警告。 如果getNew
的参数error
声明为bool
类型,为什么getNew
调用中对应的参数看起来像&error
???我的意思是它可能在形式上是正确的,因为指针可以转换为 bool
类型。但是,这里的想法是什么?
@KenWhite,我该怎么做?
【参考方案1】:
停止!立即切换到std::string
。
这将修复您的代码,并根据要求更清晰/简洁。
【讨论】:
好吧,如果问题确实在于 OP 缺乏对引用和值语义的理解(在传递参数时),那么切换到std::string
本身并不能解决太多问题。它可能会阻止崩溃,但不会使代码按预期工作。【参考方案2】:
通过 char *& 传递参数将解决问题。
#include <stdio.h>
#include <string.h>
void reassgnReference( char * &ba, char * &num );
void reassgnPointerToPointer( char ** ba, char ** num );
int main( int argc, char ** argv )
if ( argc > 4 )
char * ba = new char[strlen( argv[ 4 ] ) + 1];
char * num = new char[strlen( argv[ 2 ] ) + 1];
strncpy( ba, argv[ 4 ], strlen( argv[ 4 ] ) );
strncpy( num, argv[ 2 ], strlen( argv[ 2 ] ) );
printf( "In the beginning, ba = %s, num = %s\n", ba, num );
reassgnReference( ba, num );
printf( "reassgnReference(), ba = %s, num = %s\n", ba, num );
reassgnPointerToPointer( &ba, &num );
printf( "reassgnPointerToPointer(), ba = %s, num = %s\n", ba, num );
else
printf( "%s Expects at least 4 arguments\n", argv[ 0 ] );
return( 0 );
void reassgnReference( char *& ba, char *& num )
delete[] ba;
delete[] num;
char const * const newBa = "ba from reference";
char const * const newNum = "num from reference";
ba = new char[strlen( newBa ) + 1];
num = new char[strlen( newNum ) + 1];
strncpy( ba, newBa, strlen( newBa ) );
strncpy( num, newNum, strlen( newNum ) );
void reassgnPointerToPointer( char ** ba, char ** num )
delete[] *ba;
delete[] *num;
char const * const newBa = "ba from pointer to pointer";
char const * const newNum = "num from pointer to pointer";
*ba = new char[strlen( newBa ) + 1];
*num = new char[strlen( newNum ) + 1];
strncpy( *ba, newBa, strlen( newBa ) );
strncpy( *num, newNum, strlen( newNum ) );
【讨论】:
我们将不胜感激,如果这样更容易,可以链接到一些文档/示例。 虽然我真的不知道为什么会更好,但它并没有解决任何改变。我所做的研究表明,如果我通过引用传递,我无法重新分配它,这就是我想要做的。 我添加了如何使用指针引用和指针指针的示例。他们都工作。您不能重新分配引用,但您可以重新分配引用的值,这就是在 reassgnReference() 中发生的事情。 好吧,我不太确定最终是什么解决了这个问题,但是有一个清晰的例子说明两种方式都可以传递我的 char* 真的很有帮助。非常感谢!【参考方案3】:如果看起来您的 getNew
函数可以重新分配本地 ba
和 num
指向的内存,即 delete[]
它和 new[]
它再次。
但是ba
和num
在调用者中,在convert
中呢?另外,main
中的 ba
和 num
呢?它们按值传递给getNew
,这意味着它们保持不变。它们继续指向它们原来的(现在已经死掉的)内存位置。我猜你会继续在convert
和main
中使用那些现在毫无意义的ba
和num
值,直到它们导致崩溃。例如,如果您再次使用这些旧指针值调用 getNew
,getNew
可能会在 delete[]
处失败。
此外,目前尚不清楚error
在convert
中是什么。当getNew
实际上需要bool
参数时,为什么要将它作为&error
(可能是指针)传递?它会编译,但无论如何它看起来像一个问题。
【讨论】:
很好地抓住了&error
的东西,如果某处出现错误,我将它用作验证函数中的标志。不过我的理解是,通过发送 char* 我并没有发送值,而是将指针传递给该值,这意味着一旦在一个位置发生更改,它在所有位置都会发生更改。不是这样吗?如果不是这种情况,我需要做什么才能做到这一点?
@dlkulp:嗯,是的,通过传递char *
指针,您可以更改指向的值,它会“随处更改”。但是如果你改变指针本身,它不会“到处改变”。如果您想更改被调用者中的 char *
指针,然后在调用者中看到该更改,则通过相同的逻辑,您必须基本上传递一个指向指针的指针(char **
)。或者在 C++ 中,您可以使用 reference-to-pointer 来实现相同的效果。对指针的引用声明为char *&
。
但是char *&
不能更改,对吧?所以我希望char **
在这种情况下允许我更改指针指向的位置?以上是关于C++ 无法删除 char*,不断损坏堆的主要内容,如果未能解决你的问题,请参考以下文章