memory allocation questions (newbie)

S

Stephen Ramsay

I'm wondering if someone can help me untangle some muddled thinking
about memory allocation in C. I'm writing my first non-trivial app in
C (and having a great time), but I'm finding it difficult to stamp out
memory leaks.

I'm sure most of what I'm about to say is wrong. I'd really be very
grateful to know why.

The use of malloc() in most of the books I've read make it sound pretty
straightforward. If you allocate some memory (because the required
amount of space isn't known until runtime), you have to free that space
before the program ends.

The standard examples go something like this: You need to allocate space
for an array of ints with n elements. When the program knows the value
of n, you can allocate the memory like so:

int *p;

p = malloc(n * sizeof(int));

(I understand from lurking on this list that p = (int *) malloc(n *
sizeof(int)) is deeply offensive to many C fans :)

When I'm done with that array, I need to free it like so:

free(p);

My way of describing this may not be too precise, but I think I
understand this, and I've been able to use it this way in my programs
without incident.

However, I quickly run into problems the minute things get even slightly
more complex. For example:

0. Let's suppose that I allocate space for p, but there are branches in
the program that won't actually use p. Do I need to free the memory at
every exit point? Or does the fact that this can happen indicate a bad
design on my part?

1. Let's suppose that I pass p into a function. If that function is the
last one that will ever need p, then presumably I can (and should) free
it. But what if p is also used elsewhere? At a certain point, it seems
like I would have to write some kind of reference counter . . .

2. On a similar note, when I pass a pointer to some allocated memory as
an argument to a function, pass it back out, pass it in somewhere else,
aren't I always dealing with the same memory block? Will it not suffice
to release the memory after I'm done with all of this, or am I thinking
about it incorrectly?

3. Is there anything wrong with just freeing all allocated memory blocks
at every exit point? I realize I might still have other sorts of
problems, but wouldn't this prevent leakage?

4. What happens if I attempt to free memory that has already been freed?

My apologies if all of this seems too basic for this list. Perhaps
someone knows of a book that deals with these sorts of things in detail?

Steve
 
M

Mike Wahler

Stephen Ramsay said:
I'm wondering if someone can help me untangle some muddled thinking
about memory allocation in C. I'm writing my first non-trivial app in
C (and having a great time), but I'm finding it difficult to stamp out
memory leaks.

I'm sure most of what I'm about to say is wrong. I'd really be very
grateful to know why.

The use of malloc() in most of the books I've read make it sound pretty
straightforward.

It is.
If you allocate some memory (because the required
amount of space isn't known until runtime), you have to free that space
before the program ends.

Right. Some implementations and operating systems will do it for you
but it's poor practice to depend upon that.
The standard examples go something like this: You need to allocate space
for an array of ints with n elements. When the program knows the value
of n, you can allocate the memory like so:

int *p;

p = malloc(n * sizeof(int));

Right. However many (including myself) prefer:

p = malloc(n * sizeof *p);

This means that if the type of 'p' later changes, it still works.
(I understand from lurking on this list that p = (int *) malloc(n *
sizeof(int)) is deeply offensive to many C fans :)

Right. :)
When I'm done with that array, I need to free it like so:

free(p);
Right.

My way of describing this may not be too precise,

You did a good job.
but I think I
understand this, and I've been able to use it this way in my programs
without incident.

However, I quickly run into problems the minute things get even slightly
more complex. For example:

0. Let's suppose that I allocate space for p,

I assume you meant space for 'p' to point to. Space for 'p' itself
is already allotted when you write:

int *p;
but there are branches in
the program that won't actually use p. Do I need to free the memory at
every exit point?

You should free it before the program terminates.
Or does the fact that this can happen indicate a bad
design on my part?

Yes, I think having multiple exit points is not a good idea.
(I suppose sometimes it might be unavoidable, but I strive
to have only one exit point from any function, especially
main().)

Or are you terminating your program in ways other than returning
from main(), e.g. calling 'exit()'. I'd only use that in
extreme cases.
1. Let's suppose that I pass p into a function. If that function is the
last one that will ever need p,

How will you know that? Can you always predict in which order
your functions are called and how many times they're called?
IMO trying to do that is a recipe for insanity. :)
then presumably I can (and should) free
it.

