Casting void * to void ** ?

B

Bill Pursell

Richard Heathfield wrote, in reference to casting void * to void **:
I see no need for it, and you're right - it sounds like a bad idea. Not bad
in itself, exactly, but it's a hint that someone, somewhere, is either
assuming or just hoping(!) that void ** carries with it the same guarantees
that void * does - but, alas, this is not the case.

There's a perfectly valid reason for it: here's a function that takes
a pointer to a multidimensional array of unknown size, and dereferences
a value. (or, rather, returns a void pointer to the requested value,
which the caller can then dereference, since the caller knows the
type.)

void *dereference_array(void *A, int dim, unsigned int *coord)
{
if (dim ==1)
return (void **)A + coord[0];
else
return dereference_array(*((void **)(A)+coord[0]), dim-1,
coord+1);
}
 
R

Richard Heathfield

Joe Smith said:
'void**' reminds me of the Escher drawing of the hand drawing the hand and
the peculiar way Goedel regarded his.

Escher is more like this: void *e = &e; /* self-reference */

Goedel: volatile int *g = (int *)&PROBLEM; assert(g == g); /* might fire */

I'll fire up that source you posted
when I begin my campaign tomorrow to Take Over the Week. My methods for
handling memory are childish. I think what I'll try to do is take the
eratosthenos algorithm down yonder and have the user tell the prog how
large
an N we have.

Eratosthenes' Sieve is a completely different kettle of fish to Euclid's
Algorithm, and is perhaps a much better example of where you might need to
manage memory in some significant way. You can cut down on the amount of
RAM you need for the Sieve by using bits as flags, and by not bothering
with, say, even numbers, but if you want to build a seriously big Sieve,
you're going to need some serious RAM. For example, even if you restrict
yourself to, say, 32-bit unsigned integers, and don't bother to represent
even numbers (even though ignoring them makes your loop a bit more fiddly),
and use 1 bit per number, you still need 2^31 bits, or 2^27 bytes. This is
about 128 MB!

There are, incidentally, faster and less memory-intensive ways to determine
primality.
 
W

Walter Roberson

Joe Smith said:
Escher is more like this: void *e = &e; /* self-reference */

The scope of the variable e does not begin until after the end of
its declarator, so the second appearance of e in that expression
is not a reference to the first. Also, &e would be of type void **
which brings us back to the discussion about whether void ** will
be converted to void * by an assignment...
 
J

Joe Smith

"Richard Heathfield"
Joe Smith said:


Escher is more like this: void *e = &e; /* self-reference
But there's two hands:
while (condition)
{
*g = &f;
*f = &g;
}
Goedel: volatile int *g = (int *)&PROBLEM; assert(g == g); /* might fire
*/
Actually, I was talking about how the cat walked around looking like
Nosferatu with long, black gloves. You gotta wonder about how his neural
pathways looked on the instruments capable of doing f, f**-1 .
presently. Joe
 
J

Jordan Abel

The scope of the variable e does not begin until after the end of
its declarator, so the second appearance of e in that expression
is not a reference to the first. Also, &e would be of type void **
which brings us back to the discussion about whether void ** will
be converted to void * by an assignment...

Are you sure? It Seems To Work (tm) on GCC, and for it to work would be
a violation of the standard if it says what you think it says.

