Resolved down the rabbit hole with pointers

I recently realized the existence of void pointers. These are quite useful if the primitive type for a data storage class is not known. Though, I have a question as to whether I am using them correctly.
My storage class will allocate memory and keep track of the byte size of the individual pieces. The user then set and extract bytes via void * pointers.
The storage class then copies bytes to and from the storage memory as needed. Basically my own crude implementation of NSMutableArray/NSMutableData.
The user gets back a void * pointer and then casts this into whatever is needed. Yes, probably too much responsibility is given to the user.
Anyway, I am concerned about memory leaks. To return a value, I memcpy() the bytes into a newly created memory malloc(). But there is no corresponding free().
The user has to free the memory. But calling free after casting and dereferencing causes a crash. Does memory have to be freed in this case? See last for loop.
Thanks for reading, replying and hopefully a lesson in pointers.

Basically you are freeing memory you did not malloc/calloc. Your double returnElement within the last loop is requesting space to store a double. This will be on the stack. You are not mallocing or callocing the space for this double (if you did it'd be in the heap). You then memcpy into this space (which is fine: you are allowed to do that). You then free the space that is on the stack. You can't do that. You can't free on the stack. That is automatically done when the current stack frame is popped.

If that doesn't make sense (if you don't know what the heap and stack are for example) it's time to learn basic C properly...

Yes it's as robbieduncan says. In your one-line version, you're losing the pointer the copy of the double on the heap. Then later you try to pass the address of the copy on the stack to free, which rightly causes a crash.

Basically you can't do this in one line. You could, though, cast directly to a double pointer and still free it, like so:

Basically you are freeing memory you did not malloc/calloc. Your double returnElement within the last loop is requesting space to store a double. This will be on the stack. You are not mallocing or callocing the space for this double (if you did it'd be in the heap). You then memcpy into this space (which is fine: you are allowed to do that). You then free the space that is on the stack. You can't do that. You can't free on the stack. That is automatically done when the current stack frame is popped.

Click to expand...

My main concern was that the malloc within the memcpy did not have its own free statement. But, if I understand you correctly, the act of copying from the heap to the stack has the same effect of free()? So free() is only required to release memory that resides on the heap?

Quote

If that doesn't make sense (if you don't know what the heap and stack are for example) it's time to learn basic C properly...

Click to expand...

Trying to. Understanding basic CPU architecture (heap vs stack) seems useful. I just started watching the MIT opencourseware*. Hopefully it will be in there. If not, any book recommendations?

My mistake. But the underlying problem is the same: the address of returnElement is on the stack. The address of the memory the at malloced in the call to memcpy is "lost" as it is never saved into a variable. So that malloced memory is leaked.

But, if I understand you correctly, the act of copying from the heap to the stack has the same effect of free()?

Click to expand...

No. Absolutely 100% not. You have allocated space on the heap with the malloc. The malloc returned the address for you to free later. You did not save this address so cannot call free but that is OK as memcpy also returns the destination address (so as you can put the memcpy and malloc in one line like you have). But you fail to save the address their, instead dereferencing the pointer and saving that value in a variable. So at this point the malloced space on the heap is leaked. This is a problem. The space you allocated on the stack for the double is fine: it will get cleaned up for you.

The solution is to split this into two lines. You need to have a void * pointer variable that you store the return from memcpy in. You can then dereference and cast the that into returnElement. And finally free the void * pointer returned from memcpy.

It's wrong because you want room for doubles, but get space for double *s. These are different types with different sizes. On platforms where sizeof(double) == sizeof(double *) your code will work. On platforms where this is not true you will not have the right amount of space. In most cases you will have too little space, not too much.

That falls under "esoteric knowledge that nobody should ever bother with". Which means it immediately fails a code review, just like someone writing "a + 1 << i" and expecting people to know which operator has higher precedence.

That falls under "esoteric knowledge that nobody should ever bother with". Which means it immediately fails a code review, just like someone writing "a + 1 << i" and expecting people to know which operator has higher precedence.

Click to expand...

In all honesty I think that's a bit harsh. Anyone who uses memcpy a lot should know what it returns (if you don't and just ignore the returned value then you don't know what you are returning which I think is very bad practice). Anyone who does not use it a lot can be expected to lookup the documentation: that's what I did as soon as I opened this thread.

In all honesty I think that's a bit harsh. Anyone who uses memcpy a lot should know what it returns (if you don't and just ignore the returned value then you don't know what you are returning which I think is very bad practice).

Click to expand...

Except that in the case of memcpy, there is only one possible return value which it always returns.

This case is a bit different though as checking the return value would find out if malloc failed earlier, but it doesn't matter either because if malloc fails, memcpy will copy memory to NULL and the program will crash.

MacRumors attracts a broad audience
of both consumers and professionals interested in
the latest technologies and products. We also boast an active community focused on
purchasing decisions and technical aspects of the iPhone, iPod, iPad, and Mac platforms.