为什么我在堆和堆栈上分配的数组之间看到不同的行为?

Jos*_* M. 4 c++ arrays memory-management

我正在检查C++中两个2D数组的行为,一个是从堆栈中分配的,另一个是从堆中分配的.

我创建了两个相同形状的2D数组,并用一些数据填充这些数组.然后我尝试用两种不同的方法读取数组,第一种方法是使用简单的数组索引格式"Arr [ROW] [COLUMN]".然后我使用指针取消引用读取数组,我得到堆分配数组的两个不同结果,但堆栈分配数组的结果相同.我试图理解为什么结果不同.如果有人能提供任何澄清,我将不胜感激.提前致谢.

我正在运行的代码如下:

#include <iostream>

using namespace std;

int main(){

    int rows = 6;
    int columns = 3;

    // allocate from the stack.
    double q[rows][columns];

    // allocate from the heap.
    double ** a;
    a = new double*[rows];

    for(int i = 0; i < rows; ++i){
        a[i] = new double[columns];
    }

    // populate the arrays.
    for(int i = 0; i < rows; ++i){
        for(int j = 0; j < columns; ++j){
            a[i][j] = columns*i+j;
            q[i][j] = columns*i+j;
        }
    }

    cout << "*****************" << endl;
    cout << "Array indexing method." << endl;
    cout << "*****************" << endl;

    // print the heap allocated array using array indexing.
    for(int i = 0; i < rows; ++i){
        for(int j = 0; j < columns; ++j){
            cout << a[i][j] << '\t';
        }
        cout << endl;
    }

    cout << "*****************" << endl;

    // print the stack allocated array using array indexing.
    for(int i = 0; i < rows; ++i){
        for(int j = 0; j < columns; ++j){
            cout << q[i][j] << '\t';
        }
        cout << endl;
    }

    cout << "*****************" << endl;
    cout << "Pointer dereferencing method." << endl;
    cout << "*****************" << endl;

    // print the heap allocated array.
    for(int i = 0; i < rows; ++i){
        for(int j = 0; j < columns; ++j){
            cout << *(&a[0][0] + columns*i + j) << '\t';
        }
        cout << endl;
    }

    cout << "*****************" << endl;

    // print the stack allocated array.
    for(int i = 0; i < rows; ++i){
        for(int j = 0; j < columns; ++j){
            cout << *(&q[0][0] + columns*i + j) << '\t';
        }
        cout << endl;
    }
    cout << "*****************" << endl;

    // release the memory allocated to the heap.
    for(int i = 0; i < rows; ++i){
        delete[] a[i];
    }

    delete a;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我得到的结果是:

*****************
Array indexing method.
*****************
0       1       2
3       4       5
6       7       8
9       10      11
12      13      14
15      16      17
*****************
0       1       2
3       4       5
6       7       8
9       10      11
12      13      14
15      16      17
*****************
Pointer dereferencing method.
*****************
0       1       2
0       3       4
5       0       6
7       8       0
9       10      11
0       12      13
*****************
0       1       2
3       4       5
6       7       8
9       10      11
12      13      14
15      16      17
*****************
Run Code Online (Sandbox Code Playgroud)

我可以看到,在第三个输出块中,堆分配的数组没有被正确读取,但堆栈分配的数组是.

再次感谢.

use*_*670 11

&q[0][0]为您提供指向包含rowsx columns双精度的块中第一个双精度的指针.虽然&a[0][0]给你一个指针,包含columns双打的块中的第一个双精度(你已经使用它分配了a[0] = new double[columns];,记得吗?).因此访问它将columns*i + j超出界限并将触发未定义的行为.

  • 啊,所以我的问题是我假设堆中的分配是连续的,但事实上并非如此?据推测,每一列的列都非常接近其他列,因为在我的输出中,我得到了一些适当的值,而不是它们应该在哪里. (3认同)
  • @JoshM.您的堆分配根本不是连续的.你将1个包含`rows`指针数的块分配给double,然后将`rows`计数包含`columns`计数,每个包含双精度数.虽然在这种特殊情况下它们是一个接一个地分配(在它们之间有一些填充)是有道理的,因为堆还没有混乱.但是,人们不应该依赖这种关于分配器行为的假设. (2认同)