Using realloc to resize a dynamic array - c

I tried to extend my ful list of players.
When I use the realloc function, it save my player except the last.
I mean that if I had 4 players in my array and I tried to extend my array to 7 I got a new array in size 7 and just 3 players.
This is part of the function:
void initializeListForTree(Player** players, int listSize)
{
int formulaSize = bla bla bla.....
players = (Player **)realloc(players, sizeof(Player *)*formulaSize);
if (!players)
{
printf("memory allocation failed\n");
}
}

More something like:
void initializeListForTree(Player*** players, int listSize)
{
int formulaSize = bla bla bla.....
void *p = realloc(*players, sizeof(Player *)*formulaSize);
if (!p) {
printf("memory allocation failed\n");
}
else {
*players = p;
}
}
and at the call site
Player **playerslist = NULL;
initializeListForTree(&playerslist, 1);
...
initializeListForTree(&playerslist, 2);
etc..
This, of course, only if your type is a pointer to a list of pointers.

No, you cannot change players itself () from initializeListForTree() function. C uses pass by value for function argument passing. Any changes made to player inside initializeListForTree() function won't be reflected to the actual argument used.
If you have to get that done, you'll need to pass a pointer to players.
If you don't mind having an alternate approach, if choose to return the newly
allocated pointer from initializeListForTree() and collect the same into the actual argument passed, then you'll not be needing to pass a pointer-to-pointer-to-pointer.
That said,
Please do not cast the return value of malloc() and family in C.
Please do not store the return value of realloc() directly into the targeted pointer. In case realloc() fails, it will overwrite the valid entry.

Where realloc() find the extend memory:
If there are enough free space after the original memory, then it will use that, and the original address don't change.
If orignal memory is at end of heap/.. , it extend the memory, so the original address don't change.
If original memory is in middle of heap/.., and there is not enough space, then it will allocate a new memory block, and copy your original memory into the new ones, so the address change.
The last case happens with big chance, so you always need to update your address after call realloc().
And the old address might be put into the free memory list, you should not touch it any more. It might be allocated by another malloc()/.. call in future.
And you can see that, realloc() could be heavy, because it might need to copy memory, so improve code to avoid to use it, if possible.
Here is a possible use case (from TLPI):
// nptr is new pointer, ptr is your original pointer,
nptr = realloc(ptr, newsize);
if (nptr == NULL) {
/* Handle error */
} else {
/* realloc() succeeded */
ptr = nptr;
}
Basicly, first check return value to see whether it succeed:
If failed, then original memory remain unchange.
If succeed, assign new address to original pointer.
And, you need to make sure you don't have another pointer that point to middle of original memory, because that would change too, use offset to start address could make things easier.
If your array size change frequently, then you might allocate a bigger memory, remember its size, and reallocate it only when the size is reached, when resize you also give a bigger value than the new value.
You can choose a factor when resize, e.g factor = 1.5, means: new_size = old_size * factor.

Related

BOOLEAN allocate_items(struct item * items, size_t howmany) function for allocate an array of struct item

