Questions on use of malloc() and free() - c

Thanks for notice my question.
In C Primer Plus, it first writes
The argument to free() should be a pointer to a block of memory allocated by malloc(); you can’t use free() to free memory allocated by other means
which means ONE malloc(), ONE and ONLY one free().
But later it goes
It’s okay to use a different pointer variable with free() than with malloc(); what must agree are the addresses stored in the pointers.
which seems contradict to the first statement.
So my understanding is that as long as a pair of malloc() and free() share the same address there is no error, and the name of pointers doesn't matter. Am I right?

For example:
void* p = malloc (100);
void* q = p;
free (q);
...is fine. The argument for free () is the value that was returned by malloc. The sentence
"It’s okay to use a different pointer variable with free() than with
malloc()"
is actually pointless and just creates confusion - of course it is fine to use different variables as long as the value is the same.

Just remember that freeing any alias, makes all the pointers invalid
int *a, *b, *c, *d, *e;
a = malloc(42 * sizeof (int));
b = a;
c = b;
d = c;
e = d;
a[0] = 42;
b[1] = 100; // same as a[1]
c[2] = 999; // same as a[2]
d[3] = -1; // same as a[3]
e[4] = 0; // same as a[4]
free(d); // for example
// all of a, b, c, d, and e are now invalid;

Variables contain some value, which could be a pointer (i.e. a memory address).
Two variables could contain the same pointer (that is, the same address), it is called pointer aliasing.
What matters to free is to get the value of a pointer previously given by malloc (that is a memory address previously given by malloc)

Related

While copying a pointer, is the memory copied as well?

Consider the code below:
int * a = malloc(sizeof *a * 10);
int * b;
b = a; //Is there an operation "b = malloc(sizeof *a * 10);" occuring?
free(b); //will the memory of 'a' be free?
Also, how can I test whether a piece of memory is released or not?
b = a; //Is there an operation "b = malloc(sizeof *a * 10);" occuring?
No, assigning a to b merely sets b to have the value of a. Since a is a pointer, b then points to the same place that a points to.
free(b); //will the memory of 'a' be free?
Yes, after b = a;, free(b); will free the memory that a points to. Note that this is not the memory of a, it is the memory a points to. C does not create or maintain any connection or ownership relation between a pointer and the memory it points to. Pointers are merely things with values that are addresses.
The fact that memory was initially allocated and assigned to a with a = malloc(…) does not create any special relationship between a and the memory. Other pointers can be used to access and free the memory, and the value of a can be changed to something entirely unrelated without affecting the memory.

Does this specific code contain memory leakage?

