optimusfrenk
optimusfrenk

Reputation: 1321

Understanding casting/conversion from pointer to multidimensional array

I'm playing around pointers and arrays, and i want to cast/convert a pointer to an array of int (allocated with malloc) to a multidimensional array of int.

I don't know why the following C program doesn't print the same number two times.

...
str->val = malloc(16);
int (*m)[4][4] = str->val;
printf("The number is %d, yes the number is %d", str->val[4+1], (*m)[1][1]);
...

Now, the first printed number is right, but the second one is not. I found other question on SO similar to mine, but i couldn't resolve my problem. I'm sorry for the possible duplication.

I have one more question: what's the difference between the following declarations?

int m[10];
int (*m)[10];

EDIT:

My problem is caused by a wrong declaration of the field val of my struct: I declared it as char.

Upvotes: 0

Views: 76

Answers (3)

Sylvain Chiron
Sylvain Chiron

Reputation: 290

I'm playing around pointers and arrays, and i want to cast/convert a pointer to an array of int (allocated with malloc) to a multidimensional array of int.

This is a very good idea. I’ve discovered this year that you can have pointer to arrays, and this is very useful when you want to parse a block of memory like a multidimensional array (because it comes from a struct in which the array dimensions can vary, for example). This post is very old, but let’s add an answer.

I have one more question: what's the difference between the following declarations?

int m1[10];
int (*m2)[10];

They are not the same at all!

  • m1 is an array of ten integers. It occupies 10 * sizeof(int) bytes, which is typically 40 bytes.
  • m2 is a pointer to such an array. So it is just a pointer. It can be assigned NULL, for instance. It just stores an address. It occupies sizeof(void *) bytes, typically 8 bytes nowadays.

When you have an array, you can change it directly to a pointer, and use the pointer the same way you use the array:

int m[10], * mPtr = m;
assert(m[i] == mPtr[i]);

This is actually just the same for multidimensional arrays, giving that a multidimensional array is an array of arrays:

int m[10][10], (* mPtr)[10] = m;
assert(m[i][j] == mPtr[i][j]);

So when you want a pointer, you have to omit the first dimension, because it is actually not needed to compute the address of a cell. &mPtr[i][j] is computed as mPtr + i * sizeof(int[10]) + j * sizeof(int) (which is also mPtr + i * sizeof(*mPtr) + j * sizeof(**mPtr). When you go onto the next i, it jumps ten ints as you expect.

Hence the solution to your problem:

str->val = malloc(sizeof(int[4][4]));
int (* m)[4] = (int (* )[4])str->val;

As a conclusion, C has actually good features/syntaxes to deal with multidimensional arrays, especially matrices. Only the declaration of the pointer is ugly, this is why I commonly use macros for it. See these test cases and the macro definitions. For your case, it could be used like that:

PtrDim2(int, m, 4, 4, str->val);

To declare and initialize m just like above. The first dimension is simply like a comment, actually you can omit it completely if you want: PtrDim2(int, m, , 4, str->val);.

Upvotes: 0

Yousf
Yousf

Reputation: 3997

Using the nice cdecl.org tool, int (*m)[4][4] is translated to declare m as pointer to array 4 of array 4 of int, which is multidimensional array. It should work if you allocated more memory.

int m[10]; is array of 10 integers stacked as a row in memory. int (*m)[10]; is a pointer to an array which holds 10 values.

int m[4][5] is multidimensional array, but they are almost like int m[20]. They are stacked as a row in memory. Indexing m[2][0] is simply translated to m[5*2 + 0].

int *m[5] is NOT multidimensional array, it is array of pointers. Each pointer points to a different array. Values are not stored in sequence.

Upvotes: 2

user529758
user529758

Reputation:

Your problem is that 16 bytes ain't enough for your array. Common values of sizeof(int) are 2 and 4, so you need at least 32 or 64 bytes for representing 4 ints. But you shouldn't be sticking hard-wired constants into your code anyway. Use the sizeof operator, and it will work:

int (*arr)[4][4] = malloc(sizeof(*arr));
int *ptr = &(*arr)[0][0];

// fill it with something, then:

printf("%d = %d\n", (*arr)[1][1], ptr[1 * 4 + 1]);

Upvotes: 1

Related Questions