微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么 C++ 中的可变长度数组在某些大小上重叠?

如何解决为什么 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++ 标准,此时编译器所做的一切都是正确的。 (无论发生什么,编译器都会责怪你的代码。)当size9 时,编译器使用left[0] 作为right[4] 的位置。

在幕后,leftright 数组在内存中可能或多或少相邻。布局将有 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 是奇数且 sizesize/2 的倍数时,您应该会看到这种行为;也就是说,4 是 8 的倍数的 1,如 9、17、25、33 等。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。