Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I'm interested in different ways to allocate memory in the heap for bi-dimensional arrays.

It seems like the same notation is used when accessing pointers to pointers and pointers to arrays of one or several dimensions. I was hoping to have someone clarify the difference and the usefulness of each. Are they both right?

This first way would be storing the array as a pointer to pointer:

char **createTable(int r, int c) {
    char **table;
    int i;
    char *offset;
    table = malloc(r * sizeof (char *) + r * c * sizeof (char));
    if (!table) return NULL;
    offset = (char *) table + sizeof (char *) * r;
    for (i = 0; i < r; i++) {
        table[i] = offset + c * i;
    }
    return table;
}

This other way seems faster. I can't think of a good way to wrap it in a function like the other one.

char (*table)[c];
table = (char (*)[c]) calloc(r * c, sizeof (char));

Am I right in understanding that even though arrays are like static pointers, arrays have the ability to have several dimensions in themselves?

Is it true that the first way I describe is the orthodox way?

share|improve this question
1  
Both appear to do the same thing. The second is definitely more elegant. –  Fiddling Bits Nov 21 '13 at 21:01
    
Why not just do char table[r][c]? I guess your intention is that is will be possible to return the pointer from the function that allocates it? It might be useful to make this clear in the question so we know why you're not just doing char table[r][c]; –  Aaron McDaid Nov 21 '13 at 21:11
    
To be more specific: You can't return table, where table is char (*table)[c]; from a function that returns char**. Clang: incompatible pointer types returning 'char (*)[c]' from a function with result type 'char **' –  Aaron McDaid Nov 21 '13 at 21:12
    
I made an edition to say that I'm interested in using dynamic allocation, so I understand I can't use a normal array. To the second comment I can see the prototype wouldn't be char** but I don't know how to return it with it's own type or even return it via a return argument. Even if longer the first option has a simpler type as far as syntax complexity, what do you think? –  niic Nov 21 '13 at 21:25
    
Your first method is the technique I use to make dynamic multi-dimensional arrays. Just be careful with your alignment if using non-char types. Also, note that offset = (char *)(table + r) is cleaner. –  paddy Nov 21 '13 at 21:59
add comment

1 Answer

up vote 1 down vote accepted

Unfortunately there seems no way to have a function return a pointer to variable length array that would be properly typed. You could go for a trick like this:

#include <stddef.h>
#include <stdlib.h>

void* createTable_(size_t r, size_t c) {
  char (*table)[c] = malloc(sizeof(char[r][c]));
  /* do the intialization that you need */
  return table;
}

#define createTable(R, C) ((char(*)[C])createTable_((R), (C)))

int main(int argc, char*argv[]) {
  char (*table)[argc] = createTable(argc, argc);
}

The function just returns a void* pointer and the macro ensures the correct typing. Unfortunately such a macro has to evaluate the second argument twice, so be careful with side effects.

Edit, for the other sub-questions that you ask:

I wouldn't call the pointer to pointer way of emulating multi-dimensional matrices "orthodox", just out-dated. At least it is so for the most usages that I have seen for it.

  • It is error prone. You really have to get all index computations right. BTW there also you could get something more readable by using sizeof on arrays, something like

    malloc(sizeof (char*[r]) + sizeof (char[r][c]))

  • It wastes space, the sizeof(char*[c]) part

  • It is less efficient, instead of simple index calculations it has to do an additional indirection.

  • It is incompatible with other languages that use a lot of matrices, such as Fortran.

share|improve this answer
    
This is a great answer for the part you answer but the part of comparing the two approaches would be appreciated. –  niic Nov 23 '13 at 3:34
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.