(and, yes, void ** will be converted to void * by assignment. why
wouldn't it be?)
 
J

Joe Smith

"Richard Heathfield"
Joe Smith said:
[funny stuff snipped]

I've been writing elementary programs to knock some of the rust off my
game
here. Both Professors Knuth and Gallian start with Euclid's algortihm.
I
would like to implement it with the memory techniques at the beginning of
_Unleashed_

I'm not sure why you'd need memory techniques for Euclid's Algorithm.

You can find an implementation on p326 of CU. Alternatively, here's my
own,
relatively straightforward, implementation of Knuth's description of
Euclid's Algorithm in TAOCP:

You and Knuth solved this using recursion, where the computer worries about
providing for its own memory.
unsigned long gcd(unsigned long m, unsigned long n)
{
if(n == 0)
{
/* Caller doesn't know what he's doing. It's not
* our job to bomb out, so we'll simply return an
* impossible result - 0 - to match our impossible
* input.

Interesting way to say it.
*/
}
else if(m < n)
{
n = gcd(n, m);
}
else
{
unsigned long r = m % n;
if(r > 0)
{
n = gcd(n, r);
}
}
return n;
}
[snip]
For better or worse, I'm going to attempt sieve4.c in which
p = malloc(n + 1);
appears. It would seem to me to be a necessary skill. Joe
 
B

Ben Pfaff

The scope of the variable e does not begin until after the end of
its declarator,

This is correct.
so the second appearance of e in that expression is not a
reference to the first.

This is wrong. Declarations and declarators are distinct
concepts. The declarator is *e. The initializer follows the
declarator.
 
J

Jordan Abel

"Richard Heathfield"
Joe Smith said:
[funny stuff snipped]

I've been writing elementary programs to knock some of the rust off
my game here. Both Professors Knuth and Gallian start with Euclid's
algortihm. I would like to implement it with the memory techniques
at the beginning of _Unleashed_

I'm not sure why you'd need memory techniques for Euclid's Algorithm.

You can find an implementation on p326 of CU. Alternatively, here's
my own, relatively straightforward, implementation of Knuth's
description of Euclid's Algorithm in TAOCP:

You and Knuth solved this using recursion, where the computer worries about
providing for its own memory.

This can be done iteratively. Mechanical iterative conversion below,
probably should be rewritten to use a real loop.
Interesting way to say it.
->> n = gcd(n, m);
+ int tmp = n;
+ n = m;
+ m = tmp;
+ goto top;+ m = n; n = r;
+ goto top;
->> n = gcd(n, r);
}
}
return n;
}
[snip]
For better or worse, I'm going to attempt sieve4.c in which
p = malloc(n + 1);
appears. It would seem to me to be a necessary skill. Joe
 
R

Richard Heathfield

Walter Roberson said:
The scope of the variable e does not begin until after the end of
its declarator,
Right.

so the second appearance of e in that expression
is not a reference to the first.

Wrong. But you can have a consolation prize - it was something similar that
prompted Dan Pop to say "the expression isn't unclear *at all*, and only an
expert could possibly have any doubts about it".
Also, &e would be of type void **

Right. So?
which brings us back to the discussion about whether void ** will
be converted to void * by an assignment...

It will. An automatic conversion is supplied in the special case of void *
(in either direction), as I'm sure you knew already but had temporarily
forgotten.
 
R

Richard Heathfield

Joe Smith said:
"Richard Heathfield"

You and Knuth solved this using recursion, where the computer worries
about providing for its own memory.

Actually, I did but Knuth didn't. Here is an even more straightforward
implementation of Knuth's description of Euclid's Algorithm in TAOCP,
without using recursion:

unsigned long gcd(unsigned long m, unsigned long n)
{
if(m < n)
{
unsigned long temp = m;
m = n;
n = temp;
}
if(n > 0)
{
unsigned long r;
do
{
r = m % n;
m = n;
n = r ? r : n;
} while(r > 0);
}

return n;
}
 
J

Joe Smith

"Richard Heathfield"
Joe Smith said:

The reason, for better or worse, that I think I need a memory technique
might have to do with the development as given by Gallian. We had the
division algorithm that would be guaranteed to terminate in a finite number
of steps, and then we had to rewrite all the equations and substitute, so as
to write a given N as a linear combo. I'm failing to see how this stack of
numbers behaves in your treatment. With a debugger that is only telling me
'no matching symbolic information found', I am unable to step through.
Actually, I did but Knuth didn't. Here is an even more straightforward
implementation of Knuth's description of Euclid's Algorithm in TAOCP,
without using recursion:

unsigned long gcd(unsigned long m, unsigned long n)
{
if(m < n)
{
unsigned long temp = m;
m = n;
n = temp;
}
if(n > 0)
{
unsigned long r;
do
{
r = m % n;
m = n;
n = r ? r : n;
} while(r > 0);
}

return n;
}
I guess what I'll do is add some printf's and breaks and do some figgerin.
Joe
 
J

Joe Smith

Richard Heathfield said:
Joe Smith said:


Actually, I did but Knuth didn't. Here is an even more straightforward
implementation of Knuth's description of Euclid's Algorithm in TAOCP,
without using recursion:

unsigned long gcd(unsigned long m, unsigned long n)
{
if(m < n)
{
unsigned long temp = m;
m = n;
n = temp;
}
if(n > 0)
{
unsigned long r;
do
{
r = m % n;
m = n;
n = r ? r : n;
} while(r > 0);
}

return n;
}

Bear with me, please. Elsethread:
I've elaborated on this theme and seek comment. I have a debugger now, so
my programming IQ just got a bump. Joe
 

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,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top