int* a = (int*)malloc(5);
int* b = a;
free(b);
Is there memory leakage? If so, why does this occur?
This doesn't leak memory, you free what you allocate, but both a and b are invalid after the free so using either of them is undefined behaviour.
No, this is perfectly safe. (Though you shouldn't cast malloc(). Casts are evil and should be avoided whenever possible. malloc() returns void *, which you never need to cast to a different pointer type)
In your case, there is no memory leakage but these pointers are called Dangling pointers.
Because you are delete object from memory but pointers still pointing same memory location.
{
int* a = (int*)malloc(5);
int* b = a;
free(b); // a and b dangling now
a = b = NULL; //reset pointers // a and b are no longer dangling
}

"pointer being freed was not allocated" while using memcpy

I trying to use memcpy to copy content from one array to another, the code is as follow:
#include <stdio.h>
int main(){
int *a;
a = (int*) malloc(sizeof(int) * 4);
a[0] = 4;
a[1] = 3;
a[2] = 2;
a[3] = 1;
int *b;
b = (int*) malloc(sizeof(int) * 4);
memcpy(&b, &a, sizeof(a));
free(a);
for (int i = 0; i < 4; i++){
printf("b[%d]:%d",i,b[i]);
}
printf("%d\n",sizeof(b));
free(b);
return 0;
}
However, when I try to run it, I encounter the following error:
b[0]:4b[1]:3b[2]:2b[3]:18
mem(6131,0x7fffbb4723c0) malloc: *** error for object 0x7fa5a4c02890: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
This error disappear if I remove the free(b) piece of code, however, I don't know why since I explicitly allocate resource to it.
Your memcpy is wrong. You're copying the value of the pointer a into b instead of copying the data pointed by a into the buffer pointed by b. You end up doing a double free because a and b point to the same place. Replace your memcpy call with this:
memcpy(b, a, sizeof(int)*4);
memcpy(&b, &a, sizeof(a));
This doesn't copy the 4 ints that a points at to the 4 ints that b points at.
This instead overwrites b with the contents of a. Then you end up doing a double free, since both a and b contain the same address.
I'll repeat my comment on your question: You need to take the time to appreciate the difference between a pointer and a pointee. What holds and address, and what is at that address.
This is the exact problem why we say not to cast the return value of malloc() and family in C..
First things first, you are missing stdlib.h include and because of that, the prototype of malloc() is not known and your compiler assumnes that it returns an int. This creates the mismatch between the implicit declaration and the actual definition, which at a later stage, invokes undefined behavior.
That said, another major issue is when you write memcpy(&b, &a, sizeof(a)); which is very wrong. You want to supply a and b themselves, as you want to copy the contents of the memory location pointed by a to the memory location pointed by b, not the address of the pointers.
In your case, the erroneous call actually messes up the contents of b, i.e., the actual pointer returned by malloc(). Therefore, as we know, passing a pointer which was not exactly returned by memory allocator functions or already free()-d, to free() causes UB, quoting C11, chapter §7.22.3.3,
[...] Otherwise, if
the argument does not match a pointer earlier returned by a memory management
function, or if the space has been deallocated by a call to free or realloc, the
behavior is undefined.
you're getting into trouble, as the current pointer held by b is the same one as a which has been already passed to free(). As mentioned in the other answer(s) [1][2], you need to write
memcpy(b, a, sizeof(int)*4);
Moral of the story: Enable compiler warnings and always check the data types.
Maybe because you free b when you do free(a). Because the memory zone is the same after doing memcpy. Try to do free(b) at the end, without the free(a).

Memory segments stack and heap

i've looked over so many topics and i still could not find out why this happens:
struct B
{
int _arr[5];
};
struct A
{
struct B * _pb;
};
int main() {
int i;
struct B b;
struct A *pa = (struct A*)malloc(sizeof (struct A));
for (i=0;i<5;++i)
{
b._arr[i] = i;
}
pa->_pb=&b;
Struct A a = *pb;
}
How come pa found on stack and *pa is found on heap! both are local variables and should be only valid through scope so it should be on stack.
also why is ‪a._pb->_arr[2] on stack should not be on heap? can anyone clarify for me when it should be on stack and when on heap
The variable pa is on the stack. The memory it points to is on the heap.
Somewhat graphically a pointer variable can be describes like this:
+----+ +--------------------------------+
| pa | --> | allocated memory for structure |
+----+ +--------------------------------+
The two locations illustrated above (pa and the memory it points to) can be in different "segments", or they can be in the same.
And a._pb->_arr[2] is on the stack because a._pb is pointing to b which is on the stack.
Lastly a note about the "stack". While it's common to store local variables on the stack, the C specification doesn't say anything about it. Local variables are really automatic variables, and the C specification only specifies the semantics of those not where they should be stored.
First off, the C standard says nothing about stacks and heaps. Those are implementation details of a given compiler. That being said, most compilers for desktop applications use both of these.
You are correct that pa is local to the main function and therefore resides on the stack. *pa however is not a local variable. It is an expression which evaluates to an instance of struct A.
In this case, the malloc function returns a pointer to a block of memory big enough for a struct A and the value of that pointer is stored in pa.
Generally speaking, anything returned by malloc, realloc, or calloc lives in the heap, while variables declared local to a function (even pointer variables which may point to the heap) reside on the stack.
Short answer: *pa (what pa points to) is found on the heap because that's where you allocated the memory using malloc(). The variable pa, the pointer itself, is allocated on the stack because it's a local variable.
Long answer: Make sure you note the difference between a pointer and what the pointer refers to.
A declaration like this:
int a[5]
Tells the compiler to reserve space for a 5-element array, while a declaration like this:
int *a;
Tells the compiler to reserve space for a pointer. If you want the pointer to refer to an array then you need to allocate the memory, usually on the heap using malloc() and then release it when you're done using free().
And just to confuse things, in the C language, the array operator, [], is equivalent to the pointer arithmetic *() so that these two statements are wholly equivalent, regardless of whether a was declared as a pointer or an array:
a[2] = 5;
*(a + 2) = 5;
Digression: Which leads to some amusing possibilities. The above two statements are also equivalent to this one:
2[a] = 5;
Because addition is commutative in C:
2[a] = 5;
*(2 + a) = 5;
*(a + 2) = 5;
a[2] = 5;
But this absolutely does not work in C++ for reasons that are too far afield for this digression.

Exact output of free() in C?

I wanted to ask, if I have a pointer pointing at some struct, but then I free(struct) then if I dereference the pointer, will it be pointing to NULL? As in can I check, pointer != NULL or is this undefined?
Thanks!
Calling free() on the pointer does not change the pointer value. It will still point to the same memory that no longer belongs to your application. You should always assign NULL to a free'd pointer immediately after you free it to ensure that you don't use it again.
void *p = malloc(10); // p points to allocated memory
free(p); // p still points to invalid memory
p = NULL; // good practice
Consider the below code
int main()
{
int *p = (int *)malloc(sizeof(int) * 10);
free(p);
}
Here variable p is a local variable of a function main. Size of this variable will be 4 bytes(in 32bit m/c) or 8 bytes(in 64 bit m/c). Now we are allocating memory for storing 10 integer elements and that address is stored in variable p. Now we are calling free function to which we are passing the dynamic memory address which is stored in the local variable p. Now free function will free the memory and it will not be able to assign NULL to the variable p. Because we passed address as value, not reference to the pointer.
We can define a wrapper function for free like below
void myfree(void **p)
{
free(*p);
*p = NULL;
}
int main()
{
int *p = (int *)malloc(sizeof(int) * 10);
myfree(&p);
}
Or we can define macro function also
#define MYFREE(x) \
free(x); \
x = NULL;
It's undefined. C does not define what it does with the contents of the pointer, although most implementations do nothing.
Take a look at this page.
It clearly says:
Notice that this function leaves the value of ptr unchanged, hence it
still points to the same (now invalid) location, and not to the null
pointer.
Note that it is up to you to make sure that pointer is not dereferenced after being freed.

Resources