free memory question

M

MN

Hi all,
Suppose that I have the next program. My question is where to free the
pointer (ptr) dynamically allocated in function "test_free"?
Freeing "ptr" before return (), implies that "calc" will be lost, then
int the next function "add_data", "calc" will point to NULL pointer.

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

struct node
{
int x;
struct node* y;
};

struct node* test_free (struct node* calc, int a, int b);
struct node* add_data (struct node* calc, int c);

int main ()
{
struct node* calc = NULL;

int a = 5;
int b = 2;
int c = 3;

calc = test_free(calc, a, b);
printf("1- Value of x is %d\n", (int)calc -> x);

calc = add_data (calc, c);
printf("2- Value of x is %d\n", (int)calc -> x);

return (0);
}

struct node* test_free (struct node* calc, int a, int b)
{
struct node* ptr;

if (!ptr)
free(ptr);

ptr = (struct node*)malloc(sizeof(struct node));

ptr -> x = a*b;
ptr -> y = NULL;

calc = ptr;
free(ptr); //<---- here the problem
return (calc);
}

struct node* add_data (struct node* calc, int c)
{
calc -> x = (calc -> x)+ c;
return (calc);
}

After excuting I got
1- Value of x is 0
2- Value of x is 3

What I want is
1- Value of x is 10
2- Value of x is 13
 
I

Ian Collins

MN said:
Hi all,
Suppose that I have the next program. My question is where to free the
pointer (ptr) dynamically allocated in function "test_free"?
Freeing "ptr" before return (), implies that "calc" will be lost, then
int the next function "add_data", "calc" will point to NULL pointer.
struct node* test_free (struct node* calc, int a, int b)
{
struct node* ptr;

if (!ptr)
free(ptr);
That's a very silly thing to do. ptr isn't initialised, so it will have
an undefined value.
ptr = (struct node*)malloc(sizeof(struct node));
Just declare ptr here and drop the unnecessary cast.
ptr -> x = a*b;
ptr -> y = NULL;

calc = ptr;
free(ptr); //<---- here the problem
return (calc);

return isn't a function, so drop the parenthesis.

Why not just return ptr and free it when you have finished with it?
 
I

Ian Collins

MN said:
In my case I must return calc to use it after in other functions like
"Add_data".

Which part of my replay are you replying to? Please keep enough context
for your post to make sense.
 
F

Flash Gordon

MN wrote, On 14/11/08 07:56:
Hi all,
Suppose that I have the next program. My question is where to free the
pointer (ptr) dynamically allocated in function "test_free"?
Freeing "ptr" before return (), implies that "calc" will be lost, then
int the next function "add_data", "calc" will point to NULL pointer.

Free it when you no longer need it but *not* before.
include <stdio.h>
#include <stdlib.h>

struct node
{
int x;
struct node* y;
};

struct node* test_free (struct node* calc, int a, int b);
struct node* add_data (struct node* calc, int c);

int main ()

Whilst not an error, it would be better to be explicit about the lack of
parameters...
int main(void)
{
struct node* calc = NULL;

int a = 5;
int b = 2;
int c = 3;

calc = test_free(calc, a, b);
printf("1- Value of x is %d\n", (int)calc -> x);

Why the cast?
free(calc);
calc = add_data (calc, c);
printf("2- Value of x is %d\n", (int)calc -> x);

free(calc);
return (0);
}

struct node* test_free (struct node* calc, int a, int b)
{
struct node* ptr;

if (!ptr)
free(ptr);

What the? ptr is a local variable which you have not initialised. If it
points to allocated memory it is mere chance and probably not memory you
want to free. Delete *both* of the above lines.

Well, if you had used calc rather than ptr...
ptr = (struct node*)malloc(sizeof(struct node));

Loose the cast, it doesn't buy you anything. Also you can simplify it by
using sizeof an object and combining with the declaration of ptr...
struct node* ptr = malloc(sizeof *ptr);

See? Far less typing and far less to get wrong.
ptr -> x = a*b;
ptr -> y = NULL;

calc = ptr;

Why assign it to calc? It won't affect the variable named calc in main!
In fact, I don't know why you passed it in (well, I do, you did it
because you have not fully understood parameter passing in C yet).

You need to look at the comp.lang.c FAQ at http://c-faq.com/ which
explains the issue. I've run out of time to look up the correct section
myself as I have to go to work.
free(ptr); //<---- here the problem

Loose the free as you have not yet finished with the pointed to data.
return (calc);

You don't need the parenthesis, I would save a few keystrokes and do
return ptr;
}

struct node* add_data (struct node* calc, int c)
{
calc -> x = (calc -> x)+ c;
return (calc);
}

