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
Related
Many people recommend doing the following to reallocate memory:
int *temp=realloc(previousVar,newSize);
if(temp==NULL){
printf("error\n");
exit(-1);
}
previousVar=temp;
I understand that, if no new variable was created, the previous pointer would be lost, as NULL would be assigned to it. But what's the point on having all this trouble, if the program will exit in case of failure anyways?
Here's a stack overflow, where the top answer has what I'm referring to:
Proper usage of realloc()
In the example that you provided it really does not matter if you assign the return value to a temporary or not. In the linked answer, the author frees the original buffer, but one could argue that it is not necessary since the process will exit anyway.
However, consider the following example:
typedef struct
{
int *values;
size_t capacity;
size_t size;
} MyBuffer;
bool append(MyBuffer *buffer, int value)
{
if (buffer->size == buffer->capacity)
{
// No more space, double the buffer.
size_t new_capacity = buffer->capacity * 2;
int *temp = realloc(buffer->values, new_capacity);
if (temp == NULL)
{
return false;
}
buffer->values = temp;
buffer->capacity = new_capacity;
}
buffer->values[buffer->size] = value;
buffer->size++;
return true;
}
The function append tries to add a new value to an already allocated buffer. If the buffer is not large enough, it tries to use realloc to obtain a larger buffer. If realloc fails the function returns false.
If we change the realloc call to set directly buffer->values we will leak memory in case of failure:
buffer->values = realloc(buffer->values, new_capacity);
if (buffer->values == NULL)
{
// Here the original `buffer->values` is lost and we can never access it again.
return false;
}
realloc does not free the original buffer, so in case of failure we no longer have access to it. This is a problem: in the best case scenario it is a memory leak, in the worst case we may have lost some data that we still needed (on top of the memory leak).
So this depends on how you handle realloc failures. If you log an error and exit immediately you don't need to use another variable to store the result. If you report the error up the call chain, or there is some cleanup that you want to do you have to do this. If you take the first approach you need to be careful if you refactor that piece of code to return an error instead of exiting, so there is some merit to always assigning the result to another variable.
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.
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.
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.
I'm trying to write the equivalent of remove for Java's ArrayList in C.
Here is my code. It assumes that index is a valid index in the list.
void arrayListRemove(ArrayList* list, int index){
int i;
if (arrayListSize(list)==1){
list->size = 0;
free(list->data);
list->data = NULL;
} else {
for(i=index;i<arrayListSize(list)-1;i++){
list->data[i] = list->data[i+1];
}
list->data = realloc(list->data, (arrayListSize(list) - 1) * sizeof(void*));
if (list->data != NULL){
--list->size;
} else {
exit(1);
}
}
}
Is this correct?
Would the code work without the arrayListSize(list) == 1 check? I.e. does realloc(list->data, 0) free the arrayList? I've seen conflicting things online about what realloc(ptr, 0) would do.
I would leave the arrayListSize(list) == 1 case. Not relying on the behavior of realloc(ptr, 0) seems prudent, and it makes the code clearer, generally and by using an explicit free.
A few more notes:
When using realloc, be sure to capture the return value in a tmp variable. If realloc fails, then it can return NULL and leave the original pointer untouched. By doing ptr = realloc(ptr); you can cause a memory leak when realloc fails, because you've now lost your original pointer. Instead use this idiom:
tmp = realloc(ptr, newSize);
if (tmp != NULL)
ptr = tmp;
else handleError();
Is it necessary to free the elements of your list when removing them from the list? Your data array consists of pointers, are you leaking memory by not calling free on removed elements? Naturally this isn't necessary in the java implementation. If your list contains the only reference to the contained objects, then you'll need to free them upon remove, or return the pointer in your function and leave it up to the caller to deal with the memory.
There's typically no need to use realloc for shrinking a list, unless you're on a platform that is really memory constrained, and even then, it's probably unnecessary to shrink allocated blocks for every deleted list element. Prefer to grow/shrink your allocated blocks by more than a single element.
This is really a nit, but since this is an API method, and you're using a size member of your data structure to track the list length, you might as well use size throughout, rather than relying on another API method arrayListSize.