Jump to content
  • Advertisement
Sign in to follow this  
DrTwox

realloc a pointer to a pointer

This topic is 3592 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

Hi all. I'm trying to rewrite three similar functions into one generic function. Currently I have something like this that works: (Retyped to summarise, not the full code!)
#define GROWSIZE 100
#define SQL_MAX_QUERY_SIZE 1024

/* This struct is mostly pointless now. I'm fixing a few other bits of code before I do away with it. */
typedef struct {
    unsigned char *string;
} SQL_TRANSACTION;

/* For good or bad, these are global */
SQL_TRANSACTION *SQL_inserts = NULL;
unsigned int numInserts = 0;
unsigned int numInsertsAllocated = 0;

SQL_TRANSACTION *SQL_updates = NULL;
unsigned int numUpdates = 0;
unsigned int numUpdatesAllocated = 0;

SQL_TRANSACTION *SQL_deletes = NULL;
unsigned int numDeletes = 0;
unsigned int numDeletesAllocated = 0;
....


Each SQL_TRANSACTION type has a function like this:
/* Add *string to the inserts array */
void SQL_Addto_Inserts(SQL_TRANSACTION *trans) {
  if (numInserts == numInsertsAllocated) {
    /* Increase the allocations */
    numInsertsAllocated += GROWSIZE;
  
    /* I know the return pointer shouldn't be the same pointer passed to realloc, but for now this works and will do! */
    SQL_inserts = (SQL_TRANSACTION*) realloc(SQL_inserts, (SQL_MAX_QUERY_SIZE * numInsertsAllocated));
    if (SQL_inserts == NULL) {
      printf("realloc failed\n");
      exit(1);
    }
  }
  
  /* More code to format the trans->string and 
  memcpy it to SQL_inserts[numInserts] */
  
  ++numInserts;
}



Everything works well like it is, but I want to replace the three functions with one generic function, but I can't work out how to point to the correct array to work with. I have something similar to this:
....
/* Transaction types */
#define SQL_UPDATE 1
#define SQL_INSERT 2
#define SQL_DELETE 3
....
/* transType is one of the above transaction types, passed by the calling function */
void SQL_Addto_Array(unsigned int transType, SQL_TRANSACTION *trans) {
  SQL_TRANSACTION **array = NULL; /* Is it correct to use the double ** notation for what I'm trying to do? */
  unsigned int *num = NULL;
  unsigned int *allocated = NULL;

  switch (transType) {
    case SQL_UPDATE:
      /* Point the pointers to the correct places */
      num = &numInserts;
      allocated = &numInsertsAllocated;
      array = &SQL_inserts; /* Is this incorrect? */
      break;
    case SQL_INSERT:
    ....
    /* Code for the other types */
    ....
  } /* End switch */
  
  if (*num == *allocated) {
    *allocated += SQL_GROWSIZE;
    
    array = (SQL_TRANSACTION*) realloc(array, (SQL_MAX_QUERY_SIZE * (*allocated))); /* I'm fairly certain this is wrong too! */
    if (array == NULL) {
      printf("realloc failed\n");
      exit(1);
    }
  }

  /* More code to format the trans->string */

  /* How do I memcpy trans->string now? */
  memcpy(array[*num], trans->string, strlen(trans->string)+1); /* Will probably explode the program! (The +1 is to copy the \0 byte) */
    
  ++(*num);
}


The above attempt crashes with... *** glibc detected *** ./wiimpdb.x86: realloc(): invalid pointer: 0x080f29f0 *** ... and anything else I've tried has similar results. I don't really understand the use of pointers to pointers, and reading the docs/tutorials I've found online has just confused me more. Whats the correct way to point the array pointer to where it needs to point, and how do I realloc the pointer it points to? *head explodes* [dead] [Edited by - DrTwox on August 16, 2008 12:05:47 AM]

Share this post


Link to post
Share on other sites
Advertisement
Hey, I'm not sure I have a solution to your problem, but I looked over your code and suggest you look at how you use pointers..

