2

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?

5
  • 1
    Both appear to do the same thing. The second is definitely more elegant. Commented Nov 21, 2013 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]; Commented Nov 21, 2013 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 **' Commented Nov 21, 2013 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? Commented Nov 21, 2013 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. Commented Nov 21, 2013 at 21:59

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

This is a great answer for the part you answer but the part of comparing the two approaches would be appreciated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.