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调用中对应的参数看起来像&amp;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 函数可以重新分配本地 banum 指向的内存,即 delete[] 它和 new[] 它再次。

但是banum 在调用者中,在convert 中呢?另外,main 中的 banum 呢?它们按值传递给getNew,这意味着它们保持不变。它们继续指向它们原来的(现在已经死掉的)内存位置。我猜你会继续在convertmain 中使用那些现在毫无意义的banum 值,直到它们导致崩溃。例如,如果您再次使用这些旧指针值调用 getNewgetNew 可能会在 delete[] 处失败。

此外,目前尚不清楚errorconvert 中是什么。当getNew 实际上需要bool 参数时,为什么要将它作为&amp;error (可能是指针)传递?它会编译,但无论如何它看起来像一个问题。

【讨论】:

很好地抓住了&amp;error 的东西,如果某处出现错误,我将它用作验证函数中的标志。不过我的理解是,通过发送 char* 我并没有发送值,而是将指针传递给该值,这意味着一旦在一个位置发生更改,它在所有位置都会发生更改。不是这样吗?如果不是这种情况,我需要做什么才能做到这一点? @dlkulp:嗯,是的,通过传递char * 指针,您可以更改指向的值,它会“随处更改”。但是如果你改变指针本身,它不会“到处改变”。如果您想更改被调用者中的 char * 指针,然后在调用者中看到该更改,则通过相同的逻辑,您必须基本上传递一个指向指针的指针(char **)。或者在 C++ 中,您可以使用 reference-to-pointer 来实现相同的效果。对指针的引用声明为char *&amp; 但是char *&amp; 不能更改,对吧?所以我希望char ** 在这种情况下允许我更改指针指向的位置?

以上是关于C++ 无法删除 char*,不断损坏堆的主要内容,如果未能解决你的问题,请参考以下文章

U盘删除文件时提示“文件或目录损坏且无法读取”的解决方法

SVN 存储库不断损坏

删除 wchar_t* 导致堆损坏

Ubuntu WSL上权限损坏的文件,无法删除但可以访问[关闭]

在删除 c ++ 时维护最小堆

电脑上文件无法删除的两个实用技巧