Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Generalized function for deallocating and setting pointer to NULL

Reply
Thread Tools

Generalized function for deallocating and setting pointer to NULL

 
 
rocco.rossi@gmail.com
Guest
Posts: n/a
 
      11-29-2007
I've been trying to write a function capable of checking if a pointer
value is set to NULL, and if it isn't, of deallocating and setting
it's value to NULL regardless of the pointer's type. I thought "void
** " should do the trick, but I kept getting the following warning
message from gcc:

warning: passing argument 1 of 'free_var' from incompatible pointer
type

which obviously could be solved by doing an explicit cast to (void **)
in the argument list when calling the fuction. That however would put
an extra burden on the programmer, so I invented the following
solution which works quite well apparently. Please give me your
opinions on this issue.

void free_var(void *vptr)
{
void **ptr = (void **) vptr;

if (ptr != NULL) {
if (*ptr != NULL) {
free(*ptr);
*ptr = NULL;
}
}
}

Thank you.
 
Reply With Quote
 
 
 
 
santosh
Guest
Posts: n/a
 
      11-29-2007
http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:

> I've been trying to write a function capable of checking if a pointer
> value is set to NULL, and if it isn't, of deallocating and setting
> it's value to NULL regardless of the pointer's type. I thought "void
> ** " should do the trick, but I kept getting the following warning
> message from gcc:
>
> warning: passing argument 1 of 'free_var' from incompatible pointer
> type


That's because in C the only pointer type capable of pointing to any
type of data is the void *, not a void **. void ** can only point to a
void * data type.

> which obviously could be solved by doing an explicit cast to (void **)


Not solved, merely suppressed.

> in the argument list when calling the fuction. That however would put
> an extra burden on the programmer, so I invented the following
> solution which works quite well apparently. Please give me your
> opinions on this issue.
>
> void free_var(void *vptr)
> {
> void **ptr = (void **) vptr;
>
> if (ptr != NULL) {
> if (*ptr != NULL) {
> free(*ptr);
> *ptr = NULL;
> }
> }
> }


C's pass by value convention means that this function does not actually
operate on the caller's 'vptr', merely this function's localised copy.
So the caller's 'vptr' is left indeterminate after a call to this
function.

 
Reply With Quote
 
 
 
 
Tomás Ó hÉilidhe
Guest
Posts: n/a
 
      11-29-2007
rocco.rossi:

> I've been trying to write a function capable of checking if a pointer
> value is set to NULL, and if it isn't, of deallocating and setting it's
> value to NULL regardless of the pointer's type. I thought "void ** "
> should do the trick, but I kept getting the following warning message
> from gcc:



void DeallocateAndNullify(void **const pp)
{
free (*pp);

*pp = 0;
}

Passing a null pointer to free has no effect, so there's no need to check
it for null.

You could use macros to pretend that C has "pass by reference", but I
wouldn't suggest it -- because a C programmer assumes their object won't
get altered unless they pass its address.

--
Tomás Ó hÉilidhe
 
Reply With Quote
 
Charlie Gordon
Guest
Posts: n/a
 
      11-29-2007
"Tomás Ó hÉilidhe" <(E-Mail Removed)> a écrit dans le message de news:
NBv3j.23506$(E-Mail Removed)...
> rocco.rossi:
>
>> I've been trying to write a function capable of checking if a pointer
>> value is set to NULL, and if it isn't, of deallocating and setting it's
>> value to NULL regardless of the pointer's type. I thought "void ** "
>> should do the trick, but I kept getting the following warning message
>> from gcc:

>
> void DeallocateAndNullify(void **const pp)
> {
> free (*pp);
>
> *pp = 0;
> }
>
> Passing a null pointer to free has no effect, so there's no need to check
> it for null.


You are right about free(NULL). But your solution is what the OP tried
first and it is not portable because pointer to different types don't all
have the same representation. It means that void ** may not be
inappropriate to store the address of an int *. gcc will give you a warning
if you invoke DeallocateAndNullify(&intp) with int *intp;

You may wonder why in hell C has such constraints... Well most
architectures have a single representation for pointers, and a simple cast
such as DeallocateAndNullify((void**)&intp) will kill the warning but not
cause undefined behaviour. It is utmostly ugly, and you will be tempted to
hide it in a macro, but beyond ugliness, it is error-prone:
DeallocateAndNullify((void**)intp) will go uncaught because you told the
compiler to shut up.

Solutions to this problem are cumbersome, and the one proposed by the OP,
while elegant, has the shortcoming of not catching missing & operators.

It is a major pain that pointers not have a consistent representation, and
the architectures that require extra information for some types are not so
numerous these days. It is actually rather counter productive to encourage
the hardware guys in this direction by keeping support for them.

> You could use macros to pretend that C has "pass by reference", but I
> wouldn't suggest it -- because a C programmer assumes their object won't
> get altered unless they pass its address.


The problem is indeed when the programmer will forget the & operator.

--
Chqrlie.


 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      11-29-2007