No, don't do it there. Do it in the same function where the memory
was allocated. IOW consider whichever function did the allocation
to 'own' that memory and take responsibility for freeing it.

void func1(int *p)
{
/* do something with 'p' */
}

void func2(int *p)
{
/* do something with 'p' */
}

void func3(int *p)
{
/* do something with 'p' */
}

void foo(void)
{
int *p = malloc(100);
func1();
func2();
func1();
func3();
free(p);
}

Often functions will be conditionally called, or called
within a loop, or indirectly through other functions. No
point in trying to manually keep track of a pointer being
passed around among them.

Often I'll do all my allocation 'up front' in 'main()', then free the
memory just before 'main()' returns.
But what if p is also used elsewhere?
Exactly.

At a certain point, it seems
like I would have to write some kind of reference counter . . .

Don't make life complicated unnecessarily.
See above.

2. On a similar note, when I pass a pointer to some allocated memory as
an argument to a function, pass it back out,

By 'pass it back out', do you mean return its value?
pass it in somewhere else,
aren't I always dealing with the same memory block?

Yes, unless one of the functions changes its value (which
would require a 'pointer-to-pointer' parameter).
Will it not suffice
to release the memory after I'm done with all of this,

If I understand you correctly, yes.
or am I thinking
about it incorrectly?

It seems you think you need to do things the 'hard way'
when you don't. :)
3. Is there anything wrong with just freeing all allocated memory blocks
at every exit point?

No. But try to minimize your exit points, ideally having only
one: the return from 'main()'.
I realize I might still have other sorts of
problems, but wouldn't this prevent leakage?

The way I described above will minimize the possibility of
leakage, since if the allocation and freeing are all done
in the same place (function), it's easier to maintain.
4. What happens if I attempt to free memory that has already been freed?

Nasal demons (undefined behavior).

Some folks like to use a preventative measure against this,
by assigning NULL to any pointer immediately after freeing it,
since 'free(NULL)' is a 'no-op' by definition. Of course others
say this is just a prevention against sloppy coding in the first
place. YMMV.
My apologies if all of this seems too basic for this list.

Not at all. Your questions were intelligent and well presented.
Novices are very welcome here. But you might want to also
check out alt.comp.lang.learn.c-c++, which is specifically geared
toward the novice. But since it discusses both C and C++, when
posting there, be sure to indicate which language you're asking about.

I suppose sooner or later you'll have occasion to use 'realloc()'.
Be careful, and have fun! :)
Perhaps
someone knows of a book that deals with these sorts of things in detail?

See the C FAQ (section 18) for book recommendations:
http://www.eskimo.com/~scs/C-faq/top.html

HTH,
-Mike
 
S

Stephen Ramsay


First, let me thank you for this wonderful reply. I was half expecting
a "read the faq" answer. Instead, I get a response that has really
helped me get several important things straight. To wit . . .
Right. However many (including myself) prefer:

p = malloc(n * sizeof *p);

This means that if the type of 'p' later changes, it still works.

Ahah. I've seen this and never really understood what it meant.

Wait. I think I still don't. Now, if I understand correctly, "sizeof"
is an operator that takes a type name as it operand. So by saying
"sizeof *p," you're saying that you want the size to be equivalent to a
pointer-to-int. I think this means something like "a pointer that is
prepared to point to a memory location big enough to hold an int." In
either case, though, the lvalue of the expression is still a
pointer-to-int. I'm lost . . .
I assume you meant space for 'p' to point to. Space for 'p' itself
is already allotted when you write:

int *p;

Yes, I keep eliding this distinction . . .
You should free it before the program terminates.


Yes, I think having multiple exit points is not a good idea.
(I suppose sometimes it might be unavoidable, but I strive
to have only one exit point from any function, especially
main().)

Or are you terminating your program in ways other than returning
from main(), e.g. calling 'exit()'. I'd only use that in
extreme cases.

The example I'm thinking of is less convoluted than this, but I've spent
the last twenty minutes trying to think of an example and I think I've
convinced myself that my problem is Not Really A Problem.
No, don't do it there. Do it in the same function where the memory
was allocated. IOW consider whichever function did the allocation
to 'own' that memory and take responsibility for freeing it.

void func1(int *p)
{
/* do something with 'p' */
}

void func2(int *p)
{
/* do something with 'p' */
}

void func3(int *p)
{
/* do something with 'p' */
}