Recently, I'm learning C. I found a question on the internet. The question is:
What is the problem with this function in terms of memory allocation?
What is a good solution? You may assume that a struct item type has
been declared. The purpose of this function is to allocate an array of
struct item, which you may assume has been declared prior to this
function.
BOOLEAN allocate_items(struct item * items, size_t howmany)
{
size_t count;
items = malloc(sizeof(struct item) * howmany);
if(!items) {
perror("failed to allocate memory");
return FALSE;
}
return TRUE;
}
So, I think that the 4th line is wrong. It should be like:
items = malloc(sizeof(struct item));
And also the 6th line is wrong. It should be like:
if(items == NULL){
Is it correct?
First of all, both line 4 and 6, as you mentioned seems to be OK.
That said, the basic problem with this function is, you're allocating memory to a local scope of variable. This way
as you don't return the pointer to allocated memory, after the function returns, there would be no way to access the allocated memory.
by not freeing up the allocated memory, you will face memory leak.
If you have to allocate memory to a pointer, you need to pass the address of that pointer to the function and allocate memory. You can also return the pointer but then you need to change the function signature.
Finally, arrays are not pointers and vice-versa. They may appear or beahave similar sometimes, but they are not the same.
The 4th line is not wrong as they are trying to declare an array of the structs.
You should add a line inside the function that declares a new pointer, temp, to hold the current value of items, then after allocating the memory,
the 6th line should be
if(items == temp)
to check whether the value has changed(because that is the closest we can get to checking whether malloc worked)
this is because the ! operator is used to check if a condition is true or not(at least at a basic level in most languages) and as a pointer isn't a condition or an int that can be used as true or false, the operator won't work.
Here a fixed version, as it would probably be written in the "industry".
bool allocate_items(struct item ** pitems, size_t howmany)
{
// argument validation
assert(NULL != pitems); // some also add release version checks...
if(NULL == pitems ) return false;
// We can also spot memory leak sources here.
// If *pItems != NULL - does that mean we have to free first to prevent
// a leak? What if it is just some random value and not something we can
// free? So contract usually is: *pitems has to be NULL...
assert(NULL == *pitems);
if(NULL != *pitems) return false;
// implementation
*pitems = malloc(sizeof(struct item) * howmany);
if(NULL == *pitems) {
perror("failed to allocate memory");
}
return NULL != *pitems;
}
While the bool defined in stdbool.h sometimes causes trouble with C++ interop (same symbols on both sides, but sometimes sizeof(bool) differs), it is still the better option compared to inventing yet another bool type.
The pitems is a pointer to the location where the pointer to the new chunk of memory shall be written to. A caller of this function might have written:
int main(int argc, const char*[] argv) {
struct item *myBunchOfStuff = NULL;
if(false != allocate_items( &myBunchOfStuff, 20) ) {
// ...
free(myBunchOfStuff);
myBunchOfStuff = NULL;
}
return 0;
}
Defensive programming states: Your function cannot claim "Heh - my function only crashed because I was given a bad value!". Instead, it has to verify itself. It is responsible not to crash. The pointer could still be != NULL but otherwise bad. That is impossible for the function to catch, usually.
In C, everyone is proud of not requiring the cast of malloc()'s return value. You can be proud of that until you compile your code with a C++ compiler. Then you have to change your code and fix that. Well, I guess it is a matter of preference...
While parameter checking is often seen as a separate part of the functions implementation, after that, you should try to stick to "single point of exit". Main reason for that is maintainability. With multiple exit points, if the function gets bigger later on, it gets harder to spot if some early exit forgets to free some memory or cleanup other forms of state.

free memory used to return value in C

I have a function that calls another function which creates a unique ID and returns it as a string by malloc().
my question is how do I free the memory once outside the function? or what is the better way to do what I would like to do.
my function that asks for the ID:
void addCustomer(TennisStoreType* ts){
CustomerNodePtr newcustdata;
int datapos = 0;
newcustdata = malloc(sizeof(CustomerNodeType));
while (datapos <= CUSTDATA_POSITIONS) {
char userinput[BUFFER_SIZE];
switch (datapos) {
case 0:
strcpy(newcustdata->custID, createCustID(ts));
break;
}
}
the function that returns uniqueID:
char* createCustID(TennisStoreType* ts) {
char *custID;
custID = (char *)malloc(CUSTID_LEN + 1 * sizeof(char));
if (ts->customerCount + 1 >= FOURDIGITS) {
sprintf(custID, "C%i\n", ts->customerCount + 1);
} else if (ts->customerCount + 1 >= THREEDIGITS){
sprintf(custID, "C0%i\n", ts->customerCount + 1);
} else if (ts->customerCount + 1 >= TWODIGITS) {
sprintf(custID, "C00%i\n", ts->customerCount + 1);
} else {
sprintf(custID, "C000%i\n", ts->customerCount + 1);
}
return custID;
}
so how would I go about freeing the string that has been copied to newcustdata->custID? do I even need to? or is there a better way to go about doing this?
thanks in advance.
You can eliminate that function entirely. The line
strcpy(newcustdata->custID, createCustID(ts));
can simply be written as
sprintf( newcustdata->custID, "C%04d", ts->customerCount + 1 );
provided, of course that custID is an array of at least 6 characters, e.g.
char custID[8];
Notes:
I typically round char array sizes up to multiples of 8, since structure
padding will waste the bytes anyways.
I removed the \n since it doesn't seem right to have a newline
character in a unique ID, but of course you can add it back in.
If you really like that function, and want to keep it, then replace
switch (datapos) {
case 0:
strcpy(newcustdata->custID, createCustID(ts));
break;
}
with this
char *temp;
switch (datapos) {
case 0:
temp = createCustID(ts);
strcpy(newcustdata->custID, temp);
free( temp );
break;
}
That will free up the memory after the copy.
Your createCustID() function is going to allocate some memory, then return it to the caller, by returning the pointer it got from malloc().
The calling routine, when it is done with the structure, can (and must) free the memory by passing that same pointer to free().
In your example, you need to expand the logic in addCustomer() to retain the pointer it received from createCustID() long enough to (1) test that it is not null, (2) copy the contents locally if needed, and (3) free the received block.
As others have pointed out, you might find it more efficient to just build the received block into the data structure you are assembling, rather than making a copy of it. However, you would still need to free the block as part of your logic for disposing the larger data structure.
You need to plan your code paths carefully with this type of code, so that you always know who "owns" the allocated block, and is responsible for freeing it when it is no longer needed.
Also, you must always check the return value of malloc() against null. If malloc fails to give you the memory you asked for, you need to handle the error appropriately; not just forge ahead writing data into the null pointer.

Modifying 2D char array passed to a function in C

Lacking money ATM so I'm offering $0.25 via paypal to the first person to point out what I did wrong in this code snippet -- I hope this doesn't violate the site rules or insult anybody.
I want to modify an multi-dimensional array in a function. It gets modified while in the function, but when scope returns to the main function the array is unchanged.
The function headers cannot be modified. Thanks for helping me out.
void getAlignment(char*s1, char*s2, char*s3, char*aligned[])
{
/***********************
Code here which assigns
char**tmp to "different" "words"
***********************/
printf("tmp in getAlignment function\n");
printf("%s %s\n", tmp[0], tmp[1]); // prints "different words", as expected
aligned = tmp;
}
int main(void)
{
// skipped some code
char** aligned = (char**)malloc(sizeof(char*)*2);
aligned[0] = "should";
aligned[1] = "change";
printf("%s %s\n", aligned[0], aligned[1]); // prints "should change", as expected
getAlignment(s1, s2, transcript, aligned); // how do i change aligned during this call?
printf("%s %s\n", aligned[0], aligned[1]); // prints "should change"
return 0;
}
When you write inside getAlignment:
aligned = (char**) malloc(2*sizeof(char*));
you are making the pointer GetAlignment::aligned point to some new memory. It no longer points to the memory that main::aligned points to. When you operate on this new memory, it has no effect on the memory that main::aligned was and is pointing to.
(Note - the :: is not C syntax, but my meaning is to disambiguate your two variables which are both called aligned in their local scope, despite the fact that they are two separate variables).
If your intent is that the code in getAlignmentmodifies the memory being pointed to by main::aligned then just remove the above line.
If your intent is that getAlignment be able to allocate new memory, and main::aligned be switched to use that new memory, then you have to pass main::aligned by reference (i.e. add an extra level of indirection in the function call). And don't forget to free() the previously-allocated memory.
BTW don't cast malloc.
You don't need to allocate 2D array again by aligned = (char**) malloc(2*sizeof(char*)); in function getAlignment because you already allocated it in main.
You require allocate each element of array like
int alignedStrLen = strlen(s3);
aligned[0] = malloc((alignedStrLen+1)*sizeof(char));
aligned[0][alignedStrLen] = '\0';
aligned[1] = malloc((alignedStrLen+1)*sizeof(char));
aligned[1][alignedStrLen] = '\0';
And and you should free the memory allocated by malloc.

Copying and freeing malloc'ed pointer

I'm trying to hunt down memory leaks and have found one source. I am malloc'in the pointer in one function and freeing it in another, but I'm missing out on understanding how to copy the value the pointer points to while also being able to free the pointer.
Current implementation (with memory leak):
// This code has been greatly simplified
// and as such does not appear to have any purpose
int foo(){
int bestval = 0;
char *best;
char *match;
for (int i=0;i<3;i++) {
int returnValue = bar(&best);
if (returnValue > 10) {
(1)
match = best;
}
}
printf("%s", match);
(2)
return 0;
}
int bar(char ** best) {
char*s = "Hello!";
*best = malloc(strlen(s) + 1);
strcpy(*best,s);
return 0;
}
Two questions
If I had to free memory at (1) rather than (2), how would I do it so that match would still have what was contained in best?
Should I be doing strcpy to copy best to match? If so, do I have to do another malloc within foo?
A bit of a stab in the dark, assuming there's a loop in Foo...
int foo()
{
int bestval = 0;
char *best;
char *match = 0; // initialize to null
// start some loop
for (int i=0;i<3;i++) {
// fetch the next best value...
int returnValue = bar(&best);
// some check (if best is really best!)
if (returnValue > 10) {
// if match has previously been populated, free it
if(match) {
free(match);
}
// save the new best value
match = best;
}
else {
// not saving best in match, so free it!
free(best);
}
}
// end some loop
// only do this if match was successful?!?
if(match) {
printf("%s", match);
// clean up once the best of the best has been used...
free(match);
}
return 0;
}
In function bar the strcpy should read as
strcpy(*best,s);
In the main function you can copy the value best points to by
strcpy(match, best);
free(best);
match needs to point to a valid memory block before. If you do a
match = best;
free(best);
match will be invalid too because it points at the same freed memory best pointed.
You need to know the size of the string.
At (1) You would be assigning the address of a memory address that has already been freed, you have to do another malloc to match*=malloc(sizestr) and then copy it with memmove or strcpy if you want to free best.
If I understood properly, you want to copy the string into best, then free bests memory and assign ptr to match? if you free best memory before memmoving or strcpying to another location you lose its contents, and if you want to copy it to another location first you need to allocate the memory where you want to copy it to, so you need 2 mallocs on that code.
If I had to free memory at (1) rather than (2), how would I do it so that match would still have what was contained in best?
If you free at position (1), it is not possible to do it so that match would still have what was contained in best.
Should I be doing strcpy to copy best to match? If so, do I have to do another malloc within foo?
match = best;
With the above statement, both are pointing to the same location. So, there is no need to strcpy at all. To do that, allocate memory for match to point to whose length is best+1 and then do a strcpy.
Copying the value of a pointer does not copy the underlying memory. So either, don't free(best) until you are done with match, or you will need to malloc a new buffer, and e.g. memcpy() the contents from one buffer to the other.
Yes, you can malloc and strcpy:
match = malloc(strlen(best) + 1);
strcpy(match, best);
But, if your implementation provides it you can use the strdup() function which is much easier:
match = strdup(best);
If you don't already have strdup(), it's a good idea to create one yourself.
Your current assignment simply assigns the pointers to the same buffer. If you then free() this buffer, you've removed what is contained here (and thus dereferencing it is a bad idea).
You don't need to use strcpy() to copy best to match - you'll be better off freeing it after the printf() (or the last point that it is needed). There's no point over-complicating things with an extra function call or six, just remember to free() memory that you've allocated at the end of each function!

Why Win32 HeapReAlloc() changes values?

I'm writing an app in C using win32 API.
When I try to enlarge the size of my array, using the HeapRealloc() function, it changes my current values in the array, instead of copying them.
The code I use to reallocate memory:
BOOL ChangeFeedArraySize(UINT newSize)
{
char tempChar[20] = "";
PFEED tempArr;
if (newSize == 1)
{
tempArr = (PFEED)HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(FEED));
}
else
{
tempArr = (PFEED)HeapReAlloc(heap, HEAP_ZERO_MEMORY, categoryArray, newSize * sizeof(FEED));
// FEED - a struct
// PFEED - a pointer to the struct
// categoryArray - array to be reallocated
}
if (tempArr != NULL)
{
MessageBox(NULL, ltoa(HeapSize(heap, 0, tempArr),tempChar,10) , "Heap size after reallocation", MB_OK | MB_ICONEXCLAMATION);
feedArray = tempArr;
return TRUE;
}
else
{
return FALSE;
}
}
Here is the status of the arrays when in breakpoint.
the feed array shows the current array state.
the temp array show the new reallocated array state (which is different).
feed array:
feedArray http://www.freeimagehosting.net/uploads/526b0b2172.jpg
temp array:
tempArray http://www.freeimagehosting.net/uploads/17858f2e7e.jpg
Please help.. :\
Link to the function description on MSDN
You cite a Windows-specific function, but this is also true of realloc(), which is the standard equivalent.
If these functions return the same address as passed in, it's because the memory right after the buffer you asked for originally is unused. So it can satisfy the request without moving the buffer.
But what if there were two quick allocations in immediate succession, for example? Maybe the memory right after what was originally requested ended up being used for the next allocation. In which case, the allocator needs to find space somewhere else, copy what was in the old buffer, free the old buffer, and return the new one.
Generally, the pattern you want to follow for this sort of thing is like this:
void *newmem = realloc(oldmem, newsize);
if (!newmem)
{
// TODO: handle failure
// possibly free(oldmem); depending on how you want to handle errors
}
else
{
oldmem = newmem;
}
A common shortcut that people take is "oldmem = realloc(oldmem, newsize);", but this is not as graceful as the above, as it leaks oldmem when there is a failure.
Update based on your edit:
One thing I'm wondering about in your code is this part:
if (newSize == 1)
{
tempArr = (PFEED)HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(FEED));
}
This seems to assume that the first allocation will always be of size one. Are you sure you didn't mean to say if (feedArray == NULL), then allocate newSize * sizeof(FEED)?
Second update:
OK. The other thing that stands out is this:
tempArr = (PFEED)HeapReAlloc(heap, HEAP_ZERO_MEMORY, categoryArray,
newSize * sizeof(FEED));
// Snip...
if (tempArr != NULL)
{
// Snip...
feedArray = tempArr;
The bolded parts should be the same.
From the documentation I see that:
HeapReAlloc is guaranteed to preserve the content of the memory being reallocated, even if the new memory is allocated at a different location. The process of preserving the memory content involves a memory copy operation that is potentially very time-consuming.
So the next question would be how do you come to the conclusion that the array contents have changed? Could you provide code? It is possible that there could be pointer issues involved and/or assumptions about where existing pointers now point to (it is important to assume that the operating system call is correct and completely exhaust any possibility your application code could be at fault first because, whilst bugs can exist with an operating system call, it is likely that a bug with a function as important as this would have been noticed before).
After the call to HeapReAlloc the original categoryArray was released so you no longer own it. Other allocations may had reuse it for other purposes and the content may had changed. You need to use the tempArr from now on:
tempArr = (PFEED)HeapReAlloc(heap, HEAP_ZERO_MEMORY, categoryArray, newSize * sizeof(FEED));
cetagoryArray = tempArr;
where are you looking after call to HeapRealloc? you should look in the RETURNED pointer, not the original one which was freed by it after your call

Resources