【问题标题】:Proper use of delete vs delete[ ] with respect to char * in C++关于 C++ 中的 char * 正确使用 delete vs delete[ ]
【发布时间】:2015-03-27 14:12:50
【问题描述】:

我有一段代码:

#include<iostream>

using namespace std;

int main()
{
    char * str = new char;

    cin >> str;
    cout << str;

    delete str;
}

对比

#include<iostream>

using namespace std;

int main()
{
    char * str = new char[30];  

    cin >> str;
    cout << str;

    delete []str;
}

当我使用 STDIN 向任一程序提供输入时,哪个程序可以确保没有内存泄漏?

当我们的教授告诉我们一个 char * 基本上等同于一个字符数组时,这个疑问就出现了。因此,如果我像第一种情况一样分配堆内存并让 str“保存”一个字符数组,如果我然后删除 str,它会完全删除数组吗?我知道第二种情况可以做到。

我已经经历过了->

delete vs delete[] operators in C++

delete vs delete[]

因此我知道 delete[] 删除由 new[] 分配的内存,而 delete 对 new 执行相同的操作。但是如果 new 本身分配了连续的内存位置呢?

【问题讨论】:

  • 两个sn-ps的代码都是错误的。:) 尝试编译成你将在你的帖子中使用的代码。
  • 你开始得很好,但是当你得到问题的前提时 “现在,如果我提供一个字符串作为两个代码的输入”,你实际上并没有显示我们你在做什么......
  • “我们的教授告诉我们,一个 char * 基本上等同于一个字符数组”你的教授错了。
  • 我刚刚做到了!它确实在 mac os x 10.9.5 上的 g++ 上编译
  • @Lightness Races in Orbit:对不起,我没有找到你。您能否详细说明我需要提供哪些信息?

标签: c++ arrays string new-operator delete-operator


【解决方案1】:

您的 both 第一个代码示例是错误的。

char * str = new char;  
cin >> str;

您只为单个字符分配了内存。如果您读取空字符串以外的任何内容,您将写入未分配的内存并具有未定义的行为。

如果我再删除str,它会完全删除数组吗?

它只会删除你分配的一个字符。您在未分配内存中写入的其余字符串不会直接受到delete 的影响。这不是内存泄漏,而是内存损坏。

对比

char * str = new char[];

这不是合法的 c++。必须指定数组大小。

编辑:修复后,只要您读取 29 个字符或更短的字符串,第二个代码就是正确的。如果您读取更长的字符串,您将再次获得未定义的行为。

但是如果 new 本身分配了连续的内存位置呢?

它没有。 new(相对于new[])只分配和构造一个对象。而delete 只销毁和释放一个对象。

TLDR 两个程序都没有内存泄漏,但第一个程序由于内存损坏而具有未定义的行为。

【讨论】:

  • 这可能是最糟糕的一种未定义行为:一切似乎都按应有的方式运行。如果可以避免,请不要使用char*。如果可以避免使用newdelete,请不要使用它们。 (在 C++03 中很难做到,但在 C++11 中通常很容易。)
  • 明智的话,@ChristopherCreutzig
【解决方案2】:

我相信您误解了内存泄漏和缓冲区溢出之间的区别。

什么是缓冲区溢出?

当我们有一块内存要存储一些数据时,就会发生缓冲区溢出。当我们存储这些数据时,我们在那里放了太多数据。例如:

int x[4];
x[0] = 7;
x[1] = 8;
x[2] = 9;
x[3] = 10;
x[4] = 11; // <-- Buffer Overflow!

您的代码可能会出现缓冲区溢出,因为cin 不知道您分配了多少内存。当使用char * 参数时,没有真正的方法可以告诉它。所以在你的第一个例子中,如果你写的字符串比空字符串长,你会导致缓冲区溢出。同样,如果您要向第二个示例写入超过 30 个字符(包括空字符),也会导致 缓冲区溢出

什么是内存泄漏?

内存泄漏传统上是这样表示的:

char *x = new char[30];
x[0] = 'a';
x[1] = '\0';
x = new char[10]; // <-- Memory Leak!

此时在代码中,您无法在第一次分配时调用delete[]。您没有指向该指针的变量。那是内存泄漏

delete[] 有什么作用?

让我们考虑在某个地方有一些桶可以给我们大量的内存。我们可以通过newnew[] 从该桶中获取内存块。当我们使用deletedelete[] 时,我们会将这些内存块返回到存储桶中。

我们与newdelete 达成的协议是,一旦我们在一块内存上调用delete,我们就不会继续使用它。我们不这样做,因为系统可能会重用那块内存,或者它可能已经删除了所有访问该指针的能力。

这怎么可能行得通?

你有这段代码:

char *x = new char;
cin >> x;

我想告诉你,它与这段代码基本相同:

char y;
cin >> &y;

在这两种情况下,您只为 一个 字符分配了空间。所以当我们在x 上调用delete 时,我们只删除了一个字符。那里可能会中断的代码部分是cin 将认为有足够的内存分配给它将尝试写入该指针的任何字符串。

事实上,可能没有足够的空间。一个字符只有一个空间。甚至字符串"a",也占用了2个字符。

【讨论】:

  • 要么这是真的很好的通灵作品,要么你回答了其他问题而不是这个问题。老实说,我不知道是哪个!祝你好运
  • @LightnessRacesinOrbit:我在问题中使用了这个语句:“现在,如果我提供一个字符串作为两个代码的输入,哪一个可以确保没有内存泄漏?”
  • 您是如何理解“提供字符串作为输入”的含义的?我还没有管理它:(提供如何?作为what的输入?(并且不要说“代码”!)
  • @LightnessRacesinOrbit:嗯,代码通过cin.. 接受用户输入。他试图将其存储为c-string..这对我来说似乎一点也不困惑..
  • 好的,输入到 STDIN。他可能一直在谈论初始化char 数组或bloomin' 任何东西。他暗示他在两个给定示例中没有提供字符串的事实(使用“Now”一词似乎在它们之后引入了代码更改)使我走错了方向。他现在已经澄清了。没关系:)
【解决方案3】:

你不能做这样的事情。 字符 *ptr = 新字符; 表示您已分配 sizeof(char) 字节。 如果你执行 cin >> ptr,并传递超过 1 个字符,你会得到段错误,因为内存没有分配。

要分配一个字符数组,您需要按以下方式进行: 字符 *ptr = 新字符 [ 大小 ]; 它将分配 size * sizeof(char) 字节。 然后你可以使用 cin >> ptr 来填充数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-11
    • 2012-10-26
    • 2011-04-07
    • 1970-01-01
    • 2020-09-27
    • 2012-02-21
    • 2021-12-20
    相关资源
    最近更新 更多