Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Pointer to Pointer Paramters (aka void **)

Reply
Thread Tools

Pointer to Pointer Paramters (aka void **)

 
 
bwaichu@yahoo.com
Guest
Posts: n/a
 
      08-06-2006
In some APIs, we see char ** or void ** as a parameter. I never
distinguished between declaring a variable as char **x and passing x as
the parameter from declaring a variable char *x and passing &x. I also
consider the two the same. And since I debug everything I write, I
also saw know difference while debugging. I have also used them pass
data in and out of functions as well.

Now, I was pointed out today that there is a difference. I was even
pointed out this is addressed in the standards.

What I would like to know is what is the proper way to handle APIs that
have functions with void ** parameters.

One interesting item brought up is that I might end up overwriting a
previously declared variable.
Anyway, I hope to learn more.

Brian

 
Reply With Quote
 
 
 
 
J. J. Farrell
Guest
Posts: n/a
 
      08-07-2006

wrote:
> In some APIs, we see char ** or void ** as a parameter. I never
> distinguished between declaring a variable as char **x and passing x as
> the parameter from declaring a variable char *x and passing &x. I also
> consider the two the same. And since I debug everything I write, I
> also saw know difference while debugging. I have also used them pass
> data in and out of functions as well.
>
> Now, I was pointed out today that there is a difference. I was even
> pointed out this is addressed in the standards.
>
> What I would like to know is what is the proper way to handle APIs that
> have functions with void ** parameters.
>
> One interesting item brought up is that I might end up overwriting a
> previously declared variable.
> Anyway, I hope to learn more.


It's not at all clear what you're confused about. Parameters to
functions are defined to be of certain types, and you must pass
parameters of those types (or ones which get automatically converted to
those types) when you call the function. If the parameter type is 'int'
you must pass an int; if it's 'struct frooble *' you must pass a
pointer to a struct frooble; if it's 'void **' you must pass a pointer
to a pointer to void.

 
Reply With Quote
 
 
 
 
Snis Pilbor
Guest
Posts: n/a
 
      08-07-2006

wrote:
> In some APIs, we see char ** or void ** as a parameter. I never
> distinguished between declaring a variable as char **x and passing x as
> the parameter from declaring a variable char *x and passing &x. I also
> consider the two the same. And since I debug everything I write, I
> also saw know difference while debugging. I have also used them pass
> data in and out of functions as well.
>


In my experience any time a function takes char ** or void **
arguments, it is for one of the following reasons:
1. the function depends not on a single char * or void * but on a
contiguous block of such, or
2. the function is meant to destructively alter the char * or void *,
for example a swap function

If the first usage is what is going on here, then that usage would not
realize its full potential unless some calling function declares the
variable as char **x and passes x. If in every single case, the
calling function declares the variable as char *x and passes &x, well,
then the fancy contiguous block code is kind of pointless (or should I
say "pointerless") since it only actually ever receives "contiguous
blocks" of size 1!

Nonetheless, I agree with you that there is no real difference.

Snis Pilbor

 
Reply With Quote
 
Snis Pilbor
Guest
Posts: n/a
 
      08-07-2006

Snis Pilbor wrote:
> wrote:
> > In some APIs, we see char ** or void ** as a parameter. I never
> > distinguished between declaring a variable as char **x and passing x as
> > the parameter from declaring a variable char *x and passing &x. I also
> > consider the two the same. And since I debug everything I write, I
> > also saw know difference while debugging. I have also used them pass
> > data in and out of functions as well.
> >

>
> In my experience any time a function takes char ** or void **
> arguments, it is for one of the following reasons:
> 1. the function depends not on a single char * or void * but on a
> contiguous block of such, or
> 2. the function is meant to destructively alter the char * or void *,
> for example a swap function
>
> If the first usage is what is going on here, then that usage would not
> realize its full potential unless some calling function declares the
> variable as char **x and passes x. If in every single case, the
> calling function declares the variable as char *x and passes &x, well,
> then the fancy contiguous block code is kind of pointless (or should I
> say "pointerless") since it only actually ever receives "contiguous
> blocks" of size 1!
>
> Nonetheless, I agree with you that there is no real difference.
>
> Snis Pilbor


Thinking about this a little more, I realized, you could in theory use
a void * to store the address to a whole contiguous buffer of void *'s.
This would probably be quite confusing, though I can see how in some
very highly obscure cases it could actually be indispensible. So in
the case of void, there is actually a third option, which is for the
caller to pass (void **) x, as so:

void **buf;
void *ptr;

buf = malloc( 100 * sizeof( void * ) );
ptr = buf;
nullify_pointer_array( (void **) ptr, 100 );

I wonder if such scandalous code as this would ever actually be useful,
or if it is just a funny example. (Of course in the above example,
"nullify_pointer_array(buf,100)" would do the same thing and be 100
times clearer)

S.P.

 
Reply With Quote
 
Richard Heathfield
Guest
Posts: n/a
 
      08-07-2006
said:

> In some APIs, we see char ** or void ** as a parameter. I never
> distinguished between declaring a variable as char **x and passing x as
> the parameter from declaring a variable char *x and passing &x. I also
> consider the two the same.


Clearly, they aren't.

char *x;
char **y;
strtod(s, &x); /* &x is the address of an object of type char *. */
strtod(s, y); /* y is an indeterminate value */

