#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会显示超出其长度的char *?它显示了“hellohellohellohellohellohellhel²²²²½½½½½½½■■”这对我来说是在分配太多的内存。作为旁注,输出始终相同(到目前为止)。这是我调试时,查看变量,它显示输出的确切内容。
答案 0 :(得分:3)
char*
需要'\0'
正确打印std::cout
。所以这一行std::cout << same_chunk->data;
将在内存中迭代,直到找到零...
这会导致崩溃,打印垃圾......
顺便说一下,在C ++中没有对指针访问进行绑定检查,所以无论何时编写data[X]
,程序都会尝试对data
+ X时间进行大约data
的大小调整。元素(这里是char)。
如果你想要绑定访问(并且你想要它),可以使用std::string
(字符整齐)或std::vector
(任何东西都很整洁)。
答案 1 :(得分:2)
C ++并没有真正检查以确保数组索引位于为该数组分配的初始内存块中。当您访问“额外”内存时,您基本上只是访问一些不相关的内存并将其作为一个字符进行转换。它不是作为数组的一部分进行分配,只是可访问就像它一样。将值分配给那些随机存储器位置只是随机覆盖内存......不好的想法。
答案 2 :(得分:2)
以下是基于较低级别视图的另一个视角:
当您调用new(或malloc)时,库(libc?)将从OS请求一些内存。此内存最有可能是页面形式(即4K,2M等大字节)。根据库用于管理动态内存的算法,可能会发生以下几种情况:
您的数据[]指针恰好位于此页面的后边缘,并且您收到页面错误(程序崩溃,预期的行为)
更有可能的是,图书馆在页面中间为您分配了一些空间。由于C ++不进行边界检查(由其他人回答),因此它将此数据*指针视为指向内存中字节列表的指针。由于分配给堆的空间的粒度相当大,因此您可以访问具有垃圾值的映射页(即没有程序崩溃)(即未初始化的值)。
另外需要注意的是,当你请求一个32字节长的内存块时,没有任何内容可以指示你得到一个完全 32字节长的内存块。 new []可能会给你一个1024字节长或400000字节长的区域。唯一的保证是至少 32字节长。因此,这是您的程序不会崩溃的另一个原因(尽管不是主要原因)。
答案 3 :(得分:1)
C和C ++不进行边界检查。所以基本上你很幸运,当你访问超出你分配的内存范围的位置时,你没有得到段错误。
[38]符号基本上表示移动到数据的等效地址+ 38 * sizeof(char *)。因此,如果这个空间被标记为毒药,那你就不幸了。