Mano-Wii
Mano-Wii

Reputation: 592

How to reshape a flat array into a 2d in C?

I have an array with x * x elements defined as a pointer.

I wanted to do something like this:

void func(const unsigned int x, const int *flat_array)
{
    const int (*reshaped)[x] = flat_array;
    ...
}

but how?

Upvotes: 0

Views: 3358

Answers (4)

Lundin
Lundin

Reputation: 214920

Assuming that the pointer does point at an array, that is - a chunk of adjacent items of the same type, then you can safely cast the pointer type:

const int (*reshaped)[x] = (const int(*)[x])flat_array;

This is guaranteed to work because the type aliasing rules in C are only concerned of the nature of the pointed-at data and not so much about the pointer types involved. (See the concept of effective type, 6.5/6).

Upvotes: 0

Jonathan Leffler
Jonathan Leffler

Reputation: 754920

This code works for me. Note that it uses a C99 (and C11) variable length array (VLA). It won't compile with a C89/C90 compiler.

#include <stdio.h>

static void func(const unsigned int x, const int *flat_array)
{
    const int (*reshaped)[x] = (void *)flat_array;
    for (unsigned int i = 0; i < x; i++)
    {
        for (unsigned int j = 0; j < x; j++)
            printf("%3d", reshaped[i][j]);
        putchar('\n');
    }
}

int main(void)
{
    int flat[] =
    {
        /* random -n 25 10 99 | commalist -n 5 -b '        ' */
        73, 34, 76, 48, 17,
        25, 71, 11, 87, 74,
        18, 87, 11, 47, 32,
        33, 62, 41, 55, 90,
        90, 28, 69, 58, 29,
    };

    for (int i = 0; i < 5; i++)
    {
        printf("R[%d]", i);
        for (int j = 0; j < 5; j++)
            printf(" [%d] = %2d", j, flat[i * 5 + j]);
        putchar('\n');
    }

    func(5, flat);
    return 0;
}

Compiled without warnings on a Mac running macOS Sierra 10.12.6 using GCC 7.1.0 with the compilation options:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
      -Wstrict-prototypes rs37.c -o rs37
$

Without the cast (to void *) in the function, I get the error:

initialization from incompatible pointer type [-Werror=incompatible-pointer-types]

The void * cast is an effective way to deal with the problem — but it could be misused very easily. You could also write:

    const int (*reshaped)[x] = (int (*)[x])flat_array;

That explicitly casts direct to the correct type — pointer to array of integers of row width x. You could add a const into the cast if you wanted to.

Output:

R[0] [0] = 73 [1] = 34 [2] = 76 [3] = 48 [4] = 17
R[1] [0] = 25 [1] = 71 [2] = 11 [3] = 87 [4] = 74
R[2] [0] = 18 [1] = 87 [2] = 11 [3] = 47 [4] = 32
R[3] [0] = 33 [1] = 62 [2] = 41 [3] = 55 [4] = 90
R[4] [0] = 90 [1] = 28 [2] = 69 [3] = 58 [4] = 29
 73 34 76 48 17
 25 71 11 87 74
 18 87 11 47 32
 33 62 41 55 90
 90 28 69 58 29

Upvotes: 3

0___________
0___________

Reputation: 68004

if original was malloced and I understand what reshape means

#define MIN(x,y) ((x) > (y) ? (y) : (x))

int *reshape(int *src, int srcRows, int srcCols, int newRows, int newColums)
{
    int *newarray = (*src != NULL && newRows > 0 && newColums > 0) ? malloc(newRows * newColums) : NULL;

    if (newarray != NULL)
    {
        for (int row = 0; row < MIN(srcRows, newRows); row++)
            for (int col = 0; col < MIN(srcCols, newColums); col++)
                *(newarray + row * newColums + col) = *(src + row * srcCols + col);
        free(src);
    }
    return newarray;
}

If new array is smaller some data will be lost.

Upvotes: 0

sancelot
sancelot

Reputation: 2063

this should do it :

int m,n;
typedef int myarray_t[x][x];
myarray_t *myarray;
myarray = (myarray_t *) flat_array;

for (m=0;m<x;m++)
   for (n=0;n<x;n++)
       printf("[%d][%d] : %d\n",m,n,(*myarray)[m][n]);

Upvotes: 0

Related Questions