C ++ 3d数组 - 在一行中对齐的动态内存分配

时间:2011-11-06 15:12:11

标签: c++ c arrays memory allocation

我有一个非常奇怪的问题,可能没有实际用途,但答案困扰了我很多。我今天试着用数组和它们如何使用这段代码在内存中分配:(编译器Xcode 4顺便说一句,4字节整数)

int ***c;
int size_x = 0;
int size_y = 0;
int size_z = 0;

cout << "Enter x: " << endl;
cin >> size_x;
cout << "Enter y: " << endl;
cin >> size_y;
cout << "Enter z: " << endl;
cin >> size_z;

c = new int**[size_x];
for (int i = 0; i < size_x; ++i) {
    *(c+i) = new int*[size_y];
    for (int j = 0; j < size_y; ++j) {
        *(*(c+i)+j) = new int[size_z];
    }
}

for (int i = 0; i < size_x; ++i) {
    for (int j = 0; j < size_y; ++j) {
        for (int k = 0; k < size_z; ++k) {
            cout << (*(*(c+i)+j)+k) << endl;
            //cout << &c[i][j][k] << endl;
        }
    }
}

delete [] c;

当我立即进入时:3,2和4我在控制台中获得以下输出:

0x100100a60 0x100100a64 0x100100a68 0x100100a6c 0x100100a70 0x100100a74 0x100100a78 0x100100a7c 0x100100a90 0x100100a94 0x100100a98 0x100100a9c 0x100100aa0 0x100100aa4 0x100100aa8 0x100100aac 0x100100ac0 0x100100ac4 0x100100ac8 0x100100acc 0x100100ad0 0x100100ad4 0x100100ad8 0x100100adc

现在我的问题是,如果我们看一下输出,比我们看到的那样,大多数情况下,内存每4个字节对齐一次,但有时我们看到更大的步骤,如从0x100100a7c到 0x100100a90。

这是正常的,我该如何防止这种情况?为什么是这样?是否有可能强制c将我的记忆与常量线对齐? (我不是原生英语,所以很抱歉,但我不知道怎么说更好)

仅用于一般理解: - )

谢谢你!

P.S。是否足以使用删除[]一次btw或我必须通过3个内存块中的每一个并删除[]那里整个数组?编辑:

我现在就像这样删除内存并且效果很好:

cout << "Free Memory" << endl;

for (int i = 0; i < m_sx; ++i) {
    for (int j = 0; j < m_sy; ++j) {
        delete [] m_array[i][j];
        //delete [] (*(*(m_array)+j)+k);
    }
    delete [] m_array[i];
}

delete [] m_array, m_array = NULL;

5 个答案:

答案 0 :(得分:6)

是的,这很正常。内存对齐,顺便说一句,它只是连续,因为对new的后续调用不能保证。是的,您可以在一个连续的缓冲区中分配整个3-d数组:

int *A = new int[size_x * size_y * size_z];

或更安全

std::vector<int> A(size_x * size_y * size_z);

然后用

索引它
int element = A[i * size_z * size_y + j * size_z + k]

将元素设为(i,j,k)

事实上,这非常有用,因为它为您提供了几乎没有开销的多维数组,保留了locality of reference并防止了间接。此外,此分配方案的错误处理更加简单,因此您可以减少内存泄漏的风险。任何好的矩阵库都将以这种方式实现。对于C ++,包括Boost.MultiArray

至于解除分配:是的,您需要在目前的方案中多次拨打delete[]

答案 1 :(得分:4)

这是一个例程,它在连续的内存空间中分配维度为N1 x N2 x N3的3D数组,同时允许运算符访问的a [i] [j] [k]语法。数组是动态的但是连续的,所以它比矢量&lt;&gt;大得多。新[]调用的方法和循环。

template <class T> T ***Create3D(int N1, int N2, int N3)
{
    T *** array = new T ** [N1];

    array[0] = new T * [N1*N2];

    array[0][0] = new T [N1*N2*N3];

    int i,j,k;

    for( i = 0; i < N1; i++) {

        if (i < N1 -1 ) {

            array[0][(i+1)*N2] = &(array[0][0][(i+1)*N3*N2]);

            array[i+1] = &(array[0][(i+1)*N2]);

        }

        for( j = 0; j < N2; j++) {     
            if (j > 0) array[i][j] = array[i][j-1] + N3;
        }

    }

    cout << endl;
    return array;
};

template <class T> void Delete3D(T ***array) {
    delete[] array[0][0]; 
    delete[] array[0];
    delete[] array;
};

以后的实施例程......

int *** array3d;
int N1=4, N2=3, N3=2;

int elementNumber = 0;

array3d = Create3D<int>(N1,N2,N3);

cout << "{" << endl;
for (i=0; i<N1; i++) {
    cout << "{";
    for (j=0; j<N2; j++) {
        cout << "{";
        for (k=0; k<N3; k++) {
            array3d[i][j][k] = elementNumber++;
            cout << setw(4) << array3d[i][j][k] << " ";
        }
        cout << "}";
    }
    cout << "}";
    cout << endl ;
}
cout << "}" << endl;

Delete3D(array3d);

给出输出:

{
{{   0    1 }{   2    3 }{   4    5 }}
{{   6    7 }{   8    9 }{  10   11 }}
{{  12   13 }{  14   15 }{  16   17 }}
{{  18   19 }{  20   21 }{  22   23 }}
}

答案 2 :(得分:3)

由于这是标记C,这里也是C答案。由于C99多维数组可以非常有效地处理,即使大小是动态的:

double c[size_x][size_y][size_z];

这会在堆栈上连续分配矩阵。矩阵元素由c[i][j][k]访问,编译器为您完成所有索引算法。如果您担心这可能会导致SO,您可以轻松地使用它来呼叫malloc

double (*c)[size_y][size_z] = malloc(sizeof(double[size_x][size_y][size_z]));

答案 3 :(得分:2)

问题不在于你的内存没有对齐...... C ++规范对newnew[]的调用的要求是它传回指向连续内存的指针正确对齐平台和所请求对象的大小。

您的问题是,您没有通过一次调用new[]为阵列分配整个缓冲区,而是多次调用new[]。因此,每次对new的调用都将返回对齐且连续的内存,对new[]的多次调用不需要返回本身连续分配的内存缓冲区。例如,每次调用new[]都会返回对齐的内存,但正如您所指出的,new返回的每个内存数组的开头都可能存在“间隙”。这些“差距”的原因可能有多种原因,实际上取决于底层操作系统如何为您的程序分配内存。

如果您不想在每个数组中有任何“间隙”,那么您需要通过一次调用new来分配整个缓冲区。

最后,要回答关于delete[]的问题,是的,因为您没有通过一次调用new[]来分配整个内存缓冲区,所以只能通过调用{{}来删除数组。 1}}。每次对delete[]的调用都必须与对new[]的调用配对,因为这些调用是单独的内存分配。

答案 4 :(得分:1)

是的,这是正常的。 您逐行分配数据;您唯一可以确定的是数据在每一行都是连续的。

相关问题