Problem with use of 'void **'

Ken Raeburn raeburn at athena.mit.edu
Sun May 27 06:32:19 AEST 1990


In article <1990May25.012342.10144 at csis.dit.csiro.au>
peterf at csis.dit.csiro.au (Peter A Fletcher) writes:
|> >
|> >I would like to be able to write a routine which can pass
|> >a block of memory back to the caller, so the obvious way
|> >to do this is by passing a pointer to a pointer of any
|> >type - 'void **' seems the natural way to do this (using
|> >'void *' would allow passing addresses of non-pointers,
|> >which is a definite no-no).

That does seem like the logical way to do it, assuming the return value of
the routine is used for some other purpose.

|> >void problem(void **a, int l)
|> >{
|> >    *a = malloc(l);
|> >}
|> >typedef char fiftychars[50];
|> >int main(int argc, char *argv[])
|> >{
|> >    fiftychars *a;
|> >    problem(&a, 50);

|> >void.c:18: warning: argument passing between incompatible pointer types

In article <1990May26.011714.7624 at druid.uucp>, darcy at druid.uucp (D'Arcy
J.M. Cain) confuses the issue by writing:

|> First of all the typedef says that an array of fifty character is created
|> when fiftychars is declared.  However, you declare a to be a *pointer* to
|> this array of 50 chars.  In effect your declaration has become:
|>     char	**a;
|> since the 50 characters have not actually been allocated.  Note that you
|> *must* have the extra size parameter for problem.

... and continues to get more confused from there.

Chris Torek posted a good detailed article a little while ago about
arrays.  I don't have a copy handy, but I'll try to briefly explain.  For
purposes of explanation, I will use "fiftyints" instead of "fiftychars";
some similarities between "void *" and "char *" are required, but they are
distinct, and the similarities can cause confusion.

In main:
	*a	is	array[50] of int
	a	is	ptr to array[50] of int
	&a	is	ptr to ptr to array[50] of int
In problem:
	a	is	ptr to ptr to void

The "char **" explanation is comparable to saying that by modifying *a,
one could modify the address of the array.  This doesn't make sense, but
neither does the conversion of array to pointer in this context.  The
variable "a" is not pointing to a pointer, but to an array.

(It's sort of akin to the error of claiming that "int x[3][3]" and "int
**x" are equivalent.)

The general reason for requiring the type mismatch is that the pointers
involved are pointing to

	foo *
and	void *

which can have different representations.  If "int *" and "void *" are
represented differently, then converting between the two is a (presumably)
simple operation that the compiler can incorporate.  However, "int **" and
"void **" are not at all compatible, since you'd wind up with a pointer of
type "void **" that points to memory in which you want to store a pointer
in "int *" format (or vice versa), and that information cannot be
maintained.

Although "char *" and "void *" are pretty much constrained to have the
same representation, they aren't exempted from this compatibility
constraint.

The fix I would suggest would be:

	void problem (void **a, int l) {
		*a = malloc (l);
	}
	typedef char fiftychars[50];
	int main () {
		fiftychars *a;
		void *vp;
		problem (&vp, 50); a = vp;
		/* ... */
	}

or something similar....

Chris, as I recall, your article explained things quite clearly; do you
have a copy you can repost?



More information about the Comp.lang.c mailing list