> And since I debug everything I write, I
> also saw know difference while debugging.


You have now learned - I hope - that debugging is not sufficient. You have
to know what you're doing, too.

<snip>

> What I would like to know is what is the proper way to handle APIs that
> have functions with void ** parameters.


It depends on what those functions are trying to do. Knowing the prototype
for a function is insufficient. You have to understand the semantics of
that function, too.

In the case of strtod, what it is trying to tell you is the address of a
character - the first character it couldn't convert. If it were written
like this: char *strtod(char *s); that would be an easier way for it to
tell you that address, but then it wouldn't be able to return the double!
And it can't just be written like this: double strtod(char *s, char
*endptr); because if it were, it wouldn't matter how much strtod tried to
change the value of endptr - it would have no effect whatsoever on the char
* that you passed in! That's because C is a pass-by-value language, always.
And so strtod's designer(s) went for the next option, which is to take the
address of a char * object. Why? So that they can store into that char *
object the address of the first character they couldn't convert. Now, for
that to be a legitimate thing to do, that object must ***exist***! And
that's why it's insufficient to use char **endptr; What you /could/ do is
this:

char *endptr;
char **intermediatevalue = &endptr;
double d = strtod(s, intermediatevalue);

and endptr now points to the first unconverted character. That code would
have just the same validity, because now the value you are passing to
strtod really is the address of a valid object.

> One interesting item brought up is that I might end up overwriting a
> previously declared variable.


The C Standard does not place limits on the possible outcomes of undefined
behaviour.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
 
Reply With Quote
 
Snis Pilbor
Guest
Posts: n/a
 
      08-07-2006

Richard Heathfield wrote:
> said:
>
> > In some APIs, we see char ** or void ** as a parameter. I never
> > distinguished between declaring a variable as char **x and passing x as
> > the parameter from declaring a variable char *x and passing &x. I also
> > consider the two the same.

>
> Clearly, they aren't.
>
> char *x;
> char **y;
> strtod(s, &x); /* &x is the address of an object of type char *. */
> strtod(s, y); /* y is an indeterminate value */
>


I think when the OP said "declaring a variable as char **x and passing
x", it was implicitly assumed x would be initialized before being used.
I'm nitpicking here because I wouldn't want someone to be confused by
your post and think, "never declare char **y, it's automatically a Bad
Thing".

char *x;
char **y;

y = malloc( 50 * sizeof( char * ) );

nullify_char_pointers( y, 50 );
nullify_char_pointers( &x, 1 );

Here the fact we call nullify_char_pointers on &x is silly since we
could've just said "x=NULL", but the point is besides silliness there's
no difference between the two calls.

The OP was particularly concerned about passing with &x (where x is
char *) being more potentially destructive than passing with x (where x
is char **). At first I thought this was indeed a concern, but
reflecting on it, they are equally safe despite intuition. In order
for the function to act destructively, it would have to act on the
dereferenced input. If it does this, it will act destructively
regardless of how the input is passed, and if not, then not. I think.

S.P. =)

 
Reply With Quote
 
Richard Heathfield
Guest
Posts: n/a
 
      08-07-2006
Snis Pilbor said:

>
> Richard Heathfield wrote:
>> said:
>>
>> > In some APIs, we see char ** or void ** as a parameter. I never
>> > distinguished between declaring a variable as char **x and passing x as
>> > the parameter from declaring a variable char *x and passing &x. I also
>> > consider the two the same.

>>
>> Clearly, they aren't.
>>
>> char *x;
>> char **y;
>> strtod(s, &x); /* &x is the address of an object of type char *. */
>> strtod(s, y); /* y is an indeterminate value */
>>

>
> I think when the OP said "declaring a variable as char **x and passing
> x", it was implicitly assumed x would be initialized before being used.


You think so? Then you might want to check out the original code he posted
that prompted this discussion:

Message-ID: < .com>

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
 
Reply With Quote
 
bwaichu@yahoo.com
Guest
Posts: n/a
 
      08-07-2006

Richard Heathfield wrote:

> You think so? Then you might want to check out the original code he posted
> that prompted this discussion:
>
> Message-ID: < .com>


And he was completely right. I overlooked my approach thinking both of
the approaches were valid, but both approaches are clearly not valid.
But the process for me to understand that took some doing. The program
compiled fine. The program "worked". And my debug session worked out
fine. But what I was doing was wrong. The compiler did not even warn
me until I turned on an additional flag per the suggestion of one of
the folks in that thread. And that flag was an optimization flag, not
even warning related. This was a tough item to learn because
everything appeared to be working fine.

Thanks Richard. Sorry about my difficulty in learning this item.
Everything appeared to work and that made the learning process more
difficult.

 
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
What is the difference between void proba(); and void proba(void); ??? PencoOdStip@gmail.com C++ 1 05-23-2007 07:12 PM
Conversion from 'void*' to pointer to non-'void' requires an explicit cast Hakirato C++ 4 10-05-2006 04:02 PM
what is the difference, void func(void) and void fucn() noblesantosh@yahoo.com C Programming 5 07-22-2005 04:38 PM
"void Method()" vs "void Method(void)" Ollej Reemt C++ 7 04-22-2005 03:47 AM
`void **' revisited: void *pop(void **root) Stig Brautaset C Programming 15 10-28-2003 09:03 AM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57