After excuting I got
1- Value of x is 0
2- Value of x is 3

What I want is
1- Value of x is 10
2- Value of x is 13

Fix it as above and you will.
 
M

MN

That's a very silly thing to do. ptr isn't initialised, so it will have
an undefined value.


Just declare ptr here and drop the unnecessary cast.



return isn't a function, so drop the parenthesis.


Why not just return ptr and free it when you have finished with it?
In my case I must return calc to use it after in other functions like
"Add_data".
 
I

Ian Collins

MN said:
In my case I must return calc to use it after in other functions like
"Add_data".

You can't return something you have freed, just return ptr and free it
when you have finished with it.
 
V

vippstar

That's a very silly thing to do. ptr isn't initialised, so it will have
an undefined value.

I agree. Assuming ptr was initialized, it's still something silly to
do; if(!ptr) means if ptr is NULL, and free(NULL) is a no-op.
I also wanted to mention that ptr formally will have an indeterminate
value, which is either an unspecified value or a trap representation.
 
J

jameskuyper

blargg said:
I thought all pointers to anything in the freed block became
indeterminate. Thus, attempts to do anything with the pointers (copy,
compare, etc.) leads to undefined behavior,

The term 'anything' is too extreme. If you access the object
containing the pointer value as array of unsigned char, the behavior
is defined.
... rather than actually returning
said pointer. See 7.20.3 and 6.2.4.

Most uses of such pointers lead to undefined behavior, which might
include actually returning said pointer. That's true, even if the
'use' did not involve a 'return' statement. :)
 
J

Joachim Schmitz

blargg said:
Joachim said:
Ian said:
MN wrote:
MN wrote: [...]
ptr = (struct node*)malloc(sizeof(struct node));
Just declare ptr here and drop the unnecessary cast.

ptr -> x = a*b;
ptr -> y = NULL;
calc = ptr;
free(ptr); //<---- here the problem
return (calc);
return isn't a function, so drop the parenthesis.

Why not just return ptr and free it when you have finished with
it?

In my case I must return calc to use it after in other functions
like "Add_data".

You can't return something you have freed,

Of course you can. Whether it's a wise thing to do is another
question.

I thought all pointers to anything in the freed block became
indeterminate. Thus, attempts to do anything with the pointers (copy,
compare, etc.) leads to undefined behavior, rather than actually
returning said pointer. See 7.20.3 and 6.2.4.

I didn't mean to suggest that you can do something with that pointer (other
than return it)

Bye, Jojo
 
H

Harald van Dijk

I didn't mean to suggest that you can do something with that pointer
(other than return it)

But that's just it: you can't even return it. When you try to return it,
you read the already indeterminate value from an object, and this is not
allowed, even if you only return the value to discard it.
 
J

Joachim Schmitz

Harald said:
But that's just it: you can't even return it. When you try to return
it, you read the already indeterminate value from an object, and this
is not allowed, even if you only return the value to discard it.

Ah, OK, got it now, thanks.

Bye, Jojo
 
A

Andrew Smallshaw

I thought all pointers to anything in the freed block became
indeterminate. Thus, attempts to do anything with the pointers (copy,
compare, etc.) leads to undefined behavior, rather than actually returning
said pointer. See 7.20.3 and 6.2.4.

When you free a block of memory with a pointer the pointer itself
is still valid and is completely unaltered by the free. The object
pointed to is no longer valid though, so dereferencing the pointer
leads to undefined behaviour. However, the pointer itself is
available for re-use if it is needed for another object.
 
A

Andrew Smallshaw

But that's just it: you can't even return it. When you try to return it,
you read the already indeterminate value from an object, and this is not
allowed, even if you only return the value to discard it.

No, it is perfectly legal to return the pointer if you wish to do
so. It just doesn't make any sense to do so since any attempt to
dereference the pointer is undefined. A pointer is logically
distinct from the object it references.
 
H

Harald van Dijk

No, it is perfectly legal to return the pointer if you wish to do so.
It just doesn't make any sense to do so since any attempt to dereference
the pointer is undefined. A pointer is logically distinct from the
object it references.

6.2.4p2:
"The value of a pointer becomes indeterminate when the object it points to
reaches the end of its lifetime."

3.17.2p1:
"indeterminate value
either an unspecified value or a trap representation"

6.2.6.1p5:
"Certain object representations need not represent a value of the object
type. If the stored value of an object has such a representation and is
read by an lvalue expression that does not have character type, the
behavior is undefined. [...] Such a representation is called a trap
representation."

