如何解决为什么 C++ 中的可变长度数组在某些大小上重叠?
在此处提供问题的答案后,我正在测试我编辑的 this code 并注意到一些奇怪的行为:
#include <iostream>
#define MAX 100
using namespace std;
int main()
{
int size = 0;
int array[MAX];
int i,j;
int input;
cout << "Array: ";
for(i = 0; i < MAX; i++)
{
cin >> input;
if(input == -1)
break;
else
{
array[i] = input;
size++;
}
}
cout << "Size: " << size << "\n\n";
int left[size / 2];
int right[size / 2];
for(i = 0; i < size / 2; i++)
left[i] = array[i];
for(i = size / 2,j = 0; i < size; i++,j++)
right[j] = array[i];
cout << "Left: ";
for(i = 0; i < size / 2; i++)
cout << left[i] << ' ';
cout << '\n';
cout << "Right: ";
for(i = 0; i < size - size / 2; i++)
cout << right[i] << ' ';
cout << '\n';
return 0;
}
此代码应该将数组拆分为两个单独的数组。不知何故,当这些是输入时,输出是错误的:
1 2 3 4 5 6 7 8 9 -1
Left: 9 2 3 4
Right: 5 6 7 8 9
调试后 如果 left
的元素是这样打印的:
for(i = size / 2,j++)
{
right[j] = array[i];
cout << left[0] << ' ';
}
cout << '\n';
表示在第 5 次迭代后修改了 left[0]
的值:
1 1 1 1 9
Left: 9 2 3 4
Right: 5 6 7 8 9
这仅在数组大小为 9 时发生。我还没有测试超过 16。我可以修复代码,使其具有正确的大小
int right[size - size / 2];
或使用 malloc()
来遵守 C++ 标准,
int *left = (int *) malloc(sizeof(*left) * n / 2);
int *right = (int *) malloc(sizeof(*left) * n / 2);
这样 left
就不会受到影响,但这不是我要问的。为什么只有在拆分大小为 9 的数组时才会发生这种情况?为什么left[0]
被覆盖?这是 g++ 中应该报告的错误还是其他问题?
解决方法
表示在第 5 次迭代后修改了 left[0]
的值:
这就是你的答案。问题发生在对具有四个元素的数组进行第五次迭代时。
当 size
为奇数时,size/2
的计算向下舍入。因此总和 size/2 + size/2
严格小于 size
,但您的循环确保原始数组中的所有 size
元素都分配到某处。必须将某些东西分配到意想不到的位置。我们称这种行为为“未定义行为”,根据 C++ 标准,此时编译器所做的一切都是正确的。 (无论发生什么,编译器都会责怪你的代码。)当size
为9
时,编译器使用left[0]
作为right[4]
的位置。
在幕后,left
和 right
数组在内存中可能或多或少相邻。布局将有 right[0]
到 right[size/2]
,然后可能是一些未使用的空间(也称为“填充”),然后是 left[0]
到 left[size/2]
。当您访问超过 right
的最后一个元素时,您最终会在未使用的空间或 left[0]
中。当您覆盖未使用的空间时,您看不到任何症状,因为该空间在其他情况下未使用。但是,当您覆盖 left[0]
时,您肯定会看到症状。
您的编译器显然使用填充来确保数组与 4*sizeof(int)
对齐。 (那样必须更快,因为编译器很少无缘无故地引入浪费。不过,我很惊讶它不是 2*sizeof(int)
。)也就是说,当 size/2
是 {{ 的倍数时没有填充1}}。如果这种猜测是准确的,那么当 4
是奇数且 size
是 size/2
的倍数时,您应该会看到这种行为;也就是说,4
是 8 的倍数的 1,如 9、17、25、33 等。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。