为什么这会修复堆损坏?
Why does this fix a heap corruption?
所以我有代码:
float **array = new float*[width + 1]; //old line was '= new float*[width]'
//Create dynamic 2D array
for (int i = 0; i < width; ++i) {
array[i] = new float[height + 1]; //old line was '= new float[height]'
}
//Hardcode 2D array for testing
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
array[i][j] = i + j;
}
}
//deallocate heap memory
for (int i = 0; i < width; ++i) {
delete [] array[i]; //Where corrupted memory error used to be
}
delete [] array;
(郑重声明,我知道分配单个内存块会更有效,但我与永远不会理解 why/how 使用它的科学家密切合作。由于它在服务器上运行,老板们说这是首选。)
我的问题是为什么 height+1/width+1 可以修复损坏的内存问题?我知道额外的 space 用于空终止符,但为什么有必要?以及为什么当高度和宽度相同时它可以工作,但当它们不同时会中断?
索尔恩:
填充数组时我的 height/width 倒退了...... -.-;感谢 NPE。
以下评论是转移注意力的评论:
delete [] array[i]; //Where corrupted memory error used to be
这不是内存错误发生的地方。这是 它被检测到的地方(由 C++ 运行时)。请注意,运行时没有义务检测 this sort of errors,因此在某种程度上它是在帮您一个忙。 :-)
您的代码部分有一个 buffer overrun(可能是循环中的差一错误),但您没有显示。
如果通过检查代码找不到它,请在 GCC 中尝试 Valgrind 或 -fsanitize=address
。
编辑:您添加到问题中的代码存在问题:
//Hardcode 2D array for testing
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
array[i][j] = i + j;
}
}
是它有 width
和 height
(或者,等价地,i
和 j
)的错误方式。除非 width == height
,您的代码有 undefined behaviour.
通过 height+1 和 weight+1 改变身高和体重可能是不够的。
您发布的代码在身高和体重方面是正确的。
这意味着在代码的其他部分中,有些东西可能刚好写在这些数组的末尾,当你增加这些数组时,它会使错误的代码直接写在数组的末尾而不是崩溃.你没有解决问题,你只是隐藏它。
由于 OS 检测堆损坏的方式存在一些限制,代码实际上在删除 [] 时崩溃了。堆上的差一错误通常会在下一次调用 new/delete/malloc/free 时检测到,而不是在它们实际发生时检测到。
如果您想确切知道您的程序何时何地使用指针进行非法操作,您可以使用 Valgrind 等工具。
您没有修复代码。您正在做的是用新代码更改可执行文件,从而将损坏错误转移到程序的另一部分。
有一件事你应该不做——不要把你的程序改成你说的"works" + 1
然后接受它。 我知道如果错误很难诊断,这可能很诱人,但不要走这条路。
你必须做的是回到非工作版本,真正解决问题。通过 "fix",意思是您可以解释修复的作用、修复问题的原因等。
所以我有代码:
float **array = new float*[width + 1]; //old line was '= new float*[width]'
//Create dynamic 2D array
for (int i = 0; i < width; ++i) {
array[i] = new float[height + 1]; //old line was '= new float[height]'
}
//Hardcode 2D array for testing
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
array[i][j] = i + j;
}
}
//deallocate heap memory
for (int i = 0; i < width; ++i) {
delete [] array[i]; //Where corrupted memory error used to be
}
delete [] array;
(郑重声明,我知道分配单个内存块会更有效,但我与永远不会理解 why/how 使用它的科学家密切合作。由于它在服务器上运行,老板们说这是首选。)
我的问题是为什么 height+1/width+1 可以修复损坏的内存问题?我知道额外的 space 用于空终止符,但为什么有必要?以及为什么当高度和宽度相同时它可以工作,但当它们不同时会中断?
索尔恩: 填充数组时我的 height/width 倒退了...... -.-;感谢 NPE。
以下评论是转移注意力的评论:
delete [] array[i]; //Where corrupted memory error used to be
这不是内存错误发生的地方。这是 它被检测到的地方(由 C++ 运行时)。请注意,运行时没有义务检测 this sort of errors,因此在某种程度上它是在帮您一个忙。 :-)
您的代码部分有一个 buffer overrun(可能是循环中的差一错误),但您没有显示。
如果通过检查代码找不到它,请在 GCC 中尝试 Valgrind 或 -fsanitize=address
。
编辑:您添加到问题中的代码存在问题:
//Hardcode 2D array for testing
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
array[i][j] = i + j;
}
}
是它有 width
和 height
(或者,等价地,i
和 j
)的错误方式。除非 width == height
,您的代码有 undefined behaviour.
通过 height+1 和 weight+1 改变身高和体重可能是不够的。 您发布的代码在身高和体重方面是正确的。
这意味着在代码的其他部分中,有些东西可能刚好写在这些数组的末尾,当你增加这些数组时,它会使错误的代码直接写在数组的末尾而不是崩溃.你没有解决问题,你只是隐藏它。
由于 OS 检测堆损坏的方式存在一些限制,代码实际上在删除 [] 时崩溃了。堆上的差一错误通常会在下一次调用 new/delete/malloc/free 时检测到,而不是在它们实际发生时检测到。
如果您想确切知道您的程序何时何地使用指针进行非法操作,您可以使用 Valgrind 等工具。
您没有修复代码。您正在做的是用新代码更改可执行文件,从而将损坏错误转移到程序的另一部分。
有一件事你应该不做——不要把你的程序改成你说的"works" + 1
然后接受它。 我知道如果错误很难诊断,这可能很诱人,但不要走这条路。
你必须做的是回到非工作版本,真正解决问题。通过 "fix",意思是您可以解释修复的作用、修复问题的原因等。