3

I am getting super confused with dynamic memory allocation and deletion of a 2D array of pointers.

The goal is to have a 2D array in which each cell has a pointer to a linked list. This is what I am doing, and I don't see any errors but few warnings.

Warnings :

1)

a value of type queue ** cannot be used to initialize an entity of type queue ***
queue* (**table) = (queue**)malloc(sizeof(queue*)*3);

2)

a value of type queue * cannot be assigned to an entity of type queue **
    table[indexI] = (queue*)malloc(sizeof(queue*)*3);

3)

a value of type queue ** cannot be assigned to an entity of type queue ***
  if( !(table = allocate()) ) {

Here is the code:

queue **allocate() {

    queue* (**table) = (queue**)malloc(sizeof(queue*)*3);
    // Warning #1 at above line 
    for(.....) {

    table[index] = (queue*)malloc(sizeof(queue*)*3);
    // Warning #2 at above line. 
    }

    for(I index - 0 to 3) {
    for(J index - 0 to 3) {

    table[I][J] = NULL;

    }
    }
    return((queue**)table);
   }

    void deallocate(queue* **table) {


    // will handle list deletion
    // next deallocate table

    for(....) {
    free(table[index]);
    }
    free(table);

   }

void
add_list_to_queue(queue ***table) {

// here I create a list of queue type and assign it to
// those cells

}

modify_table() {

    queue* (**table) = NULL;

    table = allocate();
// Warning #3 at above line
.
.
.
    add_list_to_queue(table);

// do de allocation of table, list etc.,

    deallocate(table);

}

I have confusion in these areas

  1. I am not sure if my declaration of 2D array of pointers is correct
  2. How can I pass around this 2D array of pointers
Beryllium
  • 12,808
  • 10
  • 56
  • 86
navoriion
  • 33
  • 3
  • 1
    Why not `queue *(*arr)[COLUMNS] = malloc(sizeof(*arr) * ROWS);`? –  Aug 04 '13 at 10:19
  • queue *(*arr)[COLUMNS] - I think memory for columns would be allocated on stack ? – navoriion Aug 04 '13 at 10:21
  • @userXXX When you are (I am) using `malloc()`? No way. –  Aug 04 '13 at 10:22
  • Please format your code in the question correctly as code - have a look at the SO docs to see how (e.g. indentation by four spaces of all lines that belong to a code block). Also, mention facts such as the "coding language" by adding tags to your question. – O. R. Mapper Aug 04 '13 at 10:23
  • @H2CO3 What would happen if we declare queue *(*arr)[COLUMNS] ? – navoriion Aug 04 '13 at 10:29
  • @navoriion Then you will have an uninitialized variable called `arr` which is a pointer to array of COLUMNS pointers to `queue`. –  Aug 04 '13 at 10:31
  • @H2CO3 I am not able to visualize how this memory allocation would look like. Can you please post some diagram ? – navoriion Aug 04 '13 at 10:39
  • @navoriion I don't understand what you don't understand. You declare `arr` which is a pointer-to-array. You then assign to it the return value of `malloc()` which points to an appropriately-sized memory chunk, i. e. one that is large enough to hold `sizeof (queue *) * ROWS * COLUMNS` bytes (that's the purpose of `sizeof(*arr) * COLUMNS`, after all...) –  Aug 04 '13 at 10:42
  • @H2CO3 Ok thanks, but is there anything wrong with my code snippet above ? – navoriion Aug 04 '13 at 10:55

2 Answers2

2

The first warning is because the parentheses make no difference in the LHS of your expression

queue* (**table) = (queue**)malloc(sizeof(queue*)*3);

table is simply a three-level pointer to a queue. But malloc returns a pointer to a block of memory that can hold three pointers to queue, so you're allocating a two-level pointer to a queue.

Since table is a three-level pointer, table[indexI] is a two-level pointer. But you're inconsistent on the RHS of the expression:

table[indexI] = (queue*)malloc(sizeof(queue*)*3);

malloc is again returning a pointer to a block of memory that can hold three pointers to queue (i.e., malloc is returning a two-level pointer) but you're casting it as a one-level pointer, then assigning it to a two-level pointer.

As for the third warning, you've defined allocate() as returning a pointer to a pointer to a queue, but you're trying to assign it to table. As explained above, table is a three-level pointer, but allocate() returns only a two-level pointer.

But really, multiple levels of pointer indirection isn't what you need here. Keep it simple. What do you need? A pointer to rows, each row containing pointers to queue. That's what H2CO3's suggestion in his comment gives you:

queue *(*arr)[COLUMNS] = malloc(sizeof(*arr) * ROWS);

arr is a pointer to an array of ROWS, each row containing COLUMNS pointers to queue.

Edit: To pass this around to different functions as you asked in the comments, first declare and initialize the pointer:

queue* (*arr) [COLUMNS] = NULL;

Then to allocate memory, remember that you need to change what the pointer is pointing to. So you have to pass a pointer to the pointer. Your function prototype should be:

void allocate (queue* (**arr) [COLUMNS]);  // Note the (**arr)

The function call should be:

allocate (&arr);

(To make pointer indirection easier, you might want to declare and initialize a different pointer-to-array inside allocate() using the format first suggested by H2CO3 which I explained above, then assign that pointer to *arr.)

Remember that you have to allocate memory not just for the pointer to the 2D array, but also for each element inside the array, since that element is an uninitialized pointer. You can do this using a nested loop in allocate() or, if it is more logical given your data structures, in fill_table().

For fill_table(), you can simply pass the pointer-to-array itself. The prototype will be:

void fill_table (queue* (*arr) [COLUMNS]);

and the call:

fill_table (arr);

Hope this helps. The easiest way to do things might be to do everything inside process() to begin with, then see how you can separate the allocation and filling parts out into their own functions.

verbose
  • 7,827
  • 1
  • 25
  • 40
  • Thanks verbose, how do I deallocate memory for this queue *(*arr)[COLUMNS] = malloc(sizeof(*arr) * ROWS); – navoriion Aug 04 '13 at 19:14
  • First, you need to walk the array and free the memory allocated for each queue, using a nested loop: `for (int i = 0, i < ROWS, i++) for (int j = 0, j < COLUMNS, j++) free (arr[i][j]);` Once you've done that, free memory allocated for the entire array: `free (*arr);` – verbose Aug 04 '13 at 19:49
  • Ok, I understood this. How do I pass around this queue *(*arr)[COLUMNS]and return. So, I have three functions process(), allocate, fill_table(). I call allocate and fill_table in process. Allocate as name suggests would allocate memory for this array, which later is sent to fill_table(), to fill this table with queues. I tried to send this array in various ways but I get warnings and errors like error: expression must have pointer-to-object type, return value type does not match the function type, argument of type "queue *" is incompatible with parameter of type "queue *(*)[COL] – navoriion Aug 04 '13 at 21:07
  • (I saw your previous comment saying the answer to my previous question is too long ) Should I start a new thread for this question ? – navoriion Aug 04 '13 at 22:40
  • There have been lots of questions asked on StackOverflow about how to pass multidimensional arrays between functions; you might want to research those before posting. If you still have questions after reading those, be sure to ask as specific a question as possible. I am a bit busy at the moment with something else, sorry. – verbose Aug 04 '13 at 23:13
  • Here is a question that addresses your issue: http://stackoverflow.com/questions/4152837/passing-2d-array-of-pointer-to-function-c. – verbose Aug 04 '13 at 23:29
0

1) your first error (queue* (**table)) is that you don't have a 2D array here, but a 3D array, your line can be write like that : queue ***table. So, you just have to remove a star an you will declare a 2D array pointer.

2) with the first response, i think you will not have this warning anymore

3) This error is like the first, you juste have to remove a star.

Kevin L.
  • 17
  • 1