473,394 Members | 1,696 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

Pointer to Pointer Paramters (aka void **)

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

Aug 6 '06 #1
7 2054

bw*****@yahoo.com 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.

Aug 7 '06 #2

bw*****@yahoo.com 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

Aug 7 '06 #3

Snis Pilbor wrote:
bw*****@yahoo.com 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.

Aug 7 '06 #4
bw*****@yahoo.com 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)
Aug 7 '06 #5

Richard Heathfield wrote:
bw*****@yahoo.com 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. =)

Aug 7 '06 #6
Snis Pilbor said:
>
Richard Heathfield wrote:
>bw*****@yahoo.com 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: <11**********************@m79g2000cwm.googlegroups .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)
Aug 7 '06 #7

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

Message-ID: <11**********************@m79g2000cwm.googlegroups .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.

Aug 7 '06 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: wallacej | last post by:
Does anybody know why unsigned char myImage; works but unsigned char myImage; does not? I think its because the second line is a value too big for unsigned char, is this ...
2
by: Bruno van Dooren | last post by:
Hi All, i have some (3) different weird pointer problems that have me stumped. i suspect that the compiler behavior is correct because gcc shows the same results. ...
14
by: mauri1106 | last post by:
Hi, I have a little problem with a pointer. In my project is included an ".h" file with this declaration: "#define pMDMA_D0_START_ADDR ((void * volatile *)MDMA_D0_START_ADDR)" If I assign a...
22
by: ypjofficial | last post by:
Is there any possibility of invoking the member functions of a class without creating an object (or even a pointer to ) of that class. eg. #include <iostream.h> class test { public: void...
6
by: cbull | last post by:
class A { }; class B: public A { void f(); }; typedef void (A::*MPA)(void); MPA mpA;
27
by: Erik de Castro Lopo | last post by:
Hi all, The GNU C compiler allows a void pointer to be incremented and the behaviour is equivalent to incrementing a char pointer. Is this legal C99 or is this a GNU C extention? Thanks in...
33
by: Ney André de Mello Zunino | last post by:
Hello. I have written a simple reference-counting smart pointer class template called RefCountPtr<T>. It works in conjunction with another class, ReferenceCountable, which is responsible for the...
20
by: MikeC | last post by:
Folks, I've been playing with C programs for 25 years (not professionally - self-taught), and although I've used function pointers before, I've never got my head around them enough to be able to...
10
by: vcquestions | last post by:
Hi. Is there way to have a function pointer to a delegate in c++/cli that would allow me to pass delegates with the same signatures as parameters to a method? I'm working with managed code. ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.