5

I have a function which expect a wchar_t**, I am allocating it:

wchar_t * * lFilterPatterns = malloc(aNumOfFilterPatterns*sizeof(wchar_t *));
for (i = 0; i < aNumOfFilterPatterns; i++)
{
    lFilterPatterns[i] = malloc(MAX_PATH_OR_CMD*sizeof(wchar_t));
}

is there a better/simpler way to make this allocation ?

edit: I would prefer to call malloc once only.

this has been proposed:

wchar_t (*lFilterPatterns)[MAX_PATH_OR_CMD] =
         malloc(aNumOfFilterPatterns * sizeof * lFilterPatterns);

but then the function complains: warning C4047: 'function' :

'wchar_t * *' differs in levels of indirection from 'wchar_t (*)[1024]'

can I cast 'wchar_t (*)[1024]' into 'wchar_t * *' ?

tinyfiledialogs
  • 1,111
  • 9
  • 18
  • 3
    What's wrong with this kind of allocation? – lost_in_the_source Jun 24 '16 at 13:04
  • 3
    You can just allocate the whole bunch by `malloc(aNumOfFilterPatterns*aNumOfFilterPatterns*sizeof(wchar_t))`. It will be faster and give you a contiguous memory region which is easier to work with. But if it is a big region, there is a risk it will fail. – Eugene Sh. Jun 24 '16 at 13:04
  • @EugeneSh. Your proposal might work well, but it involves some calculation for the starting addresses for the individual string which some might deem _not beautiful_. – Codor Jun 24 '16 at 13:06
  • http://c-faq.com/aryptr/dynmuldimary.html – melpomene Jun 24 '16 at 13:06
  • I haven't come across a better one in a case where **size of** `lFilterPatterns[i]` would be varying from member to member. With a fixed size of `MAX_PATH_OR_CMD` you may easily declare and allocate it as one-dimensional array, with proper pointers and counters. – user3078414 Jun 24 '16 at 13:07
  • @user3078414 If `MAX_PATH_OR_CMD` is fixed, you can do `wchar_t (*lFilterPatterns)[MAX_PATH_OR_CMD] = malloc(aNumOfFilterPatterns * sizeof *lFilterPatterns);` – melpomene Jun 24 '16 at 13:10
  • The dupe candidate linked to above has answers for using individual allocations as well as (scroll down a bit) solutions using a single chunk of memory. I think it should answer your question. – 5gon12eder Jun 24 '16 at 13:27
  • 4
    Most of the answers ignore the requirement to pass this array to a function that expects `wchar_t **` – M.M Jun 24 '16 at 13:55
  • `wchar_t **` is not an "array of arrays" (aka 2D array). A pointer is not an array. That's exactly what the message tells you. – too honest for this site Jun 24 '16 at 14:26

4 Answers4

2

If the function you are calling expects a wchar_t ** as a parameter, then no, there's really not a better way to do this.

John Bode
  • 119,563
  • 19
  • 122
  • 198
0

You could build one generic function by using void pointers. This one mallocs everything and frees all that is allocated if malloc would return NULL somewhere on the way.

void **alloc_2_dim(size_t ptrSize, size_t size, int n1, int n2)
{
    void ** p = malloc(n1 * ptrSize);

    if (p != NULL)
    {
        for (int i = 0; i < n1; i++)
        {
            p[i] = malloc(n2 * size);

            if (p[i] == NULL)
            {
                for (int j = i; j >= 0; j--)
                {
                    free(p[i]);
                }
                free(p);
                p = NULL;
                break;
            }
        }
    }

    return p;
}

Use it like this:

wchar_t **p = alloc_2_dim(sizeof(wchar_t *), sizeof(wchar_t), 10, MAX_PATH_OR_CMD);
char **p = alloc_2_dim(sizeof(char *), sizeof(char), 10, MAX_PATH_OR_CMD);

Playing with macros you can make it a little bit clearer by removing the sizeofs.

#define ALLOC_2D_CHAR(n1, n2) alloc_2_dim(sizeof(char *), sizeof(char), n1, n2)
#define ALLOC_2D_WCHAR(n1, n2) alloc_2_dim(sizeof(wchar_t *), sizeof(wchar_t), n1, n2)
Serve Laurijssen
  • 9,266
  • 5
  • 45
  • 98
0

There are 2 generally accepted methods of allocating 2D arrays in C: the contiguous method and the ragged method. Both methods have their advantages and disadvantages. For example, you can shuffle arrays made from the ragged approach, but not contiguous. On the other hand, it takes a loop to free the ragged, but only a quick 2 frees for contiguous.

Contiguous:

int** table = (int**)malloc(sizeof(int*)*rows);
int* data = (int*)malloc(sizeof(int)*rows*columns);
int i = 0;
for( i = 0; i < rows; i++ )
table[i] = &data[i*columns]

Freeing Contiguous:

free( table[0] );
free( table );

Ragged:

int** table = (int**)malloc(sizeof(int*)*rows);
int i = 0;
for( i = 0; i < rows; i++ )
    table[i] = (int*)malloc(sizeof(int)*columns);

Freeing Ragged:

  for( i = 0; i < rows; i++ )
        free( table[i] );

  free( table );
MacedonZero
  • 216
  • 1
  • 9
-1

You can just use a single dimention array , and then you can reach the [i,j] element with an index mappaing function:

The allocation for the single dimention array:

wchar_t * lFilterPatterns = malloc(aNumOfFilterPatterns*aNumOfFilterPatterns*sizeof( wchar_t));

The index retrievel function:

int GetElementIndex(int i, int j, int length)
{
     return i * length + j;
}

Usage:

lFilterPatterns[GetElementIndex(i,j,aNumOfFilterPatterns)] = 1;
Dr.Haimovitz
  • 1,568
  • 12
  • 16