-1

I'm writing a C for which I need to create a 2D array. I've found a solution to my problem using double pointers (pointers to pointers) in the following way:

#include <stdio.h>
#include <stdlib.h>
int d = 3;

#define DIM_MAX 9

void changeArray(int d, int *array[d]);

int main()
{
    //alocate array of 'd' colummns and 'd' row using malloc using array of pointers
    int **array = malloc(d*sizeof(int *));

    for(int count = 0; count < d; count++)
    {
        array[count] = malloc(d*sizeof(int *));
    }

    /* Call changeArray function */
    changeArray(d, array); 

    for(int i = 0; i < d; i++)
    {
        for(int j = 0; j < d; j++)
        {
            printf("%d ", array[i][j]);
        }
        printf("\n");
    }

    for(int count = 0; count < d; count++)
    {
        free(array[count]);
    }
    return 0;
}
void changeArray(int n, int *array[d])
{
    for(int i =0; i < n; i++)
    {
        for(int j = 0; j < n; j++)
        {
            array[i][j] = i*j;
        }
    }
    return;
}

The code above works pretty well (it seems), but I've read in the web that using pointer to pointer is not the correct way to create 2D arrays. So I've come up with the following code, which also works:

#include <stdio.h>
#include <stdlib.h>
#define DIM_MAX 9
int d = 3;
void changeArray(int d, int *array[d]);

int main()
{
    //alocate array of 'd' colummns and 'd' row using malloc using array of pointers
    int *array[DIM_MAX] = {0};

    for(int count = 0; count < d; count++)
    {
        array[count] = (int *)malloc(d*sizeof(int *));
    }

    /* Call changeArray function */
    changeArray(d, array); 

    for(int i = 0; i < d; i++)
    {
        for(int j = 0; j < d; j++)
        {
            printf("%d ", array[i][j]);
        }
        printf("\n");
    }

    for(int count = 0; count < d; count++)
    {
        free(array[count]);
    }

    return 0;
}
void changeArray(int n, int *array[d])
{
    for(int i =0; i < n; i++)
    {
        for(int j = 0; j < n; j++)
        {
            array[i][j] = i*j;
        }
    }
    return;
}

What is the difference in using any of the two ways above to write this code?

alk
  • 69,737
  • 10
  • 105
  • 255
tropez
  • 138
  • 3
  • 13
  • Just edited it. Thanks – tropez Jul 28 '17 at 18:12
  • 1
    I don't get why you don't simply write: int array[d][d]; – Dale Jul 28 '17 at 18:13
  • 5
    Neither of these is really a 2D array. The first one is a pointer to an array of pointers to arrays. The 2nd one is an array of pointers to arrays. `int array[D1][D2]` is a 2D array. – Kevin Jul 28 '17 at 18:13
  • Any of these ways will work, but the key point is that when you pass an array to a function, it will automatically be demoted to a pointer to the first element, so once you go into an function that manipulates the array, the function will be working with pointers. – Felix Guo Jul 28 '17 at 18:17
  • This is a toy version that I'm trying to implement. In the real code I'm writing, I won't be able to know the value of d (it will be a input from the user) during compile time – tropez Jul 28 '17 at 18:17
  • @Kevin: You are right none is a 2D array, nor can they point to one. But the first is a pointer to pointer to `int`, the second an array of pointer to `int`. There are no "pointers to array" involved! And that's exactly what OP could use: a pointer to a 1D array (dynamic allocation, function parameter) or a 2D array (static or automatic allocation). – too honest for this site Jul 28 '17 at 18:22
  • @Olaf Yes I'm aware, perhaps I didn't word it correctly. I just meant the whole structure after it's finished being created. `array` maybe be an `int**` but it's pointing to the beginning of a block of memory treated as an array of `int*`s. – Kevin Jul 28 '17 at 18:24
  • @Kevin: As the question shows, exact language is very important here; there is already enough missconception and confusion. – too honest for this site Jul 28 '17 at 18:26
  • @Vinicius: It does not matter if the lengths are known at run-time only. Use a VLA. The constructs you use are outdated since 18 years for a rectangular 2D array as you use it.. – too honest for this site Jul 28 '17 at 18:31
  • 1
    @Dale according to the [ISO/IEC 9899:TC3, Section 6.7.8: Initialization](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf), "_3. The type of the entity to be initialized shall be an array of unknown size or an object type that is not a variable length array type._", consequentially `int array[d][d];` results in `error: variable-sized object may not be initialized`. – Bojan P. Jul 28 '17 at 18:41
  • [How can I dynamically allocate 2D-array in one allocate C](https://stackoverflow.com/q/43710298/2410359) may help. – chux - Reinstate Monica Jul 28 '17 at 19:00
  • Tip: for explaining 2D arrays, pointers to 1D arrays, and pointers to pointers, better to use different value dimensions like `H` and `W` or 3 and 4, etc rather than form a square 2D solution of `DIM_MAX * DIM_MAX` – chux - Reinstate Monica Jul 28 '17 at 19:04

3 Answers3

0

It is actually pretty simple. All you have to do is this:

int i[][];

You are overthinking it. Same as a normal array, but has two indexes.

Alejandro Montilla
  • 2,626
  • 3
  • 31
  • 35
  • But how do I pass this array as an argument for a function if I don't know the number of columns until the user enters it? – tropez Jul 29 '17 at 14:02
0

Let's say you want to create a "table" of 4 x 4. You will need to malloc space for 4 pointers, first. Each of those index points will contain a pointer which references the location in memory where your [sub] array begins (in this case, let's say the first pointer points to the location in memory where your first of four arrays is). Now this array needs to be malloc for 4 "spaces" (in this case, let's assume of type INT). (so array[0] = the first array) If you wanted to set the values 1, 2, 3, 4 within that array, you'd be specifying array[0][0], array[0][1], array[0][2], array[0][3]. This would then be repeated for the other 3 arrays that create this table.

Hope this helps!

NamoDawn
  • 26
  • 4
0

[Not an answer, but an alternative approach to achieve the desired result, namely defining a user-defined 2D array.]

Assuming the compiler in use supports VLAs you could do this:

#include <stddef.h> /* for size_t */


void init_a(size_t x, size_t y, int a[x][y]); /* Order matters here!
                                                 1st give the dimensions, then the array. */
{
  for (size_t i = 0; i < x; ++i)
  {
    for (size_t j = 0; j < y; ++j)
    {
      a[i][j] = (int) (i * j); /* or whatever values you need ... */
    }
  }
}

int main(void)
{
  size_t x, y;

  /* Read in x and y from where ever ... */

  {
    int a[x][y]; /* Define array of user specified size. */

    init_a(x, y, a); /* "Initialise" the array's elements. */

    ...
  }
}
alk
  • 69,737
  • 10
  • 105
  • 255
  • That worked! Are there any downsides of using VLA's instead of what I was doing before? I mean, when should I use VLA's? – tropez Jul 29 '17 at 14:59
  • @Vinicius: Downsides? 1.) VLAs live on the stack, so size is limited. 2.) VLAs typical are not available from compilers =C11. They are not available in certain Non-C-Standard compliant C compilers and not all (?) in C++. – alk Jul 29 '17 at 15:06