[英]Copy a 2D matrix to a 3D matrix using memcpy in C
指示我使用單個memcpy
命令將2d數組matrix2D
所有元素復制到3d數組matrix3D
,然后打印出3d數組(用逗號分隔元素,用分號分隔行,並用換行符分隔每個2d矩陣)。 在此之前,該程序接受3d矩陣尺寸的用戶輸入,然后將所有數據輸入到矩陣中(浮點數)。 我的功能malloc2d
和malloc3d
工作正常,我沒有得到分段錯誤,但是當我試圖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對此有一個擴展。 但是,讓我們假設這按預期工作:
第一個malloc
為sizeOfType
大小的對象保留rows * cols
空間。 第二個malloc
為rows
指針保留空間。 的內存布局是(箭頭表示:指針指向):
注意, block
和matrix
以及不同的存儲位置, matrix[i]
(第i
行)指向block[j]
處序列的起點(新列的起點, cols
倍數)。
malloc3D
基本上執行相同的操作,但是執行多次( depth
次數)。 基本的內存布局與指針1的另一層相似:
請注意, block
, matrix
和matrix2
是不同的存儲位置, 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.