Jump to content
  • Advertisement
Sign in to follow this  
ahayweh

C Allocation Issue...

This topic is 4523 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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[ i ] = (void*)malloc( sizeof((*pArray)) * xRows );
	}

	return sizeof(*pArray)*(xRows+yCols);
}


Here's hoping someone has run into this before, ahayweh

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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[ i ] = malloc( elementSize * xRow );
}

return pArray;
}



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...

Thanks,

ahayweh

Share this post


Link to post
Share on other sites
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*?

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!