• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 789
  • Last Modified:

declare/define a two D array dynamically and destroy it afere using

It may be simple, but can you tell me how to ?
I want to use double or similar precision 2 D array.
0
learn
Asked:
learn
  • 17
  • 11
  • 6
  • +2
3 Solutions
 
Kent OlsenData Warehouse Architect / DBACommented:
Hi learn,

int **Array2D;
int XSize = 10;   // Width of the array
int YSize;= 100; // Length of the array;
int idx;

  Array2D = (int **) malloc (sizeof (int*) * YSize;   // Allocate the base array

  // Now loop through the array assigning memory for each row of the array.  (malloc size is sizeof (int) * XSize).


To Destroy the array, free() each of the rows then the base array.


Good Luck!
Kent
0
 
AxterCommented:
Hi learn,
Check out the following code:
http://code.axter.com/allocate2darray.h
http://code.axter.com/allocate2darray.c

David Maisonave (Axter)
Cheers!
0
 
AxterCommented:
Example usage:
#include "allocate2darray.h"

double **My2D_double = ALLOCATE2DARRAY(double, x, y);

//Now to free it
Free2DArray(My2D_double);

The above method is more efficient because only two calls are made to malloc and when you free it, only two calls are made to free.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
PaulCaswellCommented:
David,

Nice code! Very neat! Only problem (rare and unlikely) is that if ppi allocates but pool allocation fails you'll leak the ppi block but that's no criticism!

Paul
0
 
AxterCommented:
>>Nice code! Very neat! Only problem (rare and unlikely) is that if ppi allocates but pool allocation fails you'll leak the ppi block but that's no criticism!

Ahhhh!
Good catch.  No matter how good you *think* you are, it always helps to have an extra pair of eyes.

I just updated the code.
Thanks
0
 
Kent OlsenData Warehouse Architect / DBACommented:
Hi Axter, Paul,

I was thinking that this was too close to being a homework question for complete code.  Guess everyone didn't see it that way.  :)



Kent
0
 
AxterCommented:
>>I was thinking that this was too close to being a homework question for complete code.

Looking at the questioner's history, it doesn't look like a homework question.
90% time when it's a homework question, it's posted by a newbie, and usually it's the first question asked.

I usually give questioners that have been EE members for over 3 years, the benefit of the doubt.

This questioner has been an EE member longer than I have.....
0
 
AxterCommented:
Actually, he's been an EE member longer than all of us!!!
0
 
Kent OlsenData Warehouse Architect / DBACommented:
Hi Axter,

   :)


Kent
0
 
learnAuthor Commented:
Hi,

Thanks a lot for all of you!

I declare that this is not a home work.

I know C before but forgot all of them. I think I should answer some questions in other languages so that you believe me.

OK, I am going to read your suggestions and links.
0
 
PaulCaswellCommented:
Hi learn! Glad to meet you!

Hi Kent! You mean:

>>Array2D = (int **) malloc (sizeof (int*) * YSize;   // Allocate the base array

Was a giveaway newbie code example? :-) The missing bracket was a dead geveaway was it? ;-)

Nah! Just kidding! Not many students get to 2D and pointers to pointers nowadays, but good point! I should have been the one to ask! :-(

HI David!

Could you post the code here please, just for completeness, now its perfect :-) Thanks!

Thanks.

Have a good weekend all!

Paul
0
 
AxterCommented:
Sure.

/* allocate2darray.h */
#ifndef ALLOCATE2DARRAY_H_HEADER_GUARD_
#define ALLOCATE2DARRAY_H_HEADER_GUARD_

#define ALLOCATE2DARRAY(Type, x, y) (Type**)Allocate2DArray(sizeof(Type), x, y)

void **Allocate2DArray(int TypeSize, int x, int y);
void Free2DArray(void ** Array);

#endif //!ALLOCATE2DARRAY_H_HEADER_GUARD_


/* allocate2darray.c */
#include <stdlib.h>

void **Allocate2DArray(int TypeSize, int x, int y)
{
      void **ppi            = malloc(x*sizeof(void*));
      void *pool            = malloc(x*y*TypeSize);
      unsigned char *curPtr = pool;
      int i;
      if (!ppi || !pool)
      {  /* Quit if either allocation failed */
            if (ppi) free(ppi);
            if (pool) free(pool);
            return NULL;
      }

      for(i = 0; i < x; i++)
      {
            *(ppi + i) = curPtr;
            curPtr += y*TypeSize;
      }
      return ppi;
}

