分配给“char* x = new char[32]”的内存过多

Too much Memory is Allocated to `char* x = new char[32]`

本文关键字:char 内存 new 分配      更新时间:2023-10-16
#include <iostream>
using namespace std;
struct my_chunk
{
    int size;
    char* data;
};
my_chunk* make_chunk()
{
    my_chunk* new_chunk = new my_chunk;
    new_chunk->size = 32;
    new_chunk->data = new char[32];
    new_chunk->data[0] = 'h';
    new_chunk->data[1] = 'e';
    new_chunk->data[2] = 'l';
    new_chunk->data[3] = 'l';
    new_chunk->data[4] = 'o';
    new_chunk->data[5] = '5';
    new_chunk->data[5] = 'h';
    new_chunk->data[6] = 'e';
    new_chunk->data[7] = 'l';
    new_chunk->data[8] = 'l';
    new_chunk->data[9] = 'o';
    new_chunk->data[10] = 'h';
    new_chunk->data[11] = 'e';
    new_chunk->data[12] = 'l';
    new_chunk->data[13] = 'l';
    new_chunk->data[14] = 'o';
    new_chunk->data[15] = 'h';
    new_chunk->data[16] = 'e';
    new_chunk->data[17] = 'l';
    new_chunk->data[18] = 'l';
    new_chunk->data[19] = 'o';
    new_chunk->data[20] = 'h';
    new_chunk->data[21] = 'e';
    new_chunk->data[22] = 'l';
    new_chunk->data[23] = 'l';
    new_chunk->data[24] = 'o';
    new_chunk->data[25] = 'h';
    new_chunk->data[26] = 'e';
    new_chunk->data[27] = 'l';
    new_chunk->data[28] = 'l';
    new_chunk->data[29] = 'h';
    new_chunk->data[30] = 'e';
    new_chunk->data[31] = 'l';
    return new_chunk;
}
void main()
{
    my_chunk* same_chunk;
    same_chunk = make_chunk();
    std::cout << same_chunk->data;
    std::cout << std::endl;
    system("pause");
}

这就是我编译的简单代码。无论我调整char* data的大小如何,它都会添加某种形式的填充。这似乎不是对齐问题,也许我在这一点上是错误的。

我所知道的是,当我调整char* data = new char[size]大小时,我可以轻松访问元素[size]之外的内容。我可以超越并设置这些元素的事实向我表明发生了一个巨大的问题。为了澄清,这意味着在上面的代码中,我可以添加一行new_chunk->data[38] = 'x'没有任何错误、崩溃或任何内容。我已经测试过了,它工作正常。

这不是一个大问题,因为我有足够的内存来容纳我的数据。唯一的问题是我不明白为什么会发生这种情况,并且更愿意修复它。

这也是我的程序的输出:

hellohellohellohellohellohellhel²²²²½½½½½½½½¯■¯■
Press any key to continue . . .

编辑:

这已经爆发了有用的见解,也许我可以再得到一点与这一切相关的帮助。为什么 Visual Studio 2013 显示超出其长度的字符*?它显示"hellohellohellohellhell²²²²²1/21/21/21/21/21/21/21/2 ̄■ ̄■",这向我暗示它分配了太多内存。作为旁注,输出始终相同(到目前为止)。这是我调试时,查看变量,它准确地显示了输出的内容。

char*需要一个尾随''才能由std::cout正确打印。所以这条行std::cout << same_chunk->data;将在内存中迭代,直到找到一个零......

这可能会导致崩溃,打印垃圾,...

顺便说一下,C++中没有对指针访问进行边界检查,因此每当您编写data[X]程序时,请尝试转到一个data元素大小的 data + X 倍的地址(此处为 char)。

如果你想要绑定访问(并且你想要它),请使用std::string(整齐的字符)或std::vector(整齐的任何东西)。

下面是基于较低级别视图的另一个视角:

当你调用new(或malloc)时,库(libc?)将从操作系统请求一些内存。此内存最有可能是页面形式(即 4K、2M 等字节大)。根据库用于管理动态内存的算法,可能会发生以下几件事:

  1. 你的 data[] 指针恰好位于此页面的后边缘,并且您遇到页面错误(程序崩溃、预期行为)

  2. 更有可能的是,库在页面中间为您分配了一些空间。由于C++不执行边界检查(由其他人回答),因此它将此 data* 指针视为指向内存中字节列表的指针。由于分配给堆的空间粒度相当大,因此您可以访问具有垃圾值(即未初始化值)的映射页面(即没有程序崩溃)。

另外,需要注意的另一件事是,当您请求一个 32 字节长的内存块时,没有什么可以指示您得到一个正 32 字节长的内存块。 new[] 可能会为您提供一个 1024 字节长或 400000 字节长的区域。唯一的保证是它至少有 32 个字节长。因此,这是程序不会崩溃的另一个原因(尽管不是主要原因)。

C++并没有

真正检查以确保数组索引在为数组分配的初始内存块内。当你访问"额外"内存时,你基本上只是访问一些不相关的内存并将其转换为一个角色。它不是作为数组的一部分分配的,只是像是一样可访问。为这些随机内存位置分配值只是随机覆盖内存......坏主意。

C 和 C++ 不进行边界检查。所以基本上你只是很幸运,当你访问一个超过你分配的内存边界的位置时,你没有出现段错误。

[38] 表示法基本上表示移动到数据的等效地址 + 38 * sizeof(char *)。因此,如果这个空间被标记为毒药,你就不走运了。