我有一段代码:
#include<iostream>
using namespace std;
int main()
{
char * str = new char;
cin >> str;
cout << str;
delete str;
}
VS
#include<iostream>
using namespace std;
int main()
{
char * str = new char[30];
cin >> str;
cout << str;
delete []str;
}
当我使用STDIN向任一程序提供输入时,哪个程序确保没有内存泄漏?
这种怀疑产生了,因为我们的教授告诉我们,char *基本上只相当于一系列字符。因此,如果我像第一种情况那样分配堆内存并让str&#39; hold&#39;一个字符数组,如果我然后删除str,它是否完全删除了数组?我知道第二种情况是这样做的。
我已经完成了 - &gt;
delete vs delete[] operators in C++
因此我知道delete []删除new []分配的内存,delete对new执行相同的操作。但是如果new本身分配连续的内存位置呢?
答案 0 :(得分:2)
您的两个第一个代码示例都是错误的。
char * str = new char;
cin >> str;
您只为单个字符分配了内存。如果您读取空字符串以外的任何内容,您将写入未分配的内存并且将具有未定义的行为。
如果我然后删除str,它是否完全删除了数组?
它只会删除您分配的一个字符。您在未分配的内存中写入的其余字符串不会受delete
的直接影响。这不是内存泄漏,而是内存损坏。
VS
char * str = new char[];
这不是合法的c ++。必须指定数组大小。
编辑:修复后,只要您读取29个字符或更短的字符串,第二个代码就是正确的。如果你读了一个更长的字符串,你将再次得到未定义的行为。
但是如果new本身分配连续的内存位置怎么办?
没有。 new
(与new[]
相对)只分配和构造一个对象。而delete
只会破坏和释放一个对象。
TLDR两个程序都没有内存泄漏,但第一个程序由于内存损坏而具有未定义的行为。
答案 1 :(得分: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[]
。您没有指向该指针的变量。这是内存泄漏。
让我们考虑在某个地方有一些可以给我们大块记忆的桶。我们可以通过new
和new[]
从该存储桶中获取大块内存。当我们使用delete
和delete[]
时,我们会将这些内存块返回到存储桶中。
我们与new
和delete
达成的协议是,一旦我们在一块内存上调用delete
,我们就不会继续使用它。我们不这样做,因为系统可能会重用那段内存,或者它可能已经删除了所有一起访问该指针的能力。
你有这段代码:
char *x = new char;
cin >> x;
我想告诉你它与这段代码基本相同:
char y;
cin >> &y;
在这两种情况下,您只为一个字符分配了空间。因此,当我们在delete
上调用x
时,我们只会删除一个字符。那里可能会破坏的代码部分是cin
会认为有足够的内存分配给它将尝试写入该指针的任何字符串。
事实是,可能没有足够的空间。只有一个char的空间。甚至字符串"a"
也会占用2个字符。
答案 2 :(得分:0)
你不能做这些事情。 char * ptr = new char; 表示您已分配sizeof(char)字节。 如果您将执行cin&gt;&gt; ptr,并传递超过1个字符,你将得到段错误,因为没有分配内存。
要分配一组字符,您需要以下一种方式进行: char * ptr = new char [size]; 它将分配size * sizeof(char)字节。 然后你可以使用cin&gt;&gt; ptr用数据填充它。