C Allocation Issue...

Started by
5 comments, last by ahayweh 17 years, 9 months ago
Hello all, First post ( other than RE ), Ran into a quick problem that causes crashes : How would you allocate an multidimensional array using malloc? Here is the offending source :

/*
** Util routine. Allocates an arbitrarily sized 2D array.
*/
static int GL_Allocate2DArray( void** pArray , int xRows , int yCols )
{
	pArray = (void**)malloc( sizeof( pArray ) );
       *pArray = (void*)malloc( sizeof(*pArray) * yCols ); 

	for( int i=0; i < xRows; i++ )
	{
		pArray = (<span class="cpp-keyword">void</span>*)malloc( <span class="cpp-keyword">sizeof</span>((*pArray)) * xRows );
	}

	<span class="cpp-keyword">return</span> <span class="cpp-keyword">sizeof</span>(*pArray)*(xRows+yCols);
}


</pre></div><!–ENDSCRIPT–>

    Here's hoping someone has run into this before, 

    ahayweh
Advertisement
static int GL_Allocate2DArray( void** pArray , int xRows , int yCols ){  // assuming a row-major structure  //  pArray = (void**)malloc(xRows * sizeof(void*));  // then allocate the column space in each row  //  for (int i = 0; i < xRows; ++i)  {    // because you failed to indicate what the actual type contained in     // pArray is, i'm just assuming it's unsigned char. you can not allocate     // a 'void'    //    pArray = malloc(yCols * sizeof(unsigned char));  }  // to compute the total amount of memory allocated, not including pointers   // for address space:  //  return (xRows * yCols * sizeof(unsigned char));}


Now for the commentary:
  1. The above is not a multidimensional array. It is impossible to dynamically allocate a multidimensional array in C or C++ whilst preserving the access semantics and use of the subscript operator, operator[]. The closest workaround, aside from the above (which is actually an array of arrays - which is not the same thing!), is to allocate one array whose length is equal to the product of the desired array dimensions, then use a common formula for element access:

    pArray = (unsigned char *) malloc (xRows * yCols * sizeof(unsigned char));...pArray[coord(x, y)];

    where coord(m, n) is defined as follows:

    unsigned int coord(int m, int n){  return n * array_width + m; // row-major  // column major: m * array_height + n;}


  2. You can not allocate a void. You can allocate a pointer to it, but not the type itself - just as you can not declare a variable of type void.


  3. You need to review your understanding of arrays, pointers and malloc, as your code contains some grevious errors. In particular, the following bits of code:
    *pArray = (void*)malloc( sizeof(*pArray) * yCols ); ... sizeof(*pArray) ...

Hope that helped.
Ok thanks man,

I definitely need to do some more research w/pointers and the like. I guess my logic with the (*ptr), was that if I dereferenced a pointer to a pointer, I get the original pointer... Thank again for the input,

ahayweh
I am not sure if anyone is watchnig this thread, but after sucessfully allocating an array of arrays, I still can't access the array elements as desired: Code changed to allow for passizng sizeof(var_type) :

[source lang='c']static void* GL_Allocate2DArray( void** pArray , int elementSize , int xRow , int yCol ){	pArray = (void**)malloc( sizeof(void*) * yCol ); 	for( int i=0; i < yCol; i++ )	{		pArray = malloc( elementSize * xRow );<br>	}<br><br>	<span class="cpp-keyword">return</span> pArray;<br>}<br><br></pre></div><!–ENDSCRIPT–><br><br>trying to access element using pArray[x][y] causes access fault. I can acess the each array using pArray[ index ]. Do I need to dereference starting this way? I am hoping to find a 'clean' way of doing this… <br><br>Thanks, <br><br>ahayweh
Why are you accepting a parameter that you never read and don't use as an out-parameter?

Why are you allocating a void** and returning it as a void*?
You are making an array of pointers, and then pointing them to other arrays. That way doesn't guarantee the memory will be all in one chunk like a normal array. I'm not entirely sure, but because your code is failing, it appears that double subscript operators might first add up the offsets of each and then add them to the base pointer. With your current code, that would most likely be an address that is not anywhere you want it to be.

One way I was thinking was just allocating all the memory you need, then you have to cast the pointer to a pointer to an array, and then the subscribting should work like a regular C 2D array. Here is what I came up with, it seems to be working.

#include <stdio.h>#include <stdlib.h>void *create_2Darray(int element_size, int rows, int columns){    /* While creating, just worry about allocating enough space       To get the subscript operator working, the pointer will have       to be casted correctly. */    void *bob = malloc( element_size * rows * columns);    return bob;}int main(void){    int i, j;    int COLUMNS = 5;    int ROWS = 6;    /* I am making a 2D array of 6 rows by 5 columns. So I cast my       pointer to a pointer to an array of 5 ints. So, when I use       array[n][m], my array should offset to the correct row by counting       off n*5 ints, and then offset from there to the correct column by       counting off m ints.    */    // This pointer is a pointer to a variable-length array. Needs C99 to work.    int (*array)[COLUMNS] = create_2Darray( sizeof(int),ROWS,COLUMNS );    for( i = 0; i < ROWS; i++)    {        for(j = 0; j < COLUMNS; j++)        {            array[j] = i+j;        }    }        for( i = 0; i < ROWS; i++)    {        for(j = 0; j < COLUMNS; j++)        {            printf("%d, %d: %d\n", i, j, array[j]);        }    }    return 0;}


Edit: Well, I think the requirement from my code to make a pointer to an array of specific size kind of defeats the point of dynamically allocating the array. I just read Oluseyi's post, you can use one of the functions he was talking about instead.

Edit 2: Well, I guess if you are using C99 you could use variable length arrays, and then it should work fine. I changed my code to use that.

[Edited by - nicksterdomus on June 25, 2006 10:55:51 PM]
Thanks again everyone for your help,

After doing some more research, reading everyones input, I scapped the old code, and wrote it from the ground up. Everything is going smoothly now, so I can focus on coding some more interesting now.

Thanks again,
ahayweh

This topic is closed to new replies.

Advertisement