void foo(void)
{
int *p = malloc(100);
func1();
func2();
func1();
func3();
free(p);
}

Ah! Okay wait. I understand what you're saying. And if a funtion
returns a pointer to the caller, it becomes the caller's responsibility,
yes?
Often functions will be conditionally called, or called
within a loop, or indirectly through other functions. No
point in trying to manually keep track of a pointer being
passed around among them.

Often I'll do all my allocation 'up front' in 'main()', then free the
memory just before 'main()' returns.

Ah, that sounds so much easier than what I had been thinking about. But
this would have to include any malloc'd storage returned from functions
called by main()?
It seems you think you need to do things the 'hard way'
when you don't. :)


Not at all. Your questions were intelligent and well presented.
Novices are very welcome here. But you might want to also
check out alt.comp.lang.learn.c-c++, which is specifically geared
toward the novice. But since it discusses both C and C++, when
posting there, be sure to indicate which language you're asking about.

Thanks! I wasn't aware of the existence of this list. I'll post my
newbie questions there from now on and go back to lurking on this one.
I suppose sooner or later you'll have occasion to use 'realloc()'.
Be careful, and have fun! :)

Good grief :(

I have to say, at the risk of starting a new thread, that I'm enjoying
all of this C business immensely. C was my first language, but I never
wrote anything serious in it because it was too hard, to confusing, too
error-prone, etc. I've been programming for years (on UNIX systems)
using Perl, Ruby, Java, and stuff like that. I like these languages a
lot, but it's really wonderful to come back to C after years of
experience writing programs in high-level languages. I have a much
better understanding of how computers work (above confusions aside) and
of software design, and now I find that the absolute freedom and
expressiveness of C is a real breath of fresh air. I wish I were faster
in it (I seem to spend a lot of time programming under seige with lint,
valgrind, and gdb close by), but it's a lot of fun to work things out
and try to get the most elegant solution possible. I wonder if many
people have had the experience of coming "back to C" from
ultra-high-level languages only to find that there's something really
cool about programming closer to the metal.

Thanks again,

Steve
 
?

=?iso-8859-1?q?Nils_O=2E_Sel=E5sdal?=

First, let me thank you for this wonderful reply. I was half expecting
a "read the faq" answer. Instead, I get a response that has really
helped me get several important things straight. To wit . . .


Ahah. I've seen this and never really understood what it meant.

Wait. I think I still don't. Now, if I understand correctly, "sizeof"
is an operator that takes a type name as it operand. So by saying
"sizeof *p," you're saying that you want the size to be equivalent to a
pointer-to-int. I think this means something like "a pointer that is
No, you say that you want it to be the size of what p points to.
prepared to point to a memory location big enough to hold an int." In
either case, though, the lvalue of the expression is still a
pointer-to-int. I'm lost . . .


Yes, I keep eliding this distinction . . .


Ah, that sounds so much easier than what I had been thinking about. But
this would have to include any malloc'd storage returned from functions
called by main()?
Just as as side note, most OS's deallocate dynamically allocated
memory on process termination, thus no need for freeing things when
exiting.
 
S

Severian

Just as as side note, most OS's deallocate dynamically allocated
memory on process termination, thus no need for freeing things when
exiting.

Besides the obvious case of memory leaks in functions that are called
repeatedly:

I have often turned entire programs into functions, and having already
taken care of memory deallocation is a time-saver, especially when
scattered through multiple modules.
 
D

Darrell Grainger

I'm wondering if someone can help me untangle some muddled thinking
about memory allocation in C. I'm writing my first non-trivial app in
C (and having a great time), but I'm finding it difficult to stamp out
memory leaks.

I'm sure most of what I'm about to say is wrong. I'd really be very
grateful to know why.

The use of malloc() in most of the books I've read make it sound pretty
straightforward. If you allocate some memory (because the required
amount of space isn't known until runtime), you have to free that space
before the program ends.

The standard examples go something like this: You need to allocate space
for an array of ints with n elements. When the program knows the value
of n, you can allocate the memory like so:

int *p;

p = malloc(n * sizeof(int));

(I understand from lurking on this list that p = (int *) malloc(n *
sizeof(int)) is deeply offensive to many C fans :)

When I'm done with that array, I need to free it like so:

free(p);

My way of describing this may not be too precise, but I think I
understand this, and I've been able to use it this way in my programs
without incident.

Everything is good so far.
However, I quickly run into problems the minute things get even slightly
more complex. For example:

0. Let's suppose that I allocate space for p, but there are branches in
the program that won't actually use p. Do I need to free the memory at
every exit point? Or does the fact that this can happen indicate a bad
design on my part?

Hmm, you mean something like:

allocate memory

if condition1
free the memory
exit

some more code

if condition2
free the memory
exit

some more code

if condition3
free the memory
exit

some more code

free the memory
return 0;

There are cleaner ways to handle this. You could get all the runtime
information and allocate all your memory at once (or at least in large
groups). For example, I might want to allocate an array of strings. I find
at runtime I need 50 strings, each 100 characters long. I could call
malloc 50 times for 100 char each or I could allocate one large block of
5000 and set the 50 pointers to point into the single block of memory.

How you design to reduce the number of malloc calls will differ for each
application. Over time you should be able to figure things out. Or you
could post exact code and ask how it could be written more elegantly.
1. Let's suppose that I pass p into a function. If that function is the
last one that will ever need p, then presumably I can (and should) free
it. But what if p is also used elsewhere? At a certain point, it seems
like I would have to write some kind of reference counter . . .

Different people set different policies for how to deal with this. The
important thing is to be consistent. Generally speaking, free the memory
just after the last place you will need to access it, worst case scenario.
2. On a similar note, when I pass a pointer to some allocated memory as
an argument to a function, pass it back out, pass it in somewhere else,
aren't I always dealing with the same memory block? Will it not suffice
to release the memory after I'm done with all of this, or am I thinking
about it incorrectly?

You are dealing with the same memory block. For example, I could allocate
100 bytes in main(), pass the pointer to func1(), return to main(), pass
the pointer to func2(), return to main(), etc. Finally, in main() I will
free the memory and exit the program.
3. Is there anything wrong with just freeing all allocated memory blocks
at every exit point? I realize I might still have other sorts of
problems, but wouldn't this prevent leakage?

The more code you have to change the more risk you will make a mistake.
You want to keep the code simple, elegant and easy to maintain. What if
you create a program with 23 exit points and call free(p); at all of them.
Later you change the design and no longer need p. Now you have to go back
and remove all those calls to free(p);. Worse, what if you freed an alias
for p in some function? Most of the elimination of p would cause the rest
of the code to generate compiler errors but some might not be all that
clear.
4. What happens if I attempt to free memory that has already been freed?

Undefined behaviour. The C standard indicates that free(NULL) has no
action. I like to set up a macro so a call to free() is actually a call to
free() then set the variable to NULL. This way if you call free again on
the same variable it has no action.
 
D

Darrell Grainger

First, let me thank you for this wonderful reply. I was half expecting
a "read the faq" answer. Instead, I get a response that has really
helped me get several important things straight. To wit . . .


Ahah. I've seen this and never really understood what it meant.

Wait. I think I still don't. Now, if I understand correctly, "sizeof"
is an operator that takes a type name as it operand. So by saying
"sizeof *p," you're saying that you want the size to be equivalent to a
pointer-to-int. I think this means something like "a pointer that is
prepared to point to a memory location big enough to hold an int." In
either case, though, the lvalue of the expression is still a
pointer-to-int. I'm lost . . .

Think about it this way:

#include <stdio.h>
#inclide <stdlib.h>

int main(void)
{
int i = 5;
int *p;

if((p = malloc(sizeof int)) == NULL)
exit(EXIT_FAILURE);

*p = i;
printf("%d\n", *p);

free(p);
return 0;

Can you see that sizeof(*p), sizeof(i) and sizeof(int) are all the same
size? Note that *p is an int and that p is a pointer to an int.
Yes, I keep eliding this distinction . . .


The example I'm thinking of is less convoluted than this, but I've spent
the last twenty minutes trying to think of an example and I think I've
convinced myself that my problem is Not Really A Problem.


Ah! Okay wait. I understand what you're saying. And if a funtion
returns a pointer to the caller, it becomes the caller's responsibility,
yes?

Yes, this is a good policy. If you call malloc() then you are responsible
for freeing the memory. If you call a function that returns the pointer,
e.g.

int *somefunc(int size)
{
int *p = malloc(size * sizeof *p);
return p;
}

then you need to free that result as well.
Ah, that sounds so much easier than what I had been thinking about. But
this would have to include any malloc'd storage returned from functions
called by main()?
Yes.


Thanks! I wasn't aware of the existence of this list. I'll post my
newbie questions there from now on and go back to lurking on this one.


Good grief :(

I have to say, at the risk of starting a new thread, that I'm enjoying
all of this C business immensely. C was my first language, but I never
wrote anything serious in it because it was too hard, to confusing, too
error-prone, etc. I've been programming for years (on UNIX systems)
using Perl, Ruby, Java, and stuff like that. I like these languages a
lot, but it's really wonderful to come back to C after years of
experience writing programs in high-level languages. I have a much
better understanding of how computers work (above confusions aside) and
of software design, and now I find that the absolute freedom and
expressiveness of C is a real breath of fresh air. I wish I were faster
in it (I seem to spend a lot of time programming under seige with lint,
valgrind, and gdb close by), but it's a lot of fun to work things out
and try to get the most elegant solution possible. I wonder if many
people have had the experience of coming "back to C" from
ultra-high-level languages only to find that there's something really
cool about programming closer to the metal.

Does this mean you are ready to move to the assembly language newsgroups?
8^)
 
S

Stephen Ramsay

Hmm, you mean something like:

allocate memory

if condition1
free the memory
exit

some more code

if condition2
free the memory
exit

some more code

if condition3
free the memory
exit

some more code

free the memory
return 0;

Yes. This is exactly what I was envisioning.
There are cleaner ways to handle this. You could get all the runtime
information and allocate all your memory at once (or at least in large
groups). For example, I might want to allocate an array of strings. I find
at runtime I need 50 strings, each 100 characters long. I could call
malloc 50 times for 100 char each or I could allocate one large block of
5000 and set the 50 pointers to point into the single block of memory.

Whoa. Wait. Can you do that?

Well, I'm sure you're not lying to me, but I've never encountered
anything like this in any of the C books I've read. It sounds perilous
(but then, surely quicker than running 50 function calls). I think I'll
just have to go figure it out. ;)
How you design to reduce the number of malloc calls will differ for each
application. Over time you should be able to figure things out. Or you
could post exact code and ask how it could be written more elegantly.

When I write some code that is not embarrassing to me, I will consider
it an honor to have my betters critique its elegance.

(I'm sure that would be incredibly enlightening, actually)
Different people set different policies for how to deal with this. The
important thing is to be consistent. Generally speaking, free the memory
just after the last place you will need to access it, worst case scenario.

This sounds like the closest we'll ever get to a heuristic. Memory
management in C is starting to sound more and more like a series of
design decisions based on experience that will differ from project to
project.
You are dealing with the same memory block. For example, I could allocate
100 bytes in main(), pass the pointer to func1(), return to main(), pass
the pointer to func2(), return to main(), etc. Finally, in main() I will
free the memory and exit the program.


The more code you have to change the more risk you will make a mistake.
You want to keep the code simple, elegant and easy to maintain. What if
you create a program with 23 exit points and call free(p); at all of them.
Later you change the design and no longer need p. Now you have to go back
and remove all those calls to free(p);. Worse, what if you freed an alias
for p in some function? Most of the elimination of p would cause the rest
of the code to generate compiler errors but some might not be all that
clear.

Yes. I was getting myself into this situation when I posted my
questions.


Thanks for these comments. Very, very helpful.

Steve
 
F

/* frank */

Mike Wahler ha scritto:
int *p;
p = malloc(n * sizeof(int));

But if malloc returns a void* , how this assignment
is legal (force p that's a int* to a return value that it's void*) ?

A bit confused?

Thanks
 
C

Chris Torek

Whoa. Wait. Can you do that?

Certainly. As you note, it is probably more efficient. It has
one obvious drawback though: since there was only one malloc(),
there can be only one free(). It is no longer possible to create
and destroy individual strings -- they come or go in this unit,
the "50-string block".
[releasing memory once it is no longer required].
This sounds like the closest we'll ever get to a heuristic. Memory
management in C is starting to sound more and more like a series of
design decisions based on experience that will differ from project to
project.

Indeed.

Something I find quite helpful is the notion of the "owner" of any
given allocated block. A large program is usually made up of many
small parts, each with its own concerns; but in many cases, one
particular bit of code might "own" a block of memory, and thus be
responsible for allocating and freeing it. At some point, that
code might "sell" the memory to some other sub-program, or at least
"loan it out".

This whole accounting scheme can break down when it is no longer
clear who "owns" a block and who has it "borrowed". This is where
garbage collecting languages win: the language keeps track of you
who is using something, and once *nobody* is using it anymore, it
just goes away automatically. But garbage-collectors have a price,
and C does not make you pay it. If you want to implement your own
(in this case a simple reference-counting gc might do the trick),
you can; if you can get away with simple "one owner" accounting,
you do not even have to pay that runtime cost.
 
S

Severian

Mike Wahler ha scritto:


But if malloc returns a void* , how this assignment
is legal (force p that's a int* to a return value that it's void*) ?

A bit confused?

By definition of the C standard, pointer-to-void can be converted to
pointer-to-anything (and vice versa). It makes perfect sense, and I'm
sure someone will chime in with chapter & verse.
 
F

/* frank */

Severian ha scritto:

By definition of the C standard, pointer-to-void can be converted to
pointer-to-anything (and vice versa). It makes perfect sense, and I'm
sure someone will chime in with chapter & verse.

Then, since malloc returns a void*,
it should be done a cast.

int* p;
p = (int*) (malloc ( n * sizeof (int)));


Is it?
 
P

Peter Nilsson

/* frank */ said:
Severian ha scritto:

A pointer to void can be implicitly converted to just about any other pointer (and vice
versa).

The decision to do this was quite deliberate. As to the sense of it... I won't go there.
6.3

Then, since malloc returns a void*,
it should be done a cast.

No. The implicit conversion of void* pointers was made to _avoid_ casts.
int* p;
p = (int*) (malloc ( n * sizeof (int)));

Is it?

The idiom is precisely...

p = malloc(n * sizeof *p);

The cast is only required if you desire the code to be compilable as C++.
 
M

Malcolm

Stephen Ramsay said:
The use of malloc() in most of the books I've read make it sound pretty
straightforward. If you allocate some memory (because the required
amount of space isn't known until runtime), you have to free that space
before the program ends.
The basics are simple. malloc() grabs a block of memory from somewhere and
gives you exclusive use of it. free() puts it back for re-use.
0. Let's suppose that I allocate space for p, but there are branches in
the program that won't actually use p. Do I need to free the memory at
every exit point? Or does the fact that this can happen indicate a bad
design on my part?
Bad design. Usually each call to malloc() should be matched by one and only
one call to free().
1. Let's suppose that I pass p into a function. If that function is the
last one that will ever need p, then presumably I can (and should) free
it. But what if p is also used elsewhere? At a certain point, it seems
like I would have to write some kind of reference counter . . .
Usually you solve this by freeing in the same block that you allocate in.
void foo(void)
{
char *ptr = malloc(N);

strcpy(ptr, "a string");

bar(ptr);

free(ptr);
}

void bar(char *ptr)
{
if(!strcmp(ptr, "That's all folks"))
{
bleep();
/* bad design here, free in foo */
free(ptr);
}

}
2. On a similar note, when I pass a pointer to some allocated memory
as an argument to a function, pass it back out, pass it in somewhere
else, aren't I always dealing with the same memory block? Will it not
sufficeto release the memory after I'm done with all of this, or am I
thinking about it incorrectly?
Yes. In C pointers pass about the address of the same physical block of
memory. However usually a function that receives a pointer to a data item
doesn't need to know whether it is allocated with malloc() or not.
3. Is there anything wrong with just freeing all allocated memory blocks
at every exit point? I realize I might still have other sorts of
problems, but wouldn't this prevent leakage?
It causes huge problems, because you can free memory twice, and you've got
to maintain every path. Sometimes you do need to have more than one matching
free() to each call to malloc(), but only rarely.

Lets take this example

struct tree
{
struct tree *child1;
struct tree *child2;
char data[32];
};

void treefunction(void)
{
struct tree *root = malloc(sizeof(struct tree));
root->child1 = 0;
root->child2 = 0;
strcpy(root->data, "root node");

buildthetree( root );

/* what do we do here ? */
}

void buildthetree(struct tree *root)
{
/* huge function that adds nodes to the tree, allocated with malloc() */
}

The answer is that we write a function

void deletetree(struct tree *root)
{
if(root->child1)
deletetree(root->child1);
if(root->child2)
deletetree(root-<child2);

free(root);
}

Now we call it from the function treefunction() to clean up.

We haven't quite managed to keep to the ideal of a call to malloc() followed
by a matching call to free() in the smae block, but we've come pretty close.
As long as the tree is built correctly the whole thing is controlled and the
chance of a memory leak slipping in is small.
4. What happens if I attempt to free memory that has already been
freed?
It is undefined behaviour, which means anything can happen. Most likely the
computer would segfault or issue a "block corrupted" type warning. However
you could corrupt some vital data and send Mrs Bloggs an electricity bill
for 6 thousand million dollars.
My apologies if all of this seems too basic for this list.
It's a very good question.
 
M

Malcolm

Peter Nilsson said:
No. The implicit conversion of void* pointers was made to _avoid_
casts.
According to Plauger it was a hangover from the looser days of K and R C,
when there was no such thing as a void *, and retained to avoid breaking old
code.
The cast is only required if you desire the code to be compilable as
C++.
That's the main reason for keeping it in. Also to make it readable as C++
for someone who switches a lot between both languages.
 
M

Mac

On Sat, 03 Jul 2004 03:52:04 +0200, Nils O. Selåsdal wrote:

[snip]
Just as as side note, most OS's deallocate dynamically allocated
memory on process termination, thus no need for freeing things when
exiting.

Right. You just want to make sure that you don't do something like this:

p=malloc(n * sizeof *p);

/* code which does not free p or assign its value to another variable */

p=malloc(m * sizeof *p);

That is a memory leak.

Mac
 
H

Herbert Rosenau

Mike Wahler ha scritto:


But if malloc returns a void* , how this assignment
is legal (force p that's a int* to a return value that it's void*) ?

malloc is defined as a fuction returning a pointer to void. The C
standard says clearly that you can assign easy the value of a pointer
to void to a pointer of each type you needs really and you can even
use a pointer of each type in place when a pointer to void is
required. It is the C runtime that makes the conversion for you under
cover.

Each type above means clearly each type of data - not function as
function ponters can never converted to data pointers or the other way
around.
 
H

Herbert Rosenau

Severian ha scritto:



Then, since malloc returns a void*,
it should be done a cast.

int* p;
p = (int*) (malloc ( n * sizeof (int)));


Is it?

Never, really never. This will hide the most common mistake one can
ever do! Without a prototype in sight you will convert garbidge to to
garbidge when you tries to convert an int (that is what C assumes
malloc returns without the prototype in sight) to a pointer.

You knows: C says implicite a fuction without prototype in sight is a
fuction returning int. Many implementations use different locations
for return an int and return an pointer. So you cast fails to convert
something not set to something else, ignoring the return value from
malloc completely or at least partially.

NEVER, rreally NEVER use the cast operator (except you has double
checked the double check that you really KNOWS what you are doing.
castinng a pointer to void to anything else is ALWAYS a big mistake!
Whenever the compiler whines it whines because you are dumb enough to
use the result of malloc (or any other function that returns void*
without a prototype in sight. Correct the error using a unprototyped
function instead to make things with one hand. Use your head and
include the right header.
 
H

Herbert Rosenau

I'm wondering if someone can help me untangle some muddled thinking
about memory allocation in C. I'm writing my first non-trivial app in
C (and having a great time), but I'm finding it difficult to stamp out
memory leaks.

I'm sure most of what I'm about to say is wrong. I'd really be very
grateful to know why.

The use of malloc() in most of the books I've read make it sound pretty
straightforward. If you allocate some memory (because the required
amount of space isn't known until runtime), you have to free that space
before the program ends.

Yes, that it's.
The standard examples go something like this: You need to allocate space
for an array of ints with n elements. When the program knows the value
of n, you can allocate the memory like so:

int *p;

p = malloc(n * sizeof(int));

(I understand from lurking on this list that p = (int *) malloc(n *
sizeof(int)) is deeply offensive to many C fans :)

When I'm done with that array, I need to free it like so:

free(p);
correct.


My way of describing this may not be too precise, but I think I
understand this, and I've been able to use it this way in my programs
without incident.

However, I quickly run into problems the minute things get even slightly
more complex. For example:

0. Let's suppose that I allocate space for p, but there are branches in
the program that won't actually use p. Do I need to free the memory at
every exit point? Or does the fact that this can happen indicate a bad
design on my part?

Doesn't matter. You should allocate dynamic mememory at a point when
you knows you have to use it. Do so on the latest possible logical
point.
- initialise each pointer at creation time - in worst case
with NULL - when you have to create it some steps befor you
use it yet. This saves you weeks of debug time!
- allocate memory for a piece of data. That means one list member,
the whole array or whatever you needs now to work on.
- Initialise it; epically each pointer in it to have all pointer
alwways
in a clean, intitialised state (unused pointer shoulb be clearly
NULL,
not with random content!
- use it
- free it so soon as possible because your program is not the only one
that uses lots of memory. It may give unused memory free for use in
other applications.
- free it so soon as possible because your program may need
another bigger chunk immediately after the action is done.
It helps houseceeping memory accessible on the system and in your
app.
- assign NULL to each pointer and its sibilings when you have free'd
the
memory it points to (superflous only when the pointer itself will
go out of usage and visibility immediately after the free().
That means you allocs memory to a automatic pointer at startup of a
function
and frees it when the function goes straight to return to its caller
For pointers at file or extern scope you should ALWAYS assign NULL
to it
to have clean setup an unused pointer. So the program will crash
definitely
whenever it accesses it at an unwanted time. You can so even call
free()
multiple times without any problem because free(NULL) does
definitely nothing
whereas free(pointer to already free'd memory) invokes undefined
behavior.


1. Let's suppose that I pass p into a function. If that function is the
last one that will ever need p, then presumably I can (and should) free
it. But what if p is also used elsewhere? At a certain point, it seems
like I would have to write some kind of reference counter . . .

Who says that this fuction is definitely the last one? Yeah, You may
still use a helper fuction to allocate memory for the action you are
starting up - and another helper that cleans the action up.

But whatever you do be sure that the logic your program is in any way:
- startup an action (open resources needed by that action)
when not all resources needed accessible: cleanup and exit action or
whole process
- work on the action
On error underway: don't forget to cleanup the resources
before you breaks either the action or the whole process.
- cleanup the action (close resources)
2. On a similar note, when I pass a pointer to some allocated memory as
an argument to a function, pass it back out, pass it in somewhere else,
aren't I always dealing with the same memory block? Will it not suffice
to release the memory after I'm done with all of this, or am I thinking
about it incorrectly?

Depends. Whenever you needs a resoure like files or memory:
- get it ready for use
- use it
- close/free it
- look ehat is to do next. (maybe you starts to use another set of
memory, files,...)
3. Is there anything wrong with just freeing all allocated memory blocks
at every exit point? I realize I might still have other sorts of
problems, but wouldn't this prevent leakage?

No. But it is ever better to free it immediately after it is truly
clear that there is no need for anymore. Whenever you starts again to
use it you starts from scratch - even when your program runs only
again through the same action.
4. What happens if I attempt to free memory that has already been freed?

You starts to go into undefined behavior like you does when you starts
to access it further. Anything can occure like:
- demons flying out of your nose
- the 3. world war starts up
- your home explodes
- your emplolyer will cash back the last 12 month salary from your
bank
- something else

Avoiding it is easy: assign NULL to the pointer you've free()d. So
even when you frees it again nothing happens. Or when you access it
now mistakenly the program will crash immediately. So debugging this
mistake gets easy.

Hint: to handle dynamic memory you should always test malloc() for
success! malloc returns NULL when it fails to deliver the requested
amount of memory.

Hint: sometimes it is more easy to use realloc than malloc() + copy
something + free the old location. But realloc() likes to fail like
malloc(). Assigning the result from realloc() to the same pointer you
give realloc for size change ends up in memory leak! Use a trmprary
pointer instead to store the result. Whenever realloc says that it has
resezed the mempory override the old pointer with the new one. When
realloc returns NULL the old memory (and the pointer points to) left
unchanged. It lefts then to you to do something with it and free() it
when anything is done.

Hint: It is mostenly a bad idea to exit() the program only because
malloc/realloc() fails! You have another resources open that needs a
defined cleanup (like write buffers, close files, free other
memory.....). Often you can recover easy from that error. Let the
higher level of your code decide what is to do in that case.
 

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,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top