8

I want to declare a 2d array using malloc. On looking up on the internet, all websites tell to declare a int ** pointer and then use malloc for first allocating the individual pointers to the 1d arrays and then use malloc again to allocate space for the individual ints. My doubt is that the array declared this way does not hold its elements in contiguous memory addresses. While the following way using only one malloc statement and dynamically allocates a 2d array and all the addresses are contiguous as required. So shouldn't the following be the correct way to dynamically allocate a 2d array?

#include <stdio.h>

int main(){
    int (*p)[2] = malloc(3 * sizeof *p);
    int i;
    int j;

        //All addresses printed here are contiguous
    for(i=0; i<3; i++){
        for(j=0; j<2; j++){
            printf("%d\t", &p[i][j]);
        }
        printf("\n");
    }
}
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Nikunj Banka
  • 11,117
  • 16
  • 74
  • 112
  • 7
    this is the correct way to allocated a 2-dimensional array; what you described before is a jagged array, which, however, is pretty much useless if you don't store the lengths of the individual sub-arrays as well; change the magic number `24` to `3 * sizeof *p` and you're good to go – Christoph Jun 30 '13 at 09:40
  • 4
    you shouldn't print pointers with `%d`, though - there's `%p` for that, and for full portability, you'd have to cast to `void*` as well – Christoph Jun 30 '13 at 09:46
  • Why do you use the `&p` when referring to array elements? Is it intended to check the addresses instead of the values? – v_2e Jul 09 '20 at 14:43

3 Answers3

5

So shouldn't the following be the correct way to dynamically allocate a 2d array?

It should, since this approach is the equivalent of declaring a "statically-allocated" array of multiple dimensions.

The reason for this is that this way, you get a contiguous block of memory, which is convenient (you couldn't use memset() on a pointer-to-pointer, right?), and you still can have the compiler do the pointer arithmetic and array subscripting calculation for you (that's convenient too).

By the way, if you need a dynamically-sized array of which the scope is only within one function, i. e. you don't need to return it, consider using a VLA (variable-length array) with automatic storage duration instead.

2

Your 2D array isn't fully dynamic since one of its dimensions is fixed to two elements. (In your particular example, you could use a variable-length array, but in general you might want to be able to return your allocated array from a function.)

If you want something that syntactically acts like a 2D M×N array, is allocated completely dynamically, and uses contiguous memory, you can allocate a block of memory of M * N elements and then allocate an array of M pointers, where each element points to a "row' of the M * N block.

Q6.16 from the comp.lang.c FAQ has a good diagram and a more detailed explanation of this.

(Okay, it's not completely contiguous since the array of pointers and the block of items are separate. You could allocate both of them together, although that's trickier since it'd require some extra work to guarantee proper alignment.)

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
  • 1
    The dimension is not fixed, in that the `2` shown in the code in the question need not be a constant. The C standard has supported variable-length arrays since 1999. Any integer expression with a positive value may be used, even if its value is only available at run-time. – Eric Postpischil Jun 30 '13 at 12:30
  • @EricPostpischil Yes, I'm aware of VLAs, but a function would not be able to return it, so it's not very general. I've updated my answer to explain that. – jamesdlin Jun 30 '13 at 18:57
  • If the caller doesn't know the dimensions, you need 2 or 3 outputs anyway so you can't just return a pointer. You could return the row length (and number of rows if non-square) by reference as an output arg, and let the caller cast the returned pointer. You might need to hold it in a `void*` so the caller can get the dimensions *before* declaring the type of the pointer-to-array return value, but it is possible to pass pointers to 2D arrays along with their dimension, and similarly to receive them. – Peter Cordes Nov 21 '20 at 10:26
-4

in other words :

include < stdio.h>
include < stdlib.h>
const int **MAXX** = 10 ;
const int **MAXY** = 10 ;
int main () {
 int *p = ( int * ) malloc ( **MAXX * MAXY** ) ;
 int x=3 ;
 int y=4 ;
 ***( p + MAXX * x + y )** = 12 ;
 printf ( "\n%d ",***( p + MAXX * x + y )** );
 return 0 ;
}

this is the simplest way to allocate and use array with 2d dimension

Simon C.
  • 1,058
  • 15
  • 33
  • 4
    I'd strongly suggest you remove those extra `*`s from your answer. They just make the code hard to follow and uncompileable. – Hong Ooi Jun 30 '13 at 11:37
  • 4
    (1) Variable-length arrays have been in the C standard since 1999, and they ought to be used rather than explicitly expressed arithmetic. (2) `malloc(MAXX*MAXY)` does not allocate space for `MAXX*MAXY` `int` objects. – Eric Postpischil Jun 30 '13 at 12:21