簡體   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