why are 'num' and 'allocated' pointers? Everytime you use them you have to reference (&) them, and I can't see anywhere you actually use their pointed value.

like

unsigned int *num = NULL;
unsigned int *allocated = NULL;

could just be

unsigned int num = 0;
unsigned int allocated = 0;

and then you wouldn't have to reference/dereference them all the time.

e.g.
if (*num == *allocated)
becomes
if( num == allocated)

this should make things simpler at least..

i think the line where you typecast the result of realloc(..) is the problem. Your forcing the result to become a pointer - to a pointer, when it really isn't - because you've declared it as array**. Try declaring 'array' as just a single pointer.

Also SQL_TRANSACTION is already a pointer to a struct, so in your function declaration

SQL_Addto_Array(unsigned int transType, SQL_TRANSACTION *trans)

it could just be

SQL_Addto_Array(unsigned int transType, SQL_TRANSACTION trans)

hope this helps..

Share this post


Link to post
Share on other sites
Regarding the realloc:


// the original
array = (SQL_TRANSACTION*) realloc(array, (SQL_MAX_QUERY_SIZE * (*allocated))); /* I'm fairly certain this is wrong too! */

// this should work now
*array = (SQL_TRANSACTION*) realloc(*array, (SQL_MAX_QUERY_SIZE * (*allocated)));



i.e. reallocate where the "array" actually points to

Share this post


Link to post
Share on other sites
Quote:
Original post by supamike
why are 'num' and 'allocated' pointers? Everytime you use them you have to reference (&) them, and I can't see anywhere you actually use their pointed value.

In the (switch) statement:
num = &numInserts;
allocated = &numInsertsAllocated;

Depending on the transType value they could also point to numUpdates and numUpdatesAllocated or numDeletes and numDeletesAllocated. If I want to add another transaction array, they would point the appropriate values for it too.
Quote:

i think the line where you typecast the result of realloc(..) is the problem. Your forcing the result to become a pointer - to a pointer, when it really isn't - because you've declared it as array**. Try declaring 'array' as just a single pointer.

In the working code with the three separate functions for each array, SQL_inserts, SQL_updates or SQL_deletes, the realloc call "grows" each array as needed, and it works well (tested up to about 8500 elements each). If I want to replace those three functions with one more generic function, how do I still keep the three (or more in the future) SQL_ arrays separated? If I just use that one single pointer, I wouldn't have three arrays anymore would I? Which is why I thought I needed the pointer to a pointer. Feel free to kick me for each time I'm wrong :)
Quote:
Also SQL_TRANSACTION is already a pointer to a struct, so in your function declaration
SQL_Addto_Array(unsigned int transType, SQL_TRANSACTION *trans)
it could just be
SQL_Addto_Array(unsigned int transType, SQL_TRANSACTION trans)
hope this helps..

Cool, thanks!

Quote:
Original post by plastique
// this should work now
*array = (SQL_TRANSACTION*) realloc(*array, (SQL_MAX_QUERY_SIZE * (*allocated)));

Yes, it does work! (By work I mean compile without complaint and not crash on that line anymore :) ) How do I memcpy into the array as well?
memcpy(array[*num], trans->string, sizeof(trans->string)+1); seems to work for the first call to the function, then segfaults on the second.

Share this post


Link to post
Share on other sites
I was mainly commenting on the realloc. But anyway, I just went through the whole code now and i can confirm (as the other guy already mentioned) that you need to also allocate extra memory for the strings, so basically

- allocate an array of SQL_TRANSACTION, i.e. x times sizeof(SQL_TRANSACTION), x seems to be "numInsertsAllocated" here
- for each (new) x, allocate an array of y count unsigned chars (y seems to be SQL_MAX_QUERY_SIZE here)

then you can do the memory copy like e.g.

memcpy((*array)[*num].string, trans->string, SQL_MAX_QUERY_SIZE);

Share this post


Link to post
Share on other sites
Thanks to both of you for you suggestions and help. I've got something that works now. I think the code is long overdue for a cleanup! Hopefully I wont break anything. [smile]

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.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!