void Free2DArray(void ** Array)
{
      free(*Array);
      free(Array);
}
0
 
PaulCaswellCommented:
Excellent!

My only suggestionwould be:

         *(ppi + i) = curPtr;
 
becomes:

         ppi[i] = curPtr;

'cause I dont like faking array access but thats only a personal thing. :-)

and, of course:

    free(*Array);
     free(Array);

would be safer as:

    if (Array)
    {
     if (*Array) free(*Array);
    free(Array);
    }

you could then use:

    if (!ppi || !pool)
     {  /* Quit if either allocation failed */
        Free2DArray(ppi);

but that's just polish!
 
Paul
0
 
AxterCommented:
>>you could then use:
>>
>>    if (!ppi || !pool)
>>     {  /* Quit if either allocation failed */
>>        Free2DArray(ppi);

That's a good idea.
0
 
learnAuthor Commented:
I also made my own version :) and got no error!
Can you check my code:

#include <stdlib.h>

int main()
{
      int xSize=10, ySize=10, i;
      double **array2D = (double **) malloc (sizeof (double *) * ySize);
      for (i=0; i<xSize; i++)
      {
            *array2D = (double *) malloc (sizeof (double) * xSize);
      }

      for (i=0; i<xSize; i++)
      {      
      free(array2D[i]);
      }
      free (array2D);

      return 0;
}

There are 3 problems:

1. Why I cannot replace       
int xSize=10, ySize=10, i;
by
      int xSize, ySize, i;
      xSize = 10;
      ySize=10;
I need that way because I will read xSize and ySize from file or keyboard.

2. In
*array2D = (double *) malloc (sizeof (double) * xSize);
what the function malloc returns? Why we need (double *) before it?

3. Axter's code for free is simpler than mine :) Why not follow the inverse way of allocation to do free
      for (i=0; i<xSize; i++)
      {      
      free(array2D[i]);
      }
      free (array2D);

 
0
 
AxterCommented:
However, what would be the chances of ppi failing, but pool succeeding?

I'm not sure if that is possible.
0
 
AxterCommented:
>>I also made my own version :) and got no error!

Your version has to make many calls to malloc.
If you look at my code, you'll see that it only makes two calls to malloc.
In the second malloc call, it creates a single memory pool that is than distributed to the pointers.

>>what the function malloc returns? Why we need (double *) before it?
If you compile in a *.c file, you don't need to cast it, but if you compile in a *.cpp file or a C++ compiler, than you'll need the type casting, because C++ has strict type casting rules.

>>Axter's code for free is simpler than mine :) Why not follow the inverse way of allocation to do free
The reason my code is simpler, is because the allocation is simpler.
0
 
AxterCommented:
>>>>Axter's code for free is simpler than mine :) Why not follow the inverse way of allocation to do free

FYI:
Code that requires more malloc and free calls are not only less efficient, but it's also more prone to memory leaks.
In general, you want to limited malloc calls as much as possible.
0
 
PaulCaswellCommented:
Hmm... but then the code should become:

void **Allocate2DArray(int TypeSize, int x, int y)
{
     void **ppi          = malloc(x*sizeof(void*));
     if ( ppi )
     {
       if ( ppi[0] = malloc(x*y*TypeSize) )
       {
        unsigned char *curPtr = ppi[0];
        int i;
        // Could start i at 1 here but no need really.
        for(i = 0; i < x; i++)
        {
             ppi[i] = curPtr;
             curPtr += y*TypeSize;
        }
       }
       else
       {
       // Inner allocation failed.
       free(ppi);
       ppi = NULL;
       }
     }
     return ppi;
}

Isnt it strange how defensive coding always seems to force you to minimise processing time and correctly structure? This version avoids the pointless second malloc if the first fails and uses one less stack variable! We could skip the first assignment in the loop by starting 'i' at 1 but in my opinion that starts making the code messy.

Sorry to be pedantic! No criticism intended :-)

Paul
0
 
AxterCommented:
The above code will not compile on a *.c compiler, since you need to declare all the variables on the start of the function.

I'm not sure if this is specific to old C standard, or if it's part of the current C standard.
0
 
AxterCommented:
FYI:
That's one thing I really hate when using a C compiler.  I prefer just in time variable declarations.
I know a lot of old C programmers prefer to declare everything at the top, and no matter what you say to them, they will not see the benifit of declaring them close to where you first use them.

