繁体   English   中英

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

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

指示我使用单个memcpy命令将2d数组matrix2D所有元素复制到3d数组matrix3D ,然后打印出3d数组(用逗号分隔元素,用分号分隔行,并用换行符分隔每个2d矩阵)。 在此之前,该程序接受3d矩阵尺寸的用户输入,然后将所有数据输入到矩阵中(浮点数)。 我的功能malloc2dmalloc3d工作正常,我没有得到分段错误,但是当我试图memcpy数据,然后打印的3D矩阵,没有什么是打印。 这是代码:

#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

给定的示例输入和输出是(除了最后两行,我已经打印了所有内容-3d矩阵):

输入/输出示例

这是malloc2D,malloc3D,free2D和free3D。 我觉得他们是对的,因为他们是在我们没人能得到之后才给他们的。

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

使用单个memcpy将2d阵列复制到3d阵列的唯一方法是,如果2d和3d阵列中每个阵列的数据在内存中都是平坦的。

您提供的分配功能表明每个数据都是连续的。 因此,您需要将2d数组的数据部分复制到3d数组的数据部分中。

由于数据是连续的,因此数据段位于数组的第一个元素的地址处。 因此,2d数组的数据段始于&matrix2D[0][0] ,而3d数组的数据段始于&matrix3D[0][0][0] 给定数组语法的语义,这些表达式分别与matrix2D[0]matrix3D[0][0]相同。

假设正确初始化了matrix1D

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

我已经看过几次这种分配代码,而且我总是指出,虽然这是为双/三指针分配空间的一种聪明方法,但是如果不仔细使用,您可能会遇到问题。

让我们看一下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;
}

就像我之前指出的那样, void*指针算法在C语言中是非法的,GNU C对此有一个扩展。 但是,让我们假设这按预期工作:

第一个mallocsizeOfType大小的对象保留rows * cols空间。 第二个mallocrows指针保留空间。 的内存布局是(箭头表示:指针指向):

注意, blockmatrix以及不同的存储位置, matrix[i] (第i行)指向block[j]处序列的起点(新列的起点, cols倍数)。

malloc3D基本上执行相同的操作,但是执行多次( depth次数)。 基本的内存布局与指针1的另一层相似:

请注意, blockmatrixmatrix2是不同的存储位置, matrix2[i]指向matrix[j]处序列的开始,而matrix[j]指向block[k]处序列的开始。

现在,当您执行以下操作时:

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

没有matrix2D指向的内容复制到matrix3D指向的内容中; matrix2D的内容不是float ,而是指针! 因此,实际上您正在将matrix2D的指针复制到matrix3D 这将引起麻烦,因为指针的类型不同(请参见图表): matrix2D指针指向float*matrix3D指针指向float** ,所以在取消引用它们时,将得到错误的结果,因为您正在取消引用来自不正确的地址。 正如jxh在他/她的答案中指出的那样,这仅在内存中的值是平坦的情况下才有效,但即使block是flatt,但它们并非如此,但您没有直接访问block ,而是通过指针访问它时,它们不是有效的。

那意味着

free3D(matrix3D);
free2D(matrix2D);

会给您带来麻烦,因为第一个free不会释放malloc3D保留的内存,因为它已被memcpy覆盖。 free2D将尝试释放您不允许的相同内存。

您将不得不下降到block级别并在那里使用memcpy ,例如,这是可以的:

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

脚注

1由于图中的空间有限,我使用depth == 2 ,这就是为什么matrix2+1指向matrix+2

暂无
暂无

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

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