No, you are not allowed to read a pointer to a freed object. It's true
that doing so anyway probably won't cause problems, but the language
doesn't actually allow it.
 
C

CBFalconer

Andrew said:
When you free a block of memory with a pointer the pointer itself
is still valid and is completely unaltered by the free. The
object pointed to is no longer valid though, so dereferencing the
pointer leads to undefined behaviour. However, the pointer
itself is available for re-use if it is needed for another object.

Wrong. After the free, the pointer itself is completely unaltered,
but it IS NO LONGER VALID, because it no longer points to available
memory. The only safe thing you can do with it is to overwrite it.
 
J

James Kuyper

Andrew said:
When you free a block of memory with a pointer the pointer itself
is still valid and is completely unaltered by the free.

You've just described some language other than C. The sections of the C
standard cited above say that the pointer's value is indeterminate, and
that any attempt to use it has undefined behavior. Using the value
includes copying it, as is done when you return from a function.

Some people have misinterpreted this clause as giving free() the right
to actually modify the object representation of the pointer object. I
don't believe that this is allowed; but whether or not it is allowed,
it's not necessary. There are real, popular machines where a pointer can
become invalid just because it points to a block of memory that your
program no longer has a right to use, even though it used to. What the
standard says about free() was written to accomodate the behavior of
such systems.
The object
pointed to is no longer valid though, so dereferencing the pointer
leads to undefined behaviour. However, the pointer itself is
available for re-use if it is needed for another object.

The pointer object is available for re-use, to store a new pointer
value; but the pointer value certainly cannot be safely re-used.
 
J

James Kuyper

Richard said:
James Kuyper said:


I don't think so. I think he's just saying that the pointer *object* still
exists. ...

Keep in mind the context:

calc = ptr;
free(ptr);
return calc;

It's the pointer value that is stored in both calc and ptr that becomes
invalid as a result of the free(ptr). Copying the value stored in either
pointer object is undefined behavior, and the return statement does in
fact involve copying the value of calc.
...After all, he does go on to say that the pointer can't be
dereferenced.

Saying that it can't be dereferenced is insufficient. It also can't be
copied. Or compared for equality with other pointers. Even the simple
statement:

calc;

technically has undefined behavior, though I'd expect any decent
compiler to optimize that statement out of existence.
That's what he said, isn't it? Admittedly somewhat clumsily.

I got the distinct impression that he thought that the pointer value
could be safely copied by the return statement. If so, he was wrong. If
not, his comment was less relevant than I thought it was intended to be.
 
N

Nate Eldredge

James Kuyper said:
You've just described some language other than C. The sections of the
C standard cited above say that the pointer's value is indeterminate,
and that any attempt to use it has undefined behavior. Using the value
includes copying it, as is done when you return from a function.

Some people have misinterpreted this clause as giving free() the right
to actually modify the object representation of the pointer object. I
don't believe that this is allowed; but whether or not it is allowed,
it's not necessary. There are real, popular machines where a pointer
can become invalid just because it points to a block of memory that
your program no longer has a right to use, even though it used
to. What the standard says about free() was written to accomodate the
behavior of such systems.

I think the part that's confusing is that "a pointer becoming invalid"
apparently includes the possibility of its becoming a trap
representations.

It's completely intuitive to expect that derefencing a pointer after
it's passed to free() would be bad. IMHO it's much less intuitive that
reading the pointer at all could be bad.

I think any programmer from the past 40 years would understand that

int x, *p, *q;
/* set p to point to some malloc'ed array of int */
free(p);
x = *p;

is not safe. It's easy to imagine what could go wrong. (For example,
maybe free() unmaps the page that p pointed to.) But

free(p);
q = p;

or even

free(p);
printf("Look Ma, I just freed the pointer %p\n", (void *)p);

are a lot more subtle; there's a lot of machines on which there's no
conceivable way that these could be a problem. It makes me uneasy,
wondering how often I've done this sort of thing in my own code without
noticing.

Actually, I find the idea of trap representations pretty confusing in
general. Just based on my (admittedly limited) experience, it's hard to
get used to the idea of a machine where there are certain poisonous bit
patterns which may not even be loaded into a register. (This is
especially hard to stomach for a type like `int'.) And it's made even
worse by the fact that the set of such bit patterns is not fixed, but
can change behind your back. It seems that if p contains the bit
pattern 0x12345678, then 0x12345678 is not a trap representation before
I call `free(p)', but afterwards, it is.

I know there's always a tradeoff between supporting diverse systems and
having a language that is simple and easy to understand. This is a
situation that has me thinking that the standard authors may have gone
too far to the former side. I'm happy to be convinced otherwise, however.
 

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

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top