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

发布于 2024-12-13 20:09:04 字数 1746 浏览 2 评论 0原文

我有一个很奇怪的问题,可能没有实际用途,但答案让我很困扰。我今天尝试用数组以及如何使用以下代码在内存中分配它们来搞乱:(编译器Xcode 4 btw,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 将我的记忆对齐为一条恒定线? (我不是母语英语,所以很抱歉,但我不知道如何更好地说)

这只是为了一般理解:-)

谢谢你!

PS 顺便说一句,使用一次删除 [] 就足够了,还是我必须遍历 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;

i have a quite weird question which probably has no practical use but the answers bothers me a lot. I tried to mess around today a little bit with arrays and how they are allocated in memory using this code: (Compiler Xcode 4 btw, 4 byte integer)

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;

When i enter now: 3, 2 and 4 i get the following output in the console:

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

What my question is now, if we look at the output, than we see that mostly, the memory is aligned every 4 bytes but sometimes we see a bigger step like from 0x100100a7c to
0x100100a90 .

Is this normal and how can i prevent this? Why is this? Is there a possibility to force c to align my memory as a constant line? (I'm not native english so sorry for that but i don't know how to say it better)

Its just for general understanding :-)

Thank u!

P.S. is it enough to use delete [] once btw or do i have to go through each of the 3 memory blocks and delete [] there the whole array? EDIT:

I delete memory now like this and it works pretty good:

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;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

待"谢繁草 2024-12-20 20:09:04

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

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) 处的元素。

事实上,这非常有用,因为它以很少的开销为您提供多维数组,保留引用的位置 并防止间接。此外,此分配方案的错误处理要简单得多,因此内存泄漏的风险较小。任何好的矩阵库都会以这种方式实现。对于 C++,包括 Boost.MultiArray

至于释放:是的,您需要在当前方案中多次调用 delete[]

Yes, this is normal. The memory is aligned, btw., it's just not contiguous because subsequent calls to new do not make this guarantee. And yes, you can allocate the entire 3-d array in a single, contiguous buffer:

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

or, safer

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

and then index it with

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

to get the element at (i,j,k).

This is, in fact, very useful, as it gives you multidimensional arrays with little overhead, preserving locality of reference and preventing indirection. Also, the error handling for this allocation scheme is much simpler so you run less of a risk of memory leaks. Any good matrix library will be implemented this way. For C++, that includes Boost.MultiArray.

As for deallocation: yes, you need multiple calls to delete[] in your present scheme.

勿忘心安 2024-12-20 20:09:04

下面是一个例程,它在连续的内存空间中分配维度为 N1 x N2 x N3 的 3D 数组,同时允许使用 a[i][j][k] 语法进行运算符访问。该数组是动态但连续的,因此它比向量<>有一个巨大的优势。 new[] 调用的方法和循环。

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 }}
}

Heres a routine which allocates the 3D array of dimension N1 x N2 x N3 in contiguous memory space while allowing you the a[i][j][k] syntax for operator access. The array is dynamic but continuous so it's a huge plus over the vector<> approach and loops of new[] calls.

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;
};

And later in your implementation routine...

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);

Gives the output:

{
{{   0    1 }{   2    3 }{   4    5 }}
{{   6    7 }{   8    9 }{  10   11 }}
{{  12   13 }{  14   15 }{  16   17 }}
{{  18   19 }{  20   21 }{  22   23 }}
}
皇甫轩 2024-12-20 20:09:04

由于此问题被标记为 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]));

Since this is tagged C, here is also a C answer. Since C99 multidimensional arrays can be handled quite efficiently, even if the sizes are dynamic:

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

This allocates the matrix contiguously on the stack. Matrix elements are accessed by c[i][j][k] and the compiler does all the indexing arithmetic for you. If you fear that this could lead to SO, you can easily call malloc with it:

double (*c)[size_y][size_z] = malloc(sizeof(double[size_x][size_y][size_z]));
離殇 2024-12-20 20:09:04

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

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

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

最后,要回答有关 delete[] 的问题,是的,因为您没有通过一次调用 new[] 分配整个内存缓冲区,所以您无法删除数组只需调用一次delete[]即可。对 new[] 的每次调用都必须与对 delete[] 的调用配对,因为它们是单独的内存分配。

The issue is not that your memory isn't aligned ... the requirement by the C++ specification for a call to new and new[] is that it passes back a pointer pointing to contiguous memory that is properly aligned for the platform and the size of the object requested.

Your problem is that you are not allocating the entire buffer for the array with a single call to new[], but rather with multiple calls to new[]. Therefore while each call to new will return aligned and contiguous memory, the multiple calls to new[] are not required to return memory buffers that themselves are contiguously allocated. For example, each call to new[] returns aligned memory, but as you noted, there can be "gaps" in the start of each memory array that new returns. The reason for these "gaps" can have multiple reasons, and really depends on how the underlying OS is allocating memory for your program.

If you do not want to have any "gaps" in each array, then you will need to allocate the entire buffer with a single call to new.

Finally, to answer your question about delete[], yes, because you did not allocate the entire memory buffer with a single call to new[], you cannot delete your array with a single call to delete[]. Every call to new[] must be paired with a call to delete[] since those were separate memory allocations.

忆伤 2024-12-20 20:09:04

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

Yes this is normal.
You allocate data row by row; The only thing you can be sure is that data will be contiguous on each row.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文