(E-Mail Removed) wrote:
> I've been trying to write a function capable of checking if a pointer
> value is set to NULL, and if it isn't, of deallocating and setting
> it's value to NULL regardless of the pointer's type. I thought "void
> ** " should do the trick, but I kept getting the following warning
> message from gcc:
>
> warning: passing argument 1 of 'free_var' from incompatible pointer
> type
>
> which obviously could be solved by doing an explicit cast to (void **)
> in the argument list when calling the fuction. That however would put
> an extra burden on the programmer, so I invented the following
> solution which works quite well apparently. Please give me your
> opinions on this issue.
>
> void free_var(void *vptr)
> {
> void **ptr = (void **) vptr;
>
> if (ptr != NULL) {
> if (*ptr != NULL) {
> free(*ptr);
> *ptr = NULL;
> }
> }
> }


That method will work if you use it as follows:

void *vp = malloc(42);
free_var(&vp);

However, the more typical use of malloc is not guaranteed to work:

int *ip = malloc(42*sizeof(int));
free(&ip); // WRONG

This is because the *ptr expression in free_var has defined behavior
only if the pointed-at pointer actually has the type void*. On many
implementations, all pointers have the same representation, so this cast
happens to work. However, the standard allows each pointer type to have
it's own representation (with certain exceptions that aren't relevant here).

The void* type allows a certain amount of genericity in C, but not
enough to implement this idea as a C function. For this kind of
genericity, you need a macro:

#define FREE_VAR(p) (free(p), (p)=NULL)
 
Reply With Quote
 
CBFalconer
Guest
Posts: n/a
 
      11-29-2007
Charlie Gordon wrote:
> "Tomás Ó hÉilidhe" <(E-Mail Removed)> a écrit:
>> rocco.rossi:
>>
>>> I've been trying to write a function capable of checking if a
>>> pointer value is set to NULL, and if it isn't, of deallocating
>>> and setting it's value to NULL regardless of the pointer's type.
>>> I thought "void ** " should do the trick, but I kept getting the
>>> following warning message from gcc:

>>
>> void DeallocateAndNullify(void **const pp)
>> {
>> free (*pp);
>> *pp = 0;
>> }
>>
>> Passing a null pointer to free has no effect, so there's no need
>> to check it for null.

>
> You are right about free(NULL). But your solution is what the OP
> tried first and it is not portable because pointer to different
> types don't all have the same representation. It means that
> void** may not be inappropriate to store the address of an int*.
> gcc will give you a warning if you invoke
> DeallocateAndNullify(&intp) with int *intp;


No, you can pass that routine any pointer address, and it will be
auto-converted to void**. After that the free will work
correctly. Also, since void** is a pointer to void*, the NULL
assignment works. But it is more clearly written using NULL rather
than 0.

--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Try the download section.



--
Posted via a free Usenet account from http://www.teranews.com

 
Reply With Quote
 
jameskuyper@verizon.net
Guest
Posts: n/a
 
      11-29-2007
CBFalconer wrote:
> Charlie Gordon wrote:
> > "Tom�s � h�ilidhe" <(E-Mail Removed)> a �crit:

...
> >> void DeallocateAndNullify(void **const pp)
> >> {
> >> free (*pp);
> >> *pp = 0;
> >> }
> >>
> >> Passing a null pointer to free has no effect, so there's no need
> >> to check it for null.

> >
> > You are right about free(NULL). But your solution is what the OP
> > tried first and it is not portable because pointer to different
> > types don't all have the same representation. It means that
> > void** may not be inappropriate to store the address of an int*.
> > gcc will give you a warning if you invoke
> > DeallocateAndNullify(&intp) with int *intp;

>
> No, you can pass that routine any pointer address, and it will be
> auto-converted to void**. After that the free will work
> correctly. Also, since void** is a pointer to void*, the NULL
> assignment works. But it is more clearly written using NULL rather
> than 0.


I'm curious - if sizeof(void*) == 6 and sizeof(int*) == 4, how does
that work? Naively, I'd have expected *pp=0 to attempt to set two
extra bytes that aren't actually part of intp.

 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      11-29-2007
CBFalconer <(E-Mail Removed)> writes:
> Charlie Gordon wrote:
>> "Tomás Ó hÉilidhe" <(E-Mail Removed)> a écrit:
>>> rocco.rossi:
>>>> I've been trying to write a function capable of checking if a
>>>> pointer value is set to NULL, and if it isn't, of deallocating
>>>> and setting it's value to NULL regardless of the pointer's type.
>>>> I thought "void ** " should do the trick, but I kept getting the
>>>> following warning message from gcc:
>>>
>>> void DeallocateAndNullify(void **const pp)
>>> {
>>> free (*pp);
>>> *pp = 0;
>>> }
>>>
>>> Passing a null pointer to free has no effect, so there's no need
>>> to check it for null.

>>
>> You are right about free(NULL). But your solution is what the OP
>> tried first and it is not portable because pointer to different
>> types don't all have the same representation. It means that
>> void** may not be inappropriate to store the address of an int*.
>> gcc will give you a warning if you invoke
>> DeallocateAndNullify(&intp) with int *intp;

>
> No, you can pass that routine any pointer address, and it will be
> auto-converted to void**. After that the free will work
> correctly. Also, since void** is a pointer to void*, the NULL
> assignment works. But it is more clearly written using NULL rather
> than 0.


