free()

I

Ian Collins

Jack said:
how does free know how much of memory to release if I say free(ptr)?
Because it's good friends with malloc() and they share the
implementation specific details on allocated memory.
 
M

Michael Mair

Jack said:
how does free know how much of memory to release if I say free(ptr)?

Your implementation does the book-keeping for everything you
allocated with malloc()/realloc()/calloc() or got from a
function using one of these. It then knows how much was
allocated -- and how much is to be free()d.
If you allocated storage for foo which in turn contains
a pointer bar and you allocate storage for bar, then
free()ing foo does not free() the storage bar points to.
Often, you can reach bar only via foo, so you have to
free(bar) before free(foo).

Cheers
Michael
 
J

Jack

Michael said:
Your implementation does the book-keeping for everything you
allocated with malloc()/realloc()/calloc() or got from a
function using one of these. It then knows how much was
allocated -- and how much is to be free()d.
If you allocated storage for foo which in turn contains
a pointer bar and you allocate storage for bar, then
free()ing foo does not free() the storage bar points to.
Often, you can reach bar only via foo, so you have to
free(bar) before free(foo).

Thanks a lot.
For example, if I define the following structure:

struct A {
int *a;
int b;
};

int main(){
int *c;

struct A *p = malloc(sizeof(struct A));
p->a = malloc(10*sizeof(int));

*(p->a) = 11;
*(p->a+1) = 22;

c = p->a;

printf("p->a: %d, p->a+1: %d, c+5: %d\n", *c, *(c+1), *(c+5));

free(p->a); //LINE1
free(p); //LINE2
}

Shoud I execute both LINE1 and LINE2, or only LINE2 is needed?

Jack
 
M

Michael Mair

Jack said:
Thanks a lot.
For example, if I define the following structure:

The code below lacks
#include <stdio.h>
#include said:
struct A {
int *a;
int b;
};

int main(){

int main (void)
is preferred around here.
int *c;

struct A *p = malloc(sizeof(struct A));

Slightly better:
struct A *p = malloc(sizeof *p);
If the type of p changes, then you have only to change
the declaration of p.
p->a = malloc(10*sizeof(int));

malloc() can return a null pointer if not successful -- you
forgot to check for that:

if (NULL == p) {
fprintf(stderr, "%s, %d: Could not allocate storage for p\n",
__FILE__, __LINE__);
exit(EXIT_FAILURE);
};
p->a = malloc(10 * sizeof *p->a);
if (NULL == p->a) {
fprintf(stderr, "%s, %d: Could not allocate storage for p->a\n",
__FILE__, __LINE__);
free(p);
exit(EXIT_FAILURE);
};

*(p->a) = 11;
*(p->a+1) = 22;

c = p->a;

printf("p->a: %d, p->a+1: %d, c+5: %d\n", *c, *(c+1), *(c+5));

Note: You can also write c[0], c[1], c[5].

You did not assign a value to c[5] before reading from it, thus
the representation (the "bit pattern" in memory) could be one that
corresponds to no valid int.
free(p->a); //LINE1
free(p); //LINE2

main() returns int, so let's do that:
return 0;
}

Shoud I execute both LINE1 and LINE2, or only LINE2 is needed?

Both, and in this order.
Even if modern operating systems aught to take care of malloc()ed
memory at programme end, it is a good habit to control your
ressources -- if you leave out LINE1, you have a memory leak.
Even if everything seems to works within a programme, you can get
into trouble if you reuse code leaking memory in a library where
it does not run once but a million times (1000000*10*sizeof(int)
sounds not too bad, but imagine you need more memory per "a" member
of struct A...).


Cheers
Michael
 
S

Simon Biber

Michael said:
malloc() can return a null pointer if not successful -- you
forgot to check for that:

if (NULL == p) {
fprintf(stderr, "%s, %d: Could not allocate storage for p\n",
__FILE__, __LINE__);
exit(EXIT_FAILURE);
};

Why the extra semicolon here?
p->a = malloc(10 * sizeof *p->a);
if (NULL == p->a) {
fprintf(stderr, "%s, %d: Could not allocate storage for p->a\n",
__FILE__, __LINE__);
free(p);
exit(EXIT_FAILURE);
};

And here?

Just write p->a[0] = 11; and p->a[1] = 22;

Any time you find yourself adding to a pointer and then dereferencing
the result, it probably makes more sense to use square brackets.
c = p->a;

printf("p->a: %d, p->a+1: %d, c+5: %d\n", *c, *(c+1), *(c+5));

Note: You can also write c[0], c[1], c[5].

You did not assign a value to c[5] before reading from it, thus
the representation (the "bit pattern" in memory) could be one that
corresponds to no valid int.

In fact, you get undefined behaviour if you try to read a value from an
uninitialised memory location. The program may read a garbage value,
trap and/or crash.
 
M

Michael Mair

Simon said:
Why the extra semicolon here?


And here?

Oversight -- I "thought with my fingers" instead of writing
and compiling the code.
Just write p->a[0] = 11; and p->a[1] = 22;

Any time you find yourself adding to a pointer and then dereferencing
the result, it probably makes more sense to use square brackets.
c = p->a;

printf("p->a: %d, p->a+1: %d, c+5: %d\n", *c, *(c+1), *(c+5));


Note: You can also write c[0], c[1], c[5].

You did not assign a value to c[5] before reading from it, thus
the representation (the "bit pattern" in memory) could be one that
corresponds to no valid int.

In fact, you get undefined behaviour if you try to read a value from an
uninitialised memory location. The program may read a garbage value,
trap and/or crash.

True.


Cheers
Michael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,610
Members
45,255
Latest member
TopCryptoTwitterChannels

Latest Threads

Top