Sorry for going OT......
0
 
learnAuthor Commented:
Axter,

Thank you.
However,  I cannot allocate the array before I read xSize and ySize from file or keyboard.
0
 
PaulCaswellCommented:
>>However, what would be the chances of ppi failing, but pool succeeding?
None! But ppi could succeed while pool then failed couldnt it? pool is likely to be significantly larger.

>>1. Why I cannot replace      
...
Because you then go on to declare double** Array2D which you cant do in C without a { before it. Add a { before the Array allocation and it should work, but better still, make the array allocation a separate function and the problem solves itself.

The essential difference between yours and David's is that you allocate each column separately while Davids allocates one block of data for the whole content of the array and then parcels it out by pointing the index into parts of it. There are some minor downsides to this but overall its quicker and more efficient.

The minor downside with David's method is that if you accidentally walk off the end of one column you only corrupt the start of the next. - With yours, this could be caught by some debuggers automatically because you would be writing to free memory which can be detectable.

Paul
0
 
AxterCommented:
>>However,  I cannot allocate the array before I read xSize and ySize from file or keyboard.

I'm not sure what you're trying to say here.
Are you having problems with the code using logic that pulls the size at runtime?
0
 
PaulCaswellCommented:
>>I prefer just in time variable declarations.
I totally agree! It makes pulling code out into a function so much easier and its more stable to enhancements.

Paul
0
 
AxterCommented:
>>and, of course:
>> free(*Array);
>> free(Array);
>>would be safer as:
>>if (Array)
>>{
>>if (*Array) free(*Array);
>>free(Array);
>>}

FYI:
IAW C standard, you can call free with a NULL value.
So the free function can look like this:

void Free2DArray(void ** Array)
{
     if (Array) free(*Array);
     free(Array);
}

Above code should be safe, even if NULL.
0
 
learnAuthor Commented:
PaulCaswell,

Thanks a lot. You are right. It works:
int xSize, ySize, i;      double **array2D;
xSize=10; ySize=10;
array2D = (double **) malloc (sizeof (double *) * ySize);
0
 
AxterCommented:
>>int xSize, ySize, i;     double **array2D;

I recommend you initialize your pointer to NULL.
double **array2D = NULL;
0
 
PaulCaswellCommented:
>>IAW C standard, you can call free with a NULL value.
Good point! I keep forgetting this! I work with about 5 different C compilers at work! I think the oldest dates back to the 70's (MS C 6.0) and would definitely cause a bang if you tried to free NULL.

Paul
0
 
learnAuthor Commented:
Axter,

I was doing wrong.....Now it is fine.
0
 
PaulCaswellCommented:
Good luck learn! Come back again whenever you like!

Sorry we hijacked your question with our idle chatter. We'll try to focus better next time. It IS friday night however! :-)

Paul
0
 
learnAuthor Commented:
Thanks a lot again for all your helps!
0
 
leisnerCommented:
e 70's (MS C 6.0)

This is truly an old C compiler -- didn't know ms made C compiler in the 70s ;-)

0
 
PaulCaswellCommented:
Oops! A about a decade out! Its (C) 1984-90 but its still ancient! 128 caracter limit on the command-line! No debugger! Pretty unhelpful!

Paul
0
 
AxterCommented:
>>A about a decade out! Its (C) 1984-90 but its still ancient! 128 caracter limit on the command-line! No debugger!

I had to use this compiler about 3 years ago, and it's limitations broght back some painfull memories of programming in the 80's.
I created the following logging code just to debug the code:
http://code.axter.com/debuglog.h
http://code.axter.com/debuglog.c

This compiler support cross-compiling to OS2, and the above code was used on OS2, but I'm pretty sure it will also work for DOS.
0
 
PaulCaswellCommented:
Thanks David!

I've been working with it for 7 years now and I've got buckets of stuff I use for all sorts of things, including debug logging etc. but thanks for the thoughts.

I eventually wrote a tool that replaced CL.EXE under Visual Studio 6 so it detects which compiler I want it to use from environment variables and translates the command-line parameters into the correct form for it (and 3 other compilers I have to use) before launching it. It means I have full browse features and SourceSafe integration for all my development.

Paul
0
 
AxterCommented:
>>I eventually wrote a tool that replaced CL.EXE under Visual Studio 6.

I did the same exact thing for the project I was working on.
Makes me wonder how many times we developers reinvent the wheel...??? :-)
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 17
  • 11
  • 6
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now