0

I'm trying to to create the follow data structure:

{} = dynamic memory allocation

[] = array

{[ptr, ptr, ptr], [ptr, ptr, ptr], ...}

and a memory allocation to track the size of the memory locations that the ptr's will point at:

{[int, int, int], [int, int, int], ...}

and then pass this data structure into a function such that the values of the inner ptr's and int's are changed from within the function.

I hoped something like this would work:

void foo(int **arr[3], int *sizes[3], int num_arrays)
{
  int i, j, k;
  for(i=0; i<num_arrays; i++)
  {
    for(j=0; j<3; j++)
    {
      sizes[i][j] = 1 + (i * j);
      arr[i][j] = malloc(sizeof(int) * sizes[i][j]);
      for(k=0; k<sizes[i][j]; k++)
      {
        arr[i][j][k] = i * j * k;
      }
    }
  }
}

int main(int argc, char *argv[])
{
  int **arr[3] = malloc(sizeof(*(int[3])) * 10); //line 33
  int *sizes[3] = malloc(sizeof(int[3]) * 10); //line 34
  foo(arr, sizes, 10);

  int i, j, k;
  for(i=0; i<10; i++)
  {
    for(j=0; j<3; j++)
    {
      for(k=0; k<sizes[i][j]; k++)
      {
        printf("%d ", arr[i][j][k]);
      }
      printf("\n");
    }
    printf("\n");
  }
  return 0;
}

Unfortunately this results in compiler errors:

main.c: In function ‘main’:
main.c:33:41: error: expected expression before ‘)’ token
   int **arr[3] = malloc(sizeof(*(int[3])) * 10);
                                         ^
main.c:34:19: error: invalid initializer
   int *sizes[3] = malloc(sizeof(int[3]) * 10);
CSStudent7782
  • 618
  • 1
  • 5
  • 21
  • Maybe try `typedef int INTARR3[3];`... you can then use things like `sizeof (INTARR3)` for size of an array with 3 ints. – pmg Oct 14 '20 at 17:39
  • @pmg see edit, didn't work. – CSStudent7782 Oct 14 '20 at 17:45
  • works for me ... `typedef int INTARR3[3]; INTARR3 *a = malloc(4 * sizeof (INTARR3)); a[0][1] = 42;` – pmg Oct 14 '20 at 17:50
  • `int **arr[3]` declares an array with three elements, each of which is a pointer to pointer to int. – pmg Oct 14 '20 at 17:54
  • I don't know what the difference is, but I get `error: subscripted value is neither array nor pointer nor vector arr[i][j][k] = i * j * k;` – CSStudent7782 Oct 14 '20 at 17:59
  • You need to match the "dimensions" of the array to the amount of indexing. `int a[3] /* one dimension*/; int *b[3] /* two "dimensions" */; INTARR3 c /* one dimension */; INTARR3 *d /* two "dimensions" */; INTARR3 e[3] /* 2 dimensions */; INTARR3 **f /* 3 "dimensions" */;` ... – pmg Oct 14 '20 at 18:09

1 Answers1

1

As mentioned in comment, you can use type aliases (which I normally venomously object to regarding pointer aliasing) to make this at least readable. Something like this:

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

#define X_SIZE 3                 // our fixed internal size
typedef int INTARRX[X_SIZE];     // array of int
typedef int *INTPTRX[X_SIZE];    // array of pointer to int.

void foo(INTPTRX arr[], INTARRX sizes[], int num_arrays)
{
    int i, j, k;
    for (i = 0; i<num_arrays; i++)
    {
        for (j = 0; j<X_SIZE; j++)
        {
            sizes[i][j] = 1 + (i * j);
            arr[i][j] = malloc(sizeof(int) * sizes[i][j]);
            for (k = 0; k<sizes[i][j]; k++)
            {
                arr[i][j][k] = i * j * k;
            }
        }
    }
}

int main(int argc, char *argv[])
{
    INTARRX *sizes = calloc(10, sizeof *sizes);
    INTPTRX *arr = calloc(10, sizeof *arr);

    foo(arr, sizes, 10);

    int i, j, k;
    for (i = 0; i<10; i++)
    {
        for (j = 0; j<3; j++)
        {
            for (k = 0; k<sizes[i][j]; k++)
            {
                printf("%d ", arr[i][j][k]);
            }
            printf("\n");
        }
        printf("\n");
    }
    return 0;
}

Output

0
0
0

0
0 1
0 2 4

0
0 2 4
0 4 8 12 16

0
0 3 6 9
0 6 12 18 24 30 36

0
0 4 8 12 16
0 8 16 24 32 40 48 56 64

0
0 5 10 15 20 25
0 10 20 30 40 50 60 70 80 90 100

0
0 6 12 18 24 30 36
0 12 24 36 48 60 72 84 96 108 120 132 144

0
0 7 14 21 28 35 42 49
0 14 28 42 56 70 84 98 112 126 140 154 168 182 196

0
0 8 16 24 32 40 48 56 64
0 16 32 48 64 80 96 112 128 144 160 176 192 208 224 240 256

0
0 9 18 27 36 45 54 63 72 81
0 18 36 54 72 90 108 126 144 162 180 198 216 234 252 270 288 306 324

I could lose the aliases and just do everything long hand, but then you would have an entry for an obfuscation contest and not a reasonable piece of code.


Without Type Aliases

Included only for reference, the same code without the aliases. It should be readily apparent why, in this case, they actually help regarding clarity (and the only reason I would use them).

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

#define X_SIZE 3            // our fixed internal size

void foo(int *(*arr)[X_SIZE], int (*sizes)[X_SIZE], int num_arrays)
{
    int i, j, k;
    for (i = 0; i<num_arrays; i++)
    {
        for (j = 0; j<X_SIZE; j++)
        {
            sizes[i][j] = 1 + (i * j);
            arr[i][j] = malloc(sizeof(int) * sizes[i][j]);
            for (k = 0; k<sizes[i][j]; k++)
            {
                arr[i][j][k] = i * j * k;
            }
        }
    }
}

int main(int argc, char *argv[])
{
    static const int N = 10;

    int (*sizes)[X_SIZE] = calloc(N, sizeof *sizes);
    int *(*arr)[X_SIZE] = calloc(N, sizeof *arr);

    foo(arr, sizes, N);

    int i, j, k;
    for (i = 0; i<N; i++)
    {
        for (j = 0; j<X_SIZE; j++)
        {
            for (k = 0; k<sizes[i][j]; k++)
            {
                printf("%d ", arr[i][j][k]);
            }
            printf("\n");
        }
        printf("\n");
    }
    return 0;
}
WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • You say you venomously object to using this method. What would you prefer to do? Ultimately I need a dynamically decided multiple of 3 number of pointers, would it be better to just use: `int **arr = malloc(sizeof(*int) * X_SIZE * num)`? – CSStudent7782 Oct 14 '20 at 18:10
  • @CSStudent7782 Its actually the hiding of pointer types in typedefs that I so strongly object to. They rarely if ever add clarity, and often hide it instead. In this case it isn't pointer types being aliases, it's *array* types, and as such, i'd give it a pass. but when you see things like `typedef int * intp;` you'll discover it ultimately only makes the code harder, not easier, to read and manage. – WhozCraig Oct 14 '20 at 18:17