[comp.lang.c] Generic Swap

wozniak@utkux1.utk.edu (Bryon Lape) (06/11/90)

	Recently I tried to write a generic swap routine using void
pointers, but it did not work.  Below is an example:

#include<stdio.h>

void generic_swap(void *, void *);

main()
{
   short int x=4, y=50;

   printf("\n%d  %d", x ,y);
   generic_swap(&x, &y);
   printf("\n%d  %d", x, y);
}

generic_swap(void *, void *)
{
   void *temp;

   temp = b;
   b = a;
   a = temp;
}

	I ran this in Quick C 2.0 and the values DID exchange within the
function, but not on the outside.  Anyone know what might be wrong?


-bryon lape-

whipple@sun.udel.edu (Peter Adams Whipple) (06/11/90)

In article <1990Jun11.133729.6575@cs.utk.edu> wozniak@utkux1.utk.edu (Bryon Lape) writes:
>
>	Recently I tried to write a generic swap routine using void
>pointers, but it did not work.  Below is an example:

[stuff deleted]

>generic_swap(void *, void *)
>{
>   void *temp;
>
>   temp = b;
>   b = a;
>   a = temp;
>}

You are swapping the pointer (which are local values) instead of
swapping the values (*a and *b).  If you can use *a, *b, and *temp, the
routine will work as expected.  Off-hand, I don't remember if you can
dereference a void *.

-- Peter

karl@haddock.ima.isc.com (Karl Heuer) (06/11/90)

In article <1990Jun11.133729.6575@cs.utk.edu> wozniak@utkux1.utk.edu (Bryon Lape) writes:
>generic_swap(void *, void *) {
>   void *temp;   temp = b;  b = a;  a = temp;
>}

[0] This won't even compile, since you left out the names of the arguments.
Please, people, try to post code fragments directly from the test source if
possible, rather than keying them in.

[1] You have the wrong level of indirection.  The objects to be swapped were
passed by reference, so you need to dereference them (`*a', `*b') in order to
swap the actual objects.  But you can't, because this routine doesn't know the
types of the pointed-to objects.  You could use
	void generic_swap(void *pa, void *pb, size_t n) {
	    void *ptmp = malloc(n);  assert(ptmp != NULL);
	    memcpy(ptmp, pb, n);  memcpy(pb, pa, n);  memcpy(pa, ptmp, n);
	}
but this is pretty silly.  Just code the bloody thing inline, rather than
trying to use a generic routine.

[2] Note to readers: please don't followup this thread unless you've already
read the relevant part of the Frequently Asked Questions document, and have
something *new* to say.  I don't want to see the XOR hack being discussed to
death again.

Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint

dankg@sandstorm.Berkeley.EDU (Dan KoGai) (06/12/90)

>swap the actual objects.  But you can't, because this routine doesn't know the>...You could use
>	void generic_swap(void *pa, void *pb, size_t n) {
>	    void *ptmp = malloc(n);  assert(ptmp != NULL);
>	    memcpy(ptmp, pb, n);  memcpy(pb, pa, n);  memcpy(pa, ptmp, n);
>	}
>but this is pretty silly.  Just code the bloody thing inline, rather than
>trying to use a generic routine.

	I agree:  Usually we don't swap objects so large that requires
memcpy().  Instead we swap pointers to the objects.  But C sometimes
allows assignment of objects larger than size of register, such as
structs and some compilers allow to pass structs as arguments (not ptr
to structs).  Here's my quick & dirty macro

void *temp;
#define swap(type, x, y) temp = (type *)malloc(sizeof(type));\
	*(type)temp = x; x = y ; y = *(type)temp; free(temp)

	Since this is a macro, it should work even though your compiler
does not allow passing structs as arguments (struct assignment is valid
since K&R while struct as argument is not).  But since it's a macro,
handle with care (even better for C++ #inline)

>[2] Note to readers: please don't followup this thread unless you've already
>read the relevant part of the Frequently Asked Questions document, and have
>something *new* to say.  I don't want to see the XOR hack being discussed to
>death again.

	Since I haven't seen my macro version, I decided to follow.

Dan Kogai (dankg@ocf.bekeley.edu)

zhu@cs.jhu.edu (Benjamin Zhu) (06/13/90)

In article <1990Jun11.214844.21531@agate.berkeley.edu> dankg@sandstorm.Berkeley.EDU (Dan KoGai) writes:
>>swap the actual objects.  But you can't, because this routine doesn't know the>...You could use
>>	void generic_swap(void *pa, void *pb, size_t n) {
>>	    void *ptmp = malloc(n);  assert(ptmp != NULL);
>>	    memcpy(ptmp, pb, n);  memcpy(pb, pa, n);  memcpy(pa, ptmp, n);
>>	}
>>but this is pretty silly.  Just code the bloody thing inline, rather than
>>trying to use a generic routine.
>
>	I agree:  Usually we don't swap objects so large that requires
>memcpy().  Instead we swap pointers to the objects.  But C sometimes
>allows assignment of objects larger than size of register, such as
>structs and some compilers allow to pass structs as arguments (not ptr
>to structs).  Here's my quick & dirty macro
>
>void *temp;
>#define swap(type, x, y) temp = (type *)malloc(sizeof(type));\
>	*(type)temp = x; x = y ; y = *(type)temp; free(temp)
	  ^^^^			       ^^^^
	I suppose you want to write (type *) instead. Otherwise, it
	looks OK. 

>
>	Since this is a macro, it should work even though your compiler
>does not allow passing structs as arguments (struct assignment is valid
>since K&R while struct as argument is not).  But since it's a macro,
>handle with care (even better for C++ #inline)
>
>>[2] Note to readers: please don't followup this thread unless you've already
>>read the relevant part of the Frequently Asked Questions document, and have
>>something *new* to say.  I don't want to see the XOR hack being discussed to
>>death again.
>
>	Since I haven't seen my macro version, I decided to follow.
>
>Dan Kogai (dankg@ocf.bekeley.edu)

Benjamin Zhu

+=========================================================================+
+Disclaimer:								  +
+	I do not represent Johns Hopkins, Johns Hopkins does not	  +
+	represent me either.						  +
+==========================================================================

karl@haddock.ima.isc.com (Karl Heuer) (06/13/90)

In article <1990Jun11.214844.21531@agate.berkeley.edu> dankg@sandstorm.Berkeley.EDU (Dan KoGai) writes:
>void *temp;
>#define swap(type, x, y) temp = (type *)malloc(sizeof(type));\
>	*(type)temp = x; x = y ; y = *(type)temp; free(temp)

Those casts don't make sense.  I think you want
	#define swap(type, x, y) temp = malloc(sizeof(type));\
	*(type *)temp = x; x = y ; y = *(type *)temp; free(temp)

>	Since this is a macro, it should work even though your compiler
>does not allow passing structs as arguments (struct assignment is valid
>since K&R while struct as argument is not).

Wrong.  The three forms of struct copy (assignment, pass by value, return by
value) were all added at the same time, shortly after K&R 1 was published.

Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint