【问题标题】:CStrings and pointers: Heap corruption when trying to delete a character arrayCStrings 和指针:尝试删除字符数组时堆损坏
【发布时间】:2015-08-14 06:22:06
【问题描述】:

我已经筋疲力尽地在谷歌上搜索了这个,但我无法找到明确的答案或帮助自己理解出了什么问题。作为家庭作业的一部分,我正在尝试为字符数组(即 CString)动态分配内存并分配一个 char 指针变量指向它,然后在结束程序之前删除分配的内存。我只是把头绕在指针上,所以我怀疑我对幕后发生的事情的一些理解是不正确的,我最终会使用 Visual Studio 2010 给我堆损坏断点。

这是我正在尝试做的事情的简化版本(我的 cmets 表明我认为我正在做的事情):

char *chPtr = new char[10]; // Create a char pointer type variable, and point it at the memory allocated for a char array of length 10
chPtr = "September";        // Assign 9 characters (+1 null terminator character) to the char array
cout << chPtr;              // Prints "September", then finds the null terminator and stops printing
delete [] chPtr;            // THIS is what causes my heap corruption -> But I don't know why. Shouldn't this delete the array of memory that chPtr is pointing at?
  • 我也尝试过使用delete chPtr,但堆损坏结果相同。
  • 我尝试手动将空终止符分配给数组 chPtr[9] = '\0'; 的末尾,但这也会导致堆损坏。为什么?当我执行cout &lt;&lt; chPtr[7]; 等操作时,我可以从数组中访问单个字符而不会出现任何问题...

真正令人困惑的是,这可以正常工作:

char *chPtr = new char[10]; // As above, create a char pointer type and point it at the memory allocated for a char array of length 10
delete chPtr;               // This doesn't give any error!

似乎通过分配一个值来初始化数组对我来说是一种破坏。

谁能帮帮我?

【问题讨论】:

    标签: c++ arrays pointers c-strings


    【解决方案1】:

    您正在尝试删除“September”所在的内存块,并且它肯定没有在堆中分配,如果您需要初始化预分配的缓冲区,请使用 strcpy(..) 函数。

    【讨论】:

    • 没有 "heap",就 C++ 而言(至少不是您使用它的方式)。您可能指的是"free store"。
    【解决方案2】:

    这是你问题的根源:

    char *chPtr = new char[10]; // Create a char pointer type variable, and point it at the memory allocated for a char array of length 10
    chPtr = "September";  
    

    首先你在 chPtr 上分配一个堆内存,然后分配一个非堆内存(数据段内存,如果准确的话),分配非堆字符数组,其值为“september”。

    你尝试删除非堆内存,然后你得到你得到的错误。

    使用 strcpy(chPtr,"September") 甚至更好:丢掉 C 并使用 std::string。

    【讨论】:

    • 啊,这是有道理的。为了帮助我完全理解这一点,我将如何在不使用 strcpy() 的情况下将文字(即“September”)分配到new 分配的内存中?
    • C++ 对堆、非堆和数据段一无所知。 "September" 不是“临时字符串”。这不是分配字符串,而是指向字符数组的指针。
    • 您不能真正在 C 或 C 类代码上执行此操作,因为 new char[] 分配了一系列字节而没有真正为它们分配任何值。一个字节数组没有可以处理的构造函数,它只是一块内存。您必须使用一些内存复制功能,例如strcpy 或memcpy。但是,您可以在堆上创建std::string 并通过new std::string("September") 为其分配一个文字。这就是说,std::string 已经将其内部缓冲区保留在堆上,因此实际上不需要创建基于堆的 std::string
    • @isanae 我接受你的评论,我修改了我的答案。
    • 我明白了。因此,要在不使用strcpy 的情况下为new 分配的内存分配值,我需要(例如)创建一个函数,该函数按索引(即按内存地址的内存地址)循环遍历我的数组索引并手动分配每个字符?
    【解决方案3】:

    分配chPtr = "September"; 没有做你认为它做的事情。它将静态字符数组"September" 的地址 分配给变量chPtr。当您尝试对其调用 operator delete[] 时,出现问题:您正在尝试删除一个静态分配的字符数组。

    如果你想复制个字符,你必须使用像std::strcpy这样的字符串复制功能。

    当然,在 C++ 中使用 C 风格字符串的正确方法是不使用 C 风格字符串。使用标准 C++ std::basic_string 模板之一。

    【讨论】:

      【解决方案4】:

      chPtr = "September"; 更改chPtr 指向的位置。它不再指向分配了 10 个 chars 的数组的任何位置,而是指向静态字符数组“September”。然后您尝试删除它,但失败了。

      作为测试,你可以试试这个:

      char* p = nullptr;
      std::cout << static_cast<void*>(p) << "\n";
      
      p = new char[10];
      std::cout << static_cast<void*>(p) << "\n";
      
      p = "September";
      std::cout << static_cast<void*>(p) << "\n";
      

      可能的输出是:

      00000000
      0068C988
      00D18B34
      

      您可以看到p 指向的地址在每次分配时都会发生变化。在空闲存储区 (0068C988) 上分配的块在第三次分配时丢失。

      如果要分配字符,请执行以下操作

      std::strcpy(chPtr, "September");
      

      这带有内存管理、数组和指针的所有注意事项。你真正想做的是:

      std::string s = "September";
      std::cout << s;
      

      【讨论】:

        【解决方案5】:

        chPtr = "September" 不会将任何内容分配给chPtr 指向的内存,而是将chPtr 分配给确实保存“September”的其他内存。您无法删除此记忆。

        【讨论】:

        • 你的意思是数据段。 “九月”不在堆栈中
        猜你喜欢
        • 2017-01-18
        • 1970-01-01
        • 2015-10-06
        • 2010-11-20
        • 1970-01-01
        • 2011-05-12
        • 1970-01-01
        • 2013-06-04
        • 2019-08-28
        相关资源
        最近更新 更多