No, you can't. There is no implicit conversion to or from type
void**; there are only implicit conversions to and from type void*,
which is a distinct type.

void* is a generic pointer type. C has *no* generic
pointer-to-pointer type. Something of type void** points to an object
of type void*, and to nothing else.

One way to do what the OP wants is to use a macro, such as;

#define DEALLOCATE(p) (free(p), (p) = NULL)

This fails if the argument is an expression with side effects; the
uppercase name is a hint to avoid calling it with such an argument.

Another way is simply to set the pointer to NULL after freeing it:

free(p);
p = NULL;

or even:

free(p); p = NULL;

(The latter makes it clearer that the two statements are associated,
if you don't mind occasionally putting two statements on one line.
Possibly this could cause problems for debuggers.)

It's easy to forget to set the pointer to NULL after freeing it, but
it's also easy to forget to use DEALLOCATE() rather than free(). But
if you always want to use DEALLOCATE() rather than free(), you can
search your source code for calls to free().

Note that this will prevent some errors, but by no means all of them.
(Actually it doesn't so much prevent errors as make them easier to
detect.) But if a copy of the pointer value has been stored in another
variable, then that copy will not be set to NULL:

p = malloc(...);
p2 = p;
...
DEALLOCATE(p);
/* p == NULL */
/* p2 is indeterminate, and probably still points to the
deallocated memory */

Apart from setting its argument to NULL and evaluating its argument
twice, there is one more difference between free() and DEALLOCATE().
The argument to free() needn't be an lvalue. For example, this is
perfectly legal:

int *p = malloc(10 * sizeof *p);
/* ... */
if (p != NULL) {
p ++;
/* ... */
free(p-1);
}

This call to free() cannot legally be replaced with a call to
DEALLOCATE. Then again, I'd probably consider it poor style anyway.
I suspect that 99+% of calls to free() pass an lvalue expression that
refers to a pointer object (or whose value is NULL).

--
Keith Thompson (The_Other_Keith) <(E-Mail Removed)>
Looking for software development work in the San Diego area.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
CBFalconer
Guest
Posts: n/a
 
      11-29-2007
Keith Thompson wrote:
> CBFalconer <(E-Mail Removed)> writes:
>> Charlie Gordon wrote:
>>> "Tomás Ó hÉilidhe" <(E-Mail Removed)> a écrit:
>>>

.... snip ...
>>>
>>>> void DeallocateAndNullify(void **const pp)
>>>> {
>>>> free (*pp);
>>>> *pp = 0;
>>>> }
>>>>
>>>> Passing a null pointer to free has no effect, so there's no need
>>>> to check it for null.
>>>

.... snip ...
>>
>> No, you can pass that routine any pointer address, and it will be
>> auto-converted to void**. After that the free will work
>> correctly. Also, since void** is a pointer to void*, the NULL
>> assignment works. But it is more clearly written using NULL rather
>> than 0.

>
> No, you can't. There is no implicit conversion to or from type
> void**; there are only implicit conversions to and from type void*,
> which is a distinct type.


You're right, and I was sloppy.

--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Try the download section.



--
Posted via a free Usenet account from http://www.teranews.com

 
Reply With Quote
 
Charlie Gordon
Guest
Posts: n/a
 
      11-29-2007
"CBFalconer" <(E-Mail Removed)> a écrit dans le message de news:
(E-Mail Removed)...
> Keith Thompson wrote:
>> CBFalconer <(E-Mail Removed)> writes:
>>> Charlie Gordon wrote:
>>>> "Tomás Ã" hÃ?ilidhe" <(E-Mail Removed)> a écrit:
>>>>

> ... snip ...
>>>>
>>>>> void DeallocateAndNullify(void **const pp)
>>>>> {
>>>>> free (*pp);
>>>>> *pp = 0;
>>>>> }
>>>>>
>>>>> Passing a null pointer to free has no effect, so there's no need
>>>>> to check it for null.
>>>>

> ... snip ...
>>>
>>> No, you can pass that routine any pointer address, and it will be
>>> auto-converted to void**. After that the free will work
>>> correctly. Also, since void** is a pointer to void*, the NULL
>>> assignment works. But it is more clearly written using NULL rather
>>> than 0.

>>
>> No, you can't. There is no implicit conversion to or from type
>> void**; there are only implicit conversions to and from type void*,
>> which is a distinct type.

>
> You're right, and I was sloppy.


Apology accepted.

--
Chqrlie.


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
pointer to pointer intialize to NULL but still point to NULL Christopher C++ 4 07-09-2011 12:35 AM
Function adapters, currying: how to build a generalized binder? Giovanni Gherdovich C++ 2 08-18-2008 12:52 PM
Null pointer (NULL array pointer is passed) aneuryzma C++ 3 06-16-2008 05:48 AM
Best way of Allocating and Deallocating memory Amit_Basnak C++ 7 09-18-2007 08:02 AM
"stringObj == null" vs "stringObj.equals(null)", for null check?? qazmlp1209@rediffmail.com Java 5 03-29-2006 10:37 PM



Advertisments