void* type 
Author Message
 void* type

I know void* means an arbitrary pointer. In an interview, I was asked to
write a routine that swaps two pointers.

I tried with this

void Swap(void** p1, void** p2)
{
  void* p = *p1;
  *p1 = *p2;
  *p2 = *p;

Quote:
}

but it is not correct, because void* is not allowed as operand.

How should I do?

--
Huayong

WWW home pages:                           Email:



Wed, 02 Sep 1998 03:00:00 GMT  
 void* type

Quote:

>I know void* means an arbitrary pointer. In an interview, I was asked to
>write a routine that swaps two pointers.
>I tried with this
>void Swap(void** p1, void** p2)

This is a routine to swap two "void *". It is _not_ a general pointer-
swapping routine.

Quote:
>{
>  void* p = *p1;
>  *p1 = *p2;
>  *p2 = *p;

If you swap two integers, you don't dereference your "swap" variable.
You should _not_ do so when dealing with pointers.

   *p2 = p;

would be good enough in a routine that swaps two void pointers.

Quote:
>}
>but it is not correct, because void* is not allowed as operand.

It is not allowed to dereference a void *, not is it necessary in
this example.

Kurt
--
| Kurt Watzka                             Phone : +49-89-2180-6254




Thu, 03 Sep 1998 03:00:00 GMT  
 void* type


: >void Swap(void** p1, void** p2)

: It is not allowed to dereference a void *, not is it necessary in
: this example.

I agree. But you forgot to give an answer to Huayong.
Please enlighten us with *your* solution to this problem.

The best I could directly think of is :

void swap(void ** x, void ** y)
{
        char * tmp;

        tmp = *( (char**)x );
        *( (char**)x ) = *( (char**)y );
        *( (char**)y ) = tmp;

Quote:
}

You would call it for
        SomeType * x, * y
sth like
        swap((void**)&x,(void**)&y);
to avoid "incompatible pointer type"-warnings.

Best regards

        Claus



Sat, 12 Sep 1998 03:00:00 GMT  
 void* type
I am opening myself here, but I think the example with only
assign the contents of the first memory address at whatever x and
y point to. You may want to check this out in a de{*filter*}... If I
am wrong it is only because I didn't take the time to follow my
own advise...


Sun, 13 Sep 1998 03:00:00 GMT  
 void* type

Quote:



>: >void Swap(void** p1, void** p2)
>: It is not allowed to dereference a void *, not is it necessary in
>: this example.
>I agree. But you forgot to give an answer to Huayong.
>Please enlighten us with *your* solution to this problem.
>The best I could directly think of is :
>void swap(void ** x, void ** y)
>{
>    char * tmp;

There is _no_ need to make this a char*. It can well be a void *, and
you don't need any casts.

Quote:
>    tmp = *( (char**)x );

How about

    tmp = *x;

There is nothing wrong with dereferencing a pointer to pointer to void.

Quote:
>    *( (char**)x ) = *( (char**)y );
>    *( (char**)y ) = tmp;
>From the same line of thought comes

   *x = *y;
   *y = tmp;

Quote:
>}
>You would call it for
>    SomeType * x, * y

I would _not_ call it for anything but void pointers or char pointers,
because there is no generic pointer to pointer type in C, and the only
pointer type that must have the same representation as a void pointer
is a char pointer.

Quote:
>sth like
>    swap((void**)&x,(void**)&y);
>to avoid "incompatible pointer type"-warnings.

Avoiding warnings in this case means that you tell the compiler you know
what you are doing. If you know what you are doing, for example, if you
know that all pointer types will have the same representation on all
machines that your program will ever run on, go ahead.

If this is not the case, you cannot write such a function using pointers
to pointers. You can still write a generic swap(), but it takes two
void pointers as it's arguments, and it has an additional "size"
parameter. Such a generic swap function can fail, and it can be used
to swap two pointers to SomeType:

   #include <string.h>

   int
   swap(void *a, void *b, size_t sz)
   {
      void *tmp;

      tmp = malloc(sz);
      if (tmp == NULL)
         return 0;
      memcpy(tmp, a, sz);
      memcpy(a, b, sz);
      memcpy(b, tmp, sz);
      return 1;
   }

   SomeType *a, b;

   if (!swap(&a, &b))
      /* die whining */

Kurt
--
| Kurt Watzka                             Phone : +49-89-2180-6254




Sun, 13 Sep 1998 03:00:00 GMT  
 void* type



 >

 >
 >: >void Swap(void** p1, void** p2)
 >
 >: It is not allowed to dereference a void *, not is it necessary in
 >: this example.
 >
 >I agree. But you forgot to give an answer to Huayong.
 >Please enlighten us with *your* solution to this problem.

There isn't a simple generic solution to this problem.

 >The best I could directly think of is :
 >
 >void swap(void ** x, void ** y)
 >{
 >        char * tmp;
 >
 >        tmp = *( (char**)x );
 >        *( (char**)x ) = *( (char**)y );
 >        *( (char**)y ) = tmp;

You're treating the object being swapped as if it is a char *. If it
isn't a char * then this may not work - it results in undefined behaviour.

 >}
 >
 >You would call it for
 >        SomeType * x, * y
 >sth like
 >        swap((void**)&x,(void**)&y);
 >to avoid "incompatible pointer type"-warnings.

The warnings are there to indicate that you're doing something very wrong.
Simply shutting up the warnings is shooting yourself in the foot. Pointer
casting like this is rarely a sensible thing to do.

--
-----------------------------------------


-----------------------------------------



Sun, 13 Sep 1998 03:00:00 GMT  
 void* type

Quote:
(Kurt Watzka) writes:

|> If this is not the case, you cannot write such a function using pointers
|> to pointers. You can still write a generic swap(), but it takes two
|> void pointers as it's arguments, and it has an additional "size"
|> parameter. Such a generic swap function can fail, and it can be used
|> to swap two pointers to SomeType:

|>    #include <string.h>

|>    int
|>    swap(void *a, void *b, size_t sz)
|>    {
|>       void *tmp;

|>       tmp = malloc(sz);
|>       if (tmp == NULL)
|>          return 0;
|>       memcpy(tmp, a, sz);
|>       memcpy(a, b, sz);
|>       memcpy(b, tmp, sz);

I think you forgot:

        free( tmp ) ;

Otherwise, you are guaranteed that the function will return 0 if you
call it often enough:-).

|>       return 1;
|>    }

|>    SomeType *a, b;

|>    if (!swap(&a, &b))
|>       /* die whining */

And you forgot your own extra parameter:-):

    if ( ! swap( &a , &b , sizeof( SomeType ) )
        ...

BTW, I've found that a small optimizing trick in functions like this can
sometimes work wonders for performance:

    int
    swap( void* a , void* b , size_t sz )
    {
        unsigned char   buffer[ EXPECTEDMAXSIZE ] ;
        void*           tmp = (sz <= sizeof( buffer ))
                                ? buffer
                                : malloc( sz ) ;
        if ( tmp == NULL )
            return 0 ;
        memcpy(tmp, a, sz);
        memcpy(a, b, sz);
        memcpy(b, tmp, sz);
        if ( tmp != buffer )
            free( tmp ) ;
        return 1 ;
    }
--

GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle --
                            -- Beratung in industrieller Datenverarbeitung



Tue, 15 Sep 1998 03:00:00 GMT  
 void* type

: BTW, I've found that a small optimizing trick in functions like this can
: sometimes work wonders for performance:

:     int
:     swap( void* a , void* b , size_t sz )
:     {
:         unsigned char   buffer[ EXPECTEDMAXSIZE ] ;

An even smaller "trick" : use a static array instead.

Anyway.

What still nags at me about the portability issue :
Is there a machine still in use (Kurt, please name it)
on which the representation of a
        double *
differs from the representation of a
        char *
?

Have a nice week-end

        Claus



Thu, 17 Sep 1998 03:00:00 GMT  
 void* type

Quote:


>(Kurt Watzka) writes:

[snip]

Quote:
>|>    SomeType *a, b;

>|>    if (!swap(&a, &b))
>|>       /* die whining */

>And you forgot your own extra parameter:-):

And you forgot one ")" in:
Quote:

>    if ( ! swap( &a , &b , sizeof( SomeType ) )
>        ...

Or perhaps you moved it up to your smiley  :)

And everyone's missed that interesting declaration for a and b
so far.  Reminds me of a recent thread  :)

Quote:

>BTW, I've found that a small optimizing trick in functions like this can
>sometimes work wonders for performance:

>    int
>    swap( void* a , void* b , size_t sz )
>    {
>        unsigned char   buffer[ EXPECTEDMAXSIZE ] ;
>        void*           tmp = (sz <= sizeof( buffer ))
>                                ? buffer
>                                : malloc( sz ) ;

Or, if you don't need reentrant or resursive code, you can do:
        static void *tmp = NULL;
        static size_t tmp_sz = 0;

        if (sz > tmp_sz) {
            .... use realloc here .... you get the idea ....

Details left to the reader (I'm feeling lazy tonight  :)

This avoids having to guess what EXPECTEDMAXSIZE might be,
but also suffers from never freeing that buffer.  OTOH, it might
end up avoiding zillions of calls to malloc if the guess was poor.
I've had a couple of thing like that bite when data formats
were changed, and I had code inherited from people long-gone.

The realloc can certainly do something like use sz+10000
to "grow" the tmp area in tunable chunks, depending on the application.

Cheers,
Stan.
--



Thu, 17 Sep 1998 03:00:00 GMT  
 void* type

Quote:
Ryckman) writes:



|> >BTW, I've found that a small optimizing trick in functions like this can
|> >sometimes work wonders for performance:
|> >
|> >    int
|> >    swap( void* a , void* b , size_t sz )
|> >    {
|> >        unsigned char   buffer[ EXPECTEDMAXSIZE ] ;
|> >        void*           tmp = (sz <= sizeof( buffer ))
|> >                                ? buffer
|> >                                : malloc( sz ) ;

|> Or, if you don't need reentrant or resursive code, you can do:
|>   static void *tmp = NULL;
|>   static size_t tmp_sz = 0;

|>   if (sz > tmp_sz) {
|>       .... use realloc here .... you get the idea ....

I wish I'd have thought of this when I actually encountered the problem.
In the real case, the original author of the function had used multiple
returns, and I had a bit of a job finding all of the places where I had
to insert the `free'.  (The original code simply overwrote the rest of
the stack if sz were larger than EXPECTEDMAXSIZE.  Which sort of
explains why I was looking at it in the first place:-).)

|> Details left to the reader (I'm feeling lazy tonight  :)

|> This avoids having to guess what EXPECTEDMAXSIZE might be,
|> but also suffers from never freeing that buffer.  OTOH, it might
|> end up avoiding zillions of calls to malloc if the guess was poor.
|> I've had a couple of thing like that bite when data formats
|> were changed, and I had code inherited from people long-gone.

|> The realloc can certainly do something like use sz+10000
|> to "grow" the tmp area in tunable chunks, depending on the application.

Better yet: unless memory is really tight, have it double the size.
This will set a fairly reasonable upper bound on the number of reallocs
you will have to do.
--

GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle --
                            -- Beratung in industrieller Datenverarbeitung



Fri, 18 Sep 1998 03:00:00 GMT  
 void* type

|>
|> : BTW, I've found that a small optimizing trick in functions like this can
|> : sometimes work wonders for performance:
|>
|> :     int
|> :     swap( void* a , void* b , size_t sz )
|> :     {
|> :         unsigned char   buffer[ EXPECTEDMAXSIZE ] ;
|>
|> An even smaller "trick" : use a static array instead.

What improvement do you hope to gain with a static array?

Konrad Schwarz



Fri, 18 Sep 1998 03:00:00 GMT  
 void* type

Quote:

> What still nags at me about the portability issue :
> Is there a machine still in use (Kurt, please name it)
> on which the representation of a
>         double *
> differs from the representation of a
>         char *
> ?

Well, I'm not Kurt, but as I recall the Data General Eclipse
series of computers used 32-bit byte addresses for (char *)
and 31-bit word addresses for (double *).  Word addresses had
to be left-shifted by one to create the equivalent byte address,
and vice versa.  (If I recall correctly, DG used the top
bit of a word address to do some funky indirect addressing.)

Caveat: this was back in my fortran days; I don't think I
ever worked with a C compiler on that machine, but I don't
see how it could have avoided using different representations
for character pointers and other pointers.



Fri, 18 Sep 1998 03:00:00 GMT  
 void* type
Perhaps I'm confused but when I read the question this is what I came
up with.  It compiles and worked as expected in a test case.

As far as the two pointers to be swapped are concerned, they are of
the same type correct?

I do not see the problem with:

void swap_ptr(void **p1, void **p2) {
  void *tmp = *p1;

  *p1 = *p2;
  *p2 = tmp;

  return;

Quote:
}

Granted I did not do an extensive test but I did try ints, chars and floats
with no surprises. As in:

#include <stdio.h>
#include"swap_ptr.h"

int main(void) {
  char c1='A', c2='B', *pc1, *pc2;
  int  i1=1, i2=2, *pi1, *pi2;
  float f1=1.1, f2=2.2, *pf1, *pf2;

  pc1 = &c1;
  pc2 = &c2;
  pi1 = &i1;
  pi2 = &i2;
  pf1 = &f1;
  pf2 = &f2;

  printf("%c , %c\n", *pc1, *pc2);
  swap_ptr(pc1, pc2);
  printf("%c , %c\n", *pc1, *pc2);

  printf("%d, %d\n", *pi1, *pi2);
  swap_ptr(pi1, pi2);
  printf("%d, %d\n", *pi1, *pi2);

  printf("%f, %f\n", *pf1, *pf2);
  swap_ptr(pf1, pf2);
  printf("%f, %f\n", *pf1, *pf2);

  return(0);

Quote:
}

The output looks like:

r980(davidm)$ main
A , B
B , A
1, 2
2, 1
1.100000, 2.200000
2.200000, 1.100000
r980(davidm)$

Could someone enlighten me as to why this thread is so long?

Thanks
Dave



Fri, 18 Sep 1998 03:00:00 GMT  
 void* type



 :  >
 :  >: >void Swap(void** p1, void** p2)
[...]
 : There isn't a simple generic solution to this problem.

I think it is an example of a ridiculous question.  What is wrong with this:

    Some_Type *a, *b;
       .
       .
    if (some_condition_has_occured_where_a_and_b_need_swapped)
      {
         Some_Type *tmp;
         tmp = a; a = b; b = tmp;
      }
--
John E. Davis                   Center for Space Research/AXAF Science Center
617-258-8119                    MIT 37-662c, Cambridge, MA 02139
http://space.mit.edu/~davis



Fri, 18 Sep 1998 03:00:00 GMT  
 void* type

Quote:
> > The realloc can certainly do something like use sz+10000
> > to "grow" the tmp area in tunable chunks, depending on the application.

> Better yet: unless memory is really tight, have it double the size.
> This will set a fairly reasonable upper bound on the number of reallocs
> you will have to do.

Better yet: change "unless memory is really tight" to "if memory is
plentiful".  The doubling method can run out of memory when the amount
available is almost twice the amount that you need, not even considering
the possibility of fragmentation.
--
Mark Brader              "I always pass on good advice.  It's the only thing

SoftQuad Inc., Toronto       -- Lord Goring  (Oscar Wilde: An Ideal Husband)

My text in this article is in the public domain.



Fri, 18 Sep 1998 03:00:00 GMT  
 
 [ 41 post ]  Go to page: [1] [2] [3]

 Relevant Pages 

1. void type pointers

2. can char ** be passed to void * type?

3. adding with void type problem

4. void type

5. Purpose of casting a void type

6. why do we need *void* type?

7. void pointer (void *) : how to determine type?

8. HRESULT return type turns into void when adding class from type library

9. from void (void*) to void (_cdecl*) (void*)

10. what's the difference between void main(void) and int main(void)

11. difference between void foo(void) and void foo()

12. memory of type void

 

 
Powered by phpBB® Forum Software