将2D阵列重塑为3D阵列C.

时间:2018-01-30 16:42:29

标签: c

您好我正在尝试在C中转换matlab代码。在这样做时,我必须将2d数组重塑为3d数组。我试着编写一个函数,如下所示。我从here获得了帮助。

#include <stdio.h>
#include <stdlib.h>

#define ZALLOC(item, n, type) if ((item = (type *)calloc((n), sizeof(type))) == NULL) \
                                  fatalx("Unable to allocate %d unit(s) for item\n", n)
int i,j,k,x,y;
static void fatalx(const char *str, size_t n)
{
    fprintf(stderr, "%s: %zu\n", str, n);
    exit(1);
}

static int ***alloc_3d(int ar[][12],int rows, int cols,int levels)
{

    int count = 0;
    int ***array_3d;
    ZALLOC(array_3d, levels, int **);
    for (i = 0; i < levels; i++)
    {
        int **data;
        ZALLOC(data, rows, int *);
        array_3d[i] = data;
        for (j = 0; j < rows; j++)
        {
            int *entries;
            ZALLOC(entries, cols, int);
            array_3d[i][j] = entries;
            for (k = 0; k < cols; k++)
            {
                array_3d[i][j][k] = ar[i][j];
            }
        }
    }
    return array_3d;
}

static void print_3d(int ***a3d, int rows, int cols,int levels)
{
    for (i = 0; i < levels; i++)
    {
        printf("%d:\n", i);
        for (j = 0; j < rows; j++)
        {
            printf("   %d:  ", j);
            for (k = 0; k < cols; k++)
                printf(" %3d", a3d[i][j][k]);
            putchar('\n');
        }
    }
}

static void free_3d(int ***a3d, int levels, int rows)
{
    for (i = 0; i < levels; i++)
    {
        for (j = 0; j < rows; j++)
            free(a3d[i][j]);
        free(a3d[i]);
    }
    free(a3d);
}

int main(void)
{
    int ar[2][12]={
         {1,2,3,4,5,6,7,8,9,10,11,12},
         {13,14,15,16,17,18,19,20,21,22,23,24}
         };
    int d1 = 2;
    int d2 = 3;
    int d3 = 4;
    int ***a3d = alloc_3d(ar,d1, d2, d3);

    print_3d(a3d, d1, d2, d3);
    free_3d(a3d, d3, d2);

    return(0);
}

这不仅给了我错误的值,还给了垃圾值。第一个切片的matlab输出是:

  

a3d(:,:,1)=

 1     2     3
13    14    15

我的一个与

完全不同
0:
   0:     1   1   1
   1:     2   2   2
1:
   0:    13  13  13
   1:    14  14  14
2:
   0:   1991011277 1991011277 1991011277
   1:     4   4   4
3:
   0:     1   1   1
   1:   6630248 6630248 6630248

正如您所看到的那样,还有垃圾价值。所以我的索引也是错误的。知道如何正确地做到这一点? 提前谢谢。

2 个答案:

答案 0 :(得分:1)

事实上,您的示例不会执行重新整形,因为它会创建一个与原始数组完全不同类型的复合对象。

C多维数组是一个数组数组(数组......)。在其他重要特征中,这种阵列的所有元素在存储器中是连续的。你也可以构造一个指针数组,并初始化每个指针以指向它自己的数组等。尽管这些类型的对象在表面上是相似的,你可以以大致相同的方式将索引操作符应用于两者。重要的是要理解:

  • 指针数组需要额外的空间用于指针,指向它们指向的空间之上和之外。
  • 虽然指针数组中的指针在内存中是连续的,但它们指向的数组可能不是。这通常会导致
      如果系统的页面大小没有均匀划分指向数组的大小,则
    • 浪费空间,
    • 由于较差的引用位置而访问数组元素的性能较差。
  • 指针数组比较混乱,分配较慢,因为内存分配函数需要多次单独调用。
  • 指针数组更乱,速度更慢,因为所有指向数组也必须单独释放。
  • 另一方面,指针数组容纳“参差不齐”的多维伪数组,(指向)成员数组的长度不一样。

如果使用标准C多维数组(==数组数组)编写,程序的外观如下:

#include <stdlib.h>
#include <stdio.h>

#define ALLOC(p, n) do {                                \
    if (!((p) = calloc((n), sizeof(*(p))))) {           \
        fprintf(stderr, "Memory allocation failure\n"); \
        exit(1);                                        \
    }                                                   \
} while (0)

void *reshape_2d_3d(size_t id1, size_t id2, int iar[][id2],
        size_t od1, size_t od2, size_t od3) {
    // oar is a pointer to a multidimensional array; in this case, it will
    // point to the first element of an array of arrays (of arrays).
    int (*oar)[od2][od3];
    size_t size1 = id1 * id2;
    size_t size2 = od1 * od2 * od3;
    size_t min_size = (size1 <= size2) ? size1 : size2;

    ALLOC(oar, od1);

    // A loop nest could be used here, too, but I find this simpler for
    // tracking the correspondence of array elements.  It also better
    // accommodates the case where the reshaped result has different overall
    // size from the original.
    for (size_t i = 0; i < min_size; i++) {
        oar[i / (od2 * od3)][(i / od3) % od2][i % od3] = iar[i / id2][i % id2];
    }

    return oar;
}

void print_3d(size_t levels, size_t rows, size_t cols, int ar[][rows][cols]) {
    for (int i = 0; i < levels; i++) {
        printf("%d:\n", i);
        for (int j = 0; j < rows; j++) {
            printf("   %d:  ", j);
            for (int k = 0; k < cols; k++) {
                printf(" %3d", ar[i][j][k]);
            }
            putchar('\n');
        }
    }
}

int main(void) {
    int ar[2][12] = {
            {1,2,3,4,5,6,7,8,9,10,11,12},
            {13,14,15,16,17,18,19,20,21,22,23,24}
        };
    int d1 = 2, d2 = 3, d3 = 4;
    int (*a3d)[d2][d3] = reshape_2d_3d(2, 12, ar, d1, d2, d3);

    print_3d(d1, d2, d3, a3d);

    // A single, simple free() is all that's needed
    free(a3d);
}

输出:

0:
   0:     1   2   3   4
   1:     5   6   7   8
   2:     9  10  11  12
1:
   0:    13  14  15  16
   1:    17  18  19  20
   2:    21  22  23  24

请注意,它使用可变长度数组,但通常不关心堆栈分配。因此,它需要符合C99编译器,或符合C2011编译器,以实现VLA可选(在该版本中)功能。

答案 1 :(得分:0)

将数字分配给新分配的内存的方法是错误的。

static int ***alloc_3d(int ar[][12],int rows, int cols,int levels,int colsize)
{

    int count = 0;
    int ***array_3d;
    ZALLOC(array_3d, levels, int **);
    int i1=0,j1=0;
    for (i = 0; i < levels; i++)
    {       ...
            ...
            for (k = 0; k < cols; k++)
            {
                array_3d[i][j][k] = ar[i1][j1++];
                if( j1 == colsize) i1++,j1=0;
            }
        }
    }
    return array_3d;
}

像这样打电话

int colsize = 12;
int ***a3d = alloc_3d(ar,d1, d2, d3,colsize);

打印:

0:
   0:     1   2   3
   1:     4   5   6
1:
   0:     7   8   9
   1:    10  11  12
2:
   0:    13  14  15
   1:    16  17  18
3:
   0:    19  20  21
   1:    22  23  24

一个小小的注释 - 早些时候你的代码有未定义的行为访问绑定的数组索引。