在 C++ 中针对 char * 正确使用 delete 与 delete[ ]
Proper use of delete vs delete[ ] with respect to char * in C++
我有一段代码:
#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 * 基本上等同于一个 char 数组。因此,如果我像第一种情况一样分配堆内存并让 str 'hold' 一个字符数组,如果我然后删除 str,它会完全删除数组吗?我知道第二种情况成功了。
我已经通过了->
delete vs delete[] operators in C++
delete vs delete[]
因此我知道 delete[] 删除由 new[] 分配的内存并且 delete 对 new 执行相同的操作。但是,如果 new 本身分配了连续的内存位置怎么办??
你的两个第一个代码示例都是错误的。
char * str = new char;
cin >> str;
您只为单个字符分配了内存。如果您读取除空字符串以外的任何内容,您将写入未分配的内存并具有未定义的行为。
if I then delete str, does it delete the array completely?
它只会删除您分配的一个字符。您在未分配内存中写入的其余字符串不会直接受到 delete
的影响。这不是内存泄漏,这是内存损坏。
对比
char * str = new char[];
这不是合法的 c++。必须指定数组大小。
编辑:修复后,只要您读取的字符串不超过 29 个字符,第二个代码就是正确的。如果您读取更长的字符串,您将再次遇到未定义的行为。
But what if new itself allocates contiguous memory locations?
没有。 new
(相对于 new[]
)分配并构造一个对象。并且 delete
只销毁并释放一个对象。
TLDR 这两个程序都没有内存泄漏,但第一个程序由于内存损坏而出现未定义的行为。
你不能做这样的事情。
字符 *ptr = 新字符;
意味着你已经分配了 sizeof(char) 字节。
如果你将执行 cin >> ptr,并向那里传递超过 1 个字符,你将得到段错误,因为内存未分配。
要分配一个字符数组,您需要按以下方式进行:
char *ptr = new char[大小];
它将分配 size * sizeof(char) 字节。
然后你可以使用 cin >> ptr 来填充数据。
我相信您误解了内存泄漏和缓冲区溢出之间的区别。
什么是缓冲区溢出?
当我们有一些内存要存储一些数据时,就会发生缓冲区溢出。当我们存储该数据时,我们会在其中放置太多数据。例如:
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] = '[=11=]';
x = new char[10]; // <-- Memory Leak!
此时在代码中,您无法在第一次分配时调用 delete[]
。您没有指向该指针的变量。那是 内存泄漏。
删除[]有什么作用?
让我们考虑在某个地方有一些桶可以给我们提供内存块。我们可以通过 new
和 new[]
从那个桶中获取内存块。当我们使用 delete
和 delete[]
时,我们 return 将那些内存块放回桶中。
我们和new
和delete
约定的是,一旦我们对一块内存调用delete
,我们就不再继续使用它。我们不这样做,因为系统可能会重用那块内存,或者它可能已经完全移除了访问该指针的所有能力。
这怎么可能行得通?
你有这段代码:
char *x = new char;
cin >> x;
我想告诉你,它与这段代码基本相同:
char y;
cin >> &y;
在这两种情况下,您只为 一个 个字符分配了 space。因此,当我们在 x
上调用 delete
时,我们只会删除一个字符。那里的代码可能会中断的部分是 cin
会认为有足够的内存分配给它要尝试写入该指针的任何字符串。
事实是,可能还不够 space。一个字符只有 space。甚至字符串 "a"
也占用 2 个字符。
我有一段代码:
#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 * 基本上等同于一个 char 数组。因此,如果我像第一种情况一样分配堆内存并让 str 'hold' 一个字符数组,如果我然后删除 str,它会完全删除数组吗?我知道第二种情况成功了。
我已经通过了->
delete vs delete[] operators in C++
delete vs delete[]
因此我知道 delete[] 删除由 new[] 分配的内存并且 delete 对 new 执行相同的操作。但是,如果 new 本身分配了连续的内存位置怎么办??
你的两个第一个代码示例都是错误的。
char * str = new char;
cin >> str;
您只为单个字符分配了内存。如果您读取除空字符串以外的任何内容,您将写入未分配的内存并具有未定义的行为。
if I then delete str, does it delete the array completely?
它只会删除您分配的一个字符。您在未分配内存中写入的其余字符串不会直接受到 delete
的影响。这不是内存泄漏,这是内存损坏。
对比
char * str = new char[];
这不是合法的 c++。必须指定数组大小。
编辑:修复后,只要您读取的字符串不超过 29 个字符,第二个代码就是正确的。如果您读取更长的字符串,您将再次遇到未定义的行为。
But what if new itself allocates contiguous memory locations?
没有。 new
(相对于 new[]
)分配并构造一个对象。并且 delete
只销毁并释放一个对象。
TLDR 这两个程序都没有内存泄漏,但第一个程序由于内存损坏而出现未定义的行为。
你不能做这样的事情。 字符 *ptr = 新字符; 意味着你已经分配了 sizeof(char) 字节。 如果你将执行 cin >> ptr,并向那里传递超过 1 个字符,你将得到段错误,因为内存未分配。
要分配一个字符数组,您需要按以下方式进行: char *ptr = new char[大小]; 它将分配 size * sizeof(char) 字节。 然后你可以使用 cin >> ptr 来填充数据。
我相信您误解了内存泄漏和缓冲区溢出之间的区别。
什么是缓冲区溢出?
当我们有一些内存要存储一些数据时,就会发生缓冲区溢出。当我们存储该数据时,我们会在其中放置太多数据。例如:
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] = '[=11=]';
x = new char[10]; // <-- Memory Leak!
此时在代码中,您无法在第一次分配时调用 delete[]
。您没有指向该指针的变量。那是 内存泄漏。
删除[]有什么作用?
让我们考虑在某个地方有一些桶可以给我们提供内存块。我们可以通过 new
和 new[]
从那个桶中获取内存块。当我们使用 delete
和 delete[]
时,我们 return 将那些内存块放回桶中。
我们和new
和delete
约定的是,一旦我们对一块内存调用delete
,我们就不再继续使用它。我们不这样做,因为系统可能会重用那块内存,或者它可能已经完全移除了访问该指针的所有能力。
这怎么可能行得通?
你有这段代码:
char *x = new char;
cin >> x;
我想告诉你,它与这段代码基本相同:
char y;
cin >> &y;
在这两种情况下,您只为 一个 个字符分配了 space。因此,当我们在 x
上调用 delete
时,我们只会删除一个字符。那里的代码可能会中断的部分是 cin
会认为有足够的内存分配给它要尝试写入该指针的任何字符串。
事实是,可能还不够 space。一个字符只有 space。甚至字符串 "a"
也占用 2 个字符。