0

How to create a pointer to the following 2D array pointer int **arr. I am looking for something similar to int*** arr and its allocation, deallocation, accessing and usage.

int main()
{
  int** arr;

  int row = 11;
  int col = 2;
  int i,j;

  arr = (int**)malloc(sizeof(int*)*row);
  for (i=0; i<row; ++i){
    arr[i] = (int*)malloc(sizeof(int)*col);
  }

  for (i = 0; i < row; i++) {
    for (j = 0; j < col; j++) {
        arr[i][j] = i;
        printf("arr[%d][%d] : %d\n",i,j,arr[i][j]);
    }
  }

  return 0;
}

Previous references:

Dynamic 2D array Pointer:

C programming initialize 2D array dynamically

Pointer to dynamic 2D array, But the explanation here is using new keyword and I want to use malloc instead:

How to allocate a 2D array of pointers in C++

Additional Info:

Consider following scenario:

XYZ* arr[A][B];

"XYZ" is a custom datatype, "A" & "B" are dynamic variables at runtime

In this case, how can we define A & B at runtime and access arr[A][B] element values using XYZ* type.

Community
  • 1
  • 1
Nagarjun
  • 75
  • 1
  • 10
  • For a pointer to `arr` you need to become a [three-star programmer](http://c2.com/cgi/wiki?ThreeStarProgrammer), and being called that is usually *not* a compliment. – Some programmer dude Sep 29 '16 at 07:45
  • What's a "dynamic array"? An array which is allocated in dynamic memory or an array that have variable dimensions that may change at any time? The correct answer depends a lot on which of these you want. – Lundin Sep 29 '16 at 07:45
  • 2
    In case you are merely looking to allocate a 2D array dynamically, then it should be `int (*arr)[row] = malloc(sizeof(int[col][row]));` And that's it. No pointer-to-pointer-to-pointer-to-pointers are needed... – Lundin Sep 29 '16 at 07:47
  • ***Why*** do you need a triple-star pointer? What is the *actual* problem you try to solve by using one? If you want a dynamic array of arrays (which a pointer-to-pointer [really isn't](http://stackoverflow.com/questions/18440205/casting-void-to-2d-array-of-int-c/18440456#18440456)) then you already have it. Why do you need to add another level of indirection? – Some programmer dude Sep 29 '16 at 08:45
  • Please find the added additional info in the question. – Nagarjun Sep 29 '16 at 10:24
  • I can completely imagine, that `(NodeClass***)malloc(sizeof(NodeClass)*row);` is kindof solving your problem, but you should understand the reason why it does so: you are probably allocating to much memory, so there is no access violation for the elements that you actually use. As long as all your cols have the same length, you shouldn't use multi dimension pointers at all. – grek40 Sep 30 '16 at 11:00
  • @grek40 Thank you for the explanation! My col value also varies. – Nagarjun Sep 30 '16 at 11:10
  • @Nagarjun then I'll edit my answer to account for that. Second please^^ – grek40 Sep 30 '16 at 11:13
  • Beware what you use is an array of pointers to arrays. It is definitely **not** a 2D array! – Serge Ballesta Sep 30 '16 at 11:19
  • @Nagarjun Edited my answer. – grek40 Sep 30 '16 at 11:30
  • [Please don't cast the return value of `malloc()` in C](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). – unwind Sep 30 '16 at 11:32

2 Answers2

1

Further down the answer, you find more possible solutions.

First, I want to present a solution to you, where you manage a dynamic 2d array with a 1d pointer, in case of same-length columns.

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

struct XYZ
{
    int someValue;
};

struct XYZ* GetArrayItem(struct XYZ* itemArray, int numCols, int row, int col)
{
    return &itemArray[row * numCols + col];
}

int main()
{
    int A = 5;
    int B = 4;
    struct XYZ* arr = (struct XYZ*)calloc(A*B, sizeof(struct XYZ));

    for (int i = 0; i < A; i++)
    {
        for (int j = 0; j < B; j++)
        {
            GetArrayItem(arr, B, i, j)->someValue = 1;
        }
    }

    free(arr);

    return 0;
}

With columns of different length, a double pointer might be a viable solution.

struct XYZ
{
    int someValue;
};

int main()
{
    int i;
    int j;
    // row count
    int A = 5;
    // column count per row
    int B[] = { 3, 4, 3, 2, 4 };
    struct XYZ** arr = (struct XYZ**)calloc(A, sizeof(struct XYZ*));
    for (i = 0; i < A; i++)
    {
        // initialize column for each row
        arr[i] = (struct XYZ*)calloc(B[i], sizeof(struct XYZ));
    }

    for (i = 0; i < A; i++)
    {
        for (j = 0; j < B[i]; j++)
        {
            // access items
            arr[i][j].someValue = 1;
        }
    }

    for (i = 0; i < A; i++)
    {
        free(arr[i]);
    }

    free(arr);

    return 0;
}

However, I would advise you to create a more explicit object structure in case where you need 2d data. This makes the design more explicit and the column count per row more transparent.

struct XYZ
{
    int someValue;
};

struct MyDomainSpecificRow
{
    int numColumns;
    struct XYZ* myRowData;
};

int main()
{
    int i;
    int j;
    // row count
    int A = 5;
    // column count per row
    int B[] = { 3, 4, 3, 2, 4 };
    // 1d array of rows, each containing 1d array of cells
    struct MyDomainSpecificRow* arr = (struct MyDomainSpecificRow*)calloc(A, sizeof(struct MyDomainSpecificRow));

    for (i = 0; i < A; i++)
    {
        // initialize column for each row
        arr[i].numColumns = B[i];
        arr[i].myRowData = (struct XYZ*)calloc(B[i], sizeof(struct XYZ));
    }

    for (i = 0; i < A; i++)
    {
        for (j = 0; j < arr[i].numColumns; j++)
        {
            // access items
            arr[i].myRowData[j].someValue = 1;
        }
    }

    for (i = 0; i < A; i++)
    {
        free(arr[i].myRowData);
    }

    free(arr);

    return 0;
}
grek40
  • 13,113
  • 1
  • 24
  • 50
0

Solution: At last, I managed to get what I was looking for.

Declaration:

NodeClass* currentNode;     //Single Pointer Declaration
NodeClass*** triplePtrNode; //Triple Pointer Declaration

Definition & Allocation:

//row, col are dynamic values at runtime

//row memory allocation
triplePtrNode = (NodeClass***)malloc(sizeof(NodeClass)*row); 
for (i=0; i<row; ++i){
    //col memory allocation
    triplePtrNode[i] = (NodeClass**)malloc(sizeof(NodeClass)*col); 
}

Usage:

for (i=0; i<memberCounts; ++i){
    *(*(triplePtrNode+i)+0) = currentNode->member1;
    *(*(triplePtrNode+i)+1) = currentNode->member2;
}
Nagarjun
  • 75
  • 1
  • 10
  • There is no correct usage of triple pointers in C or C++. They are only useful in the branch of tree star programming. Rather than trying to become a tree star programmer, you should focus on solving the actual problem. There's a very big chance that you have chosen the wrong solution for the task. – Lundin Sep 30 '16 at 11:06
  • Yes, I agree. I would like to add the following to your comment: _MISRA-C:2004 17.5 "The declaration of objects should contain no more than 2 levels of pointer indirection"_ _MISRA C++ 2008 5-0-19 The declaration of objects shall contain no more than two levels of pointer indirection._ – Nagarjun Sep 30 '16 at 11:28
  • 2D arrays using an array of pointers to 1D arrays are much less efficient than 1D arrays with some arithmetics to do proper indexing. There is also no guarantee that the memory will be layed out consecutively, which might be an issue as well. – G. Sliepen Sep 30 '16 at 11:42