简体   繁体   English

在C中使用memcpy将2D矩阵复制到3D矩阵

[英]Copy a 2D matrix to a 3D matrix using memcpy in C

I was instructed to copy all elements from my 2d array, matrix2D , to my 3d array matrix3D using a single memcpy command and then print out the 3d array (separating elements with a comma, rows with a semicolon and each 2d matrix with a new line). 指示我使用单个memcpy命令将2d数组matrix2D所有元素复制到3d数组matrix3D ,然后打印出3d数组(用逗号分隔元素,用分号分隔行,并用换行符分隔每个2d矩阵)。 Before that, the program takes in user input for dimensions of the 3d matrix, and then all the data to go into the matrix (floats). 在此之前,该程序接受3d矩阵尺寸的用户输入,然后将所有数据输入到矩阵中(浮点数)。 My functions malloc2d and malloc3d are working correctly and I am getting no segmentation faults, but when I attempt to memcpy the data and then print the 3d matrix, nothing is printing. 我的功能malloc2dmalloc3d工作正常,我没有得到分段错误,但是当我试图memcpy数据,然后打印的3D矩阵,没有什么是打印。 Here is the code: 这是代码:

#include "utilities.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void){
    unsigned int dim1,dim2,dim3;
    printf("Dimensionality of 3-D matrix ===>");
    scanf("%u",&dim1); //takes user input for dimensions
    scanf("%u",&dim2); //takes user input for dimensions
    scanf("%u",&dim3); //takes user input for dimensions

    //allocating memory for 3d, 2d and 1d matrices
    float*** matrix3D = malloc3D((unsigned int)(dim1), (unsigned int)(dim2), (unsigned int)(dim3), sizeof(float));
    float** matrix2D = malloc2D(dim1, dim2*dim3, sizeof(float));
    float* matrix1D = malloc(dim1*dim2*dim3);

    for(int i = 0; i<(dim1*dim2*dim3); i++){ //taking user input floats
        fscanf(stdin, "%f", &matrix1D[i]);
    }//for

    for(int i = 0; i<(dim1*dim2*dim3); i++){//writing contents of 1d matrix to 2d matrix
        matrix2D[i/(dim2*dim3)][i%(dim2*dim3)] = matrix1D[i];
    }//for

    for (int i = 0; i < dim1; i++){//printing out 2d array as asked
        for (int j = 0; j < (dim2*dim3); j++){
            printf("%0.2f", matrix2D[i][j]);
            if(j==((dim2*dim3)-1)){
                printf(";");
            }//if
            else{
                printf(",");
            }//else
        }//for
    }//for

    printf("\n"); //new line for readability 

    memcpy(matrix3D, matrix2D, dim1*dim2*dim3*sizeof(float));    

    for (int i = 0; i < dim1; i++){//printing out 3d array as asked
        for (int j = 0; j < dim2; j++){
            for(int k = 0; k < dim3; k++){
                printf("%0.2f", matrix3D[i][j][k]);
                if(j==((dim2)-1)){
                    printf(";");
                }//if
                else if(k==((dim3)-1)){
                    printf("\n");
                }//else if
                else{
                    printf(",");
                }//else
            }//for
        }//for
    }//for

    free3D(matrix3D);
    free2D(matrix2D);
    free(matrix1D);

} //main

The example input and output given is (I have everything printing except the last 2 lines - the 3d matrix): 给定的示例输入和输出是(除了最后两行,我已经打印了所有内容-3d矩阵):

输入/输出示例

Here are malloc2D, malloc3D, free2D and free3D. 这是malloc2D,malloc3D,free2D和free3D。 I was under the impression they were right because they were given to us after none of us were able to get it. 我觉得他们是对的,因为他们是在我们没人能得到之后才给他们的。

void** malloc2D(size_t rows, size_t cols, size_t sizeOfType){
    void* block = malloc(sizeOfType * rows * cols);
    void** matrix = malloc(sizeof(void*) * rows);
    for (int row = 0; row < rows; ++row) {
        matrix[row] = block + cols * row * sizeOfType;
    }//for
    return matrix;
}//malloc2D

void free2D(void*** matrix){
    free((*matrix)[0]);
    free((*matrix));
    *matrix = NULL;
}//free2D

void*** malloc3D(size_t depth, size_t rows, size_t cols, size_t sizeOfType){
    void* block = malloc(sizeOfType * rows * cols * depth);
    void** matrix = malloc(sizeof(void*) * rows * depth);
    void*** matrix2 = malloc(sizeof(void**) * depth);
    for (int depth1 = 0; depth1 < depth; ++depth1) {
        matrix2[depth1] = (void**)(matrix + depth * rows * sizeof(void**));
        for(int row = 0; row < rows; ++row){
            matrix[depth1 * rows + row] = block + (depth1 * rows + row) * cols * sizeOfType;
        }//for
    }//for
    return matrix2;
}//malloc3D

void free3D(void**** matrix){
    free((*matrix)[0][0]);
    free((*matrix)[0]);
    free((*matrix));
    *matrix = NULL;
}//free3D

The only way to use a single memcpy to copy a 2d array into a 3d array is if the data for each of the 2d and 3d arrays are flat in memory. 使用单个memcpy将2d阵列复制到3d阵列的唯一方法是,如果2d和3d阵列中每个阵列的数据在内存中都是平坦的。

The allocation functions you were provided show that the data for each are contiguous. 您提供的分配功能表明每个数据都是连续的。 Therefore, you need to copy the data section of the 2d array into the data section of the 3d array. 因此,您需要将2d数组的数据部分复制到3d数组的数据部分中。

Since the data is contiguous, it follows that the data section is located at the address of the first element of the arrays. 由于数据是连续的,因此数据段位于数组的第一个元素的地址处。 Hence, the data section for the 2d array begins at &matrix2D[0][0] , and the data section for the 3d array begins at &matrix3D[0][0][0] . 因此,2d数组的数据段始于&matrix2D[0][0] ,而3d数组的数据段始于&matrix3D[0][0][0] Given the semantics of array syntax, these expressions are the same as matrix2D[0] and matrix3D[0][0] , respectively. 给定数组语法的语义,这些表达式分别与matrix2D[0]matrix3D[0][0]相同。

Assuming that matrix1D is initialized properly: 假设正确初始化了matrix1D

memcpy(matrix2D[0], matrix1D, dim1*dim2*dim3*sizeof(float));
memcpy(matrix3D[0][0], matrix2D[0], dim1*dim2*dim3*sizeof(float));

I've seen this allocation code a couple of times, and I always point out that while it's a clever way of allocating space for double/triple pointers, you might encounter problems when not used carefully. 我已经看过几次这种分配代码,而且我总是指出,虽然这是为双/三指针分配空间的一种聪明方法,但是如果不仔细使用,您可能会遇到问题。

Let's take a look at malloc2D : 让我们看一下malloc2D

void** malloc2D(size_t rows, size_t cols, size_t sizeOfType){
    void* block = malloc(sizeOfType * rows * cols);
    void** matrix = malloc(sizeof(void*) * rows);
    for (int row = 0; row < rows; ++row) {
        matrix[row] = block + cols * row * sizeOfType;
    }//for
    return matrix;
}

Like I've pointed out before, void* pointer arithmetic is illegal in C, GNU C has an extension for that. 就像我之前指出的那样, void*指针算法在C语言中是非法的,GNU C对此有一个扩展。 But let's assume this works as intended: 但是,让我们假设这按预期工作:

The first malloc reserves rows * cols spaces for objects of size sizeOfType . 第一个mallocsizeOfType大小的对象保留rows * cols空间。 The second malloc reserves space for rows pointers. 第二个mallocrows指针保留空间。 The memory layout of this is (the arrows represent: pointer points to): 的内存布局是(箭头表示:指针指向):

Note that block and matrix and different memory locations, the matrix[i] ( i th row) point to the start of a sequence at block[j] (start of a new colum, multiple of cols ). 注意, blockmatrix以及不同的存储位置, matrix[i] (第i行)指向block[j]处序列的起点(新列的起点, cols倍数)。

The malloc3D is basically doing the same but multiple times ( depth times). malloc3D基本上执行相同的操作,但是执行多次( depth次数)。 The basic memory layout is is similar with one more layer of pointers 1 : 基本的内存布局与指针1的另一层相似:

Note that block , matrix and matrix2 are different memory locations, the matrix2[i] point to the start of a sequence at matrix[j] and the matrix[j] points to the start of a sequence at block[k] . 请注意, blockmatrixmatrix2是不同的存储位置, matrix2[i]指向matrix[j]处序列的开始,而matrix[j]指向block[k]处序列的开始。

Now when you do: 现在,当您执行以下操作时:

memcpy(matrix3D, matrix2D, dim1*dim2*dim3*sizeof(float));

you are not copying the contents pointed to by matrix2D into the contents pointed to by matrix3D ; 没有matrix2D指向的内容复制到matrix3D指向的内容中; the contents of matrix2D are not float s, they are pointers! matrix2D的内容不是float ,而是指针! So you are in fact copying the pointers of matrix2D in matrix3D . 因此,实际上您正在将matrix2D的指针复制到matrix3D That will cause trouble because the pointers are not of the same type (see the graphs): matrix2D pointers point to float* and matrix3D pointers point to float** , so when you dereference them, you will get wrong results, because you are dereferencing from incorrect addresses. 这将引起麻烦,因为指针的类型不同(请参见图表): matrix2D指针指向float*matrix3D指针指向float** ,所以在取消引用它们时,将得到错误的结果,因为您正在取消引用来自不正确的地址。 As jxh points out in his/her answer , this would only work when the values are flat in memory, but they are not, even though block is flatt, but you are not accessing block directly, you are accessing it through pointers. 正如jxh在他/她的答案中指出的那样,这仅在内存中的值是平坦的情况下才有效,但即使block是flatt,但它们并非如此,但您没有直接访问block ,而是通过指针访问它时,它们不是有效的。

That means that 那意味着

free3D(matrix3D);
free2D(matrix2D);

will get you into trouble, because the first free does not free the memory reserved by malloc3D , as it has been overwritten by the memcpy . 会给您带来麻烦,因为第一个free不会释放malloc3D保留的内存,因为它已被memcpy覆盖。 free2D would attempt to free the same memory which you are not allowed to. free2D将尝试释放您不允许的相同内存。

You would have to go down to the block level and use memcpy there, for example this is OK: 您将不得不下降到block级别并在那里使用memcpy ,例如,这是可以的:

for(int i = 0; i < rows; ++i)
    memcpy(matrix3D[0][i], matrix2D[i], cols * sizeof(float));

Fotenotes 脚注

1 Because of the limited space in the graph, I use depth == 2 , so that's why matrix2+1 points to matrix+2 . 1由于图中的空间有限,我使用depth == 2 ,这就是为什么matrix2+1指向matrix+2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM