2

I need to create a swap function that takes 2 addresses as input and swaps them regardless what type they point to. Here's my swap function:

void swap(void* x,void* y){
  void* temp=x;
  x=y;
  y=temp;
}

When I use it with integers it works fine and swaps them properly, but using strings the addresses seems to swap inside the function but when I try to call them from outside the function I notice they didn't change at all.

Here's my full code and the resulting output.

  printf("before %s %s\n",(char*)array[i],(char*)array[j] );
  swap(array[i], array[j]);
  printf("after %s %s\n",(char*)array[i],(char*)array[j] );

I casted everything to string to understand what was wrong with them

void swap(void* x,void* y){
  printf("  after IN %s %s\n",(char*)x,(char*)y );
  void* temp=x;
  x=y;
  y=temp;
  printf("  after IN %s %s\n",(char*)x,(char*)y );
}

OUTPUT

before fannullone falafel
  after IN fannullone falafel
  after IN falafel fannullone
after fannullone falafel
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
ramaswag
  • 71
  • 5
  • 3
    Code shown won't swap two ints correctly. All it does is shuffle some local variables. – John3136 Aug 30 '22 at 08:19
  • Remember that arguments are passed *by value*. This means that the value used in the call will be *copied* into the functions local argument variables. Any modifications to these variables will only be made on the variables, the original value will not be changed. To solve your issue you need to *emulate pass by reference*, by passing pointer to the original variables themselves. – Some programmer dude Aug 30 '22 at 08:20
  • 1
    You *always* need to pass pointers to the *variables* you want to swap! Inside your swap function you should swap the values, not the pointers. – Aconcagua Aug 30 '22 at 08:20
  • Hm... Problem with the `void*` pointer is that you don't know what it points to – how would you know how much size the temporary needs to store a copy of one of the objects to swap? What if you try to swap objects composed of a bunch of contained variables? – Aconcagua Aug 30 '22 at 08:26
  • 2
    You cannot write such a generic function without an additional argument that specifies _the size of the data_ to swap. -- As others already say, you are currently only swapping local pointers, not the values they point to. Look at parameters as additional local variables. – the busybee Aug 30 '22 at 08:26
  • @Aconcagua Thanks I now fixed it by doing `swap(void** x, void** y)` and `void swap(void** x,void** y){ void* temp=*x; *x=*y; *y=temp; }` – ramaswag Aug 30 '22 at 08:33
  • 1
    @ramaswag Be ware that you still cannot swap arbitrary objects that way. Trying to swap e.g. `int`s might fail miserably, as size of `void*` most likely is larger than size of `int` and you'll be swapping additional memory! Only swapping pointers is reliably possible that way (and only if all pointers are of same size – which *usually* is the case, though)! – Aconcagua Aug 30 '22 at 08:38
  • @Aconcagua it luckily swaps `int` too in my case, I understand what you're saying though and I'll keep that in mind thanks! – ramaswag Aug 30 '22 at 08:45

2 Answers2

3

To swap two objects in a function you need to pass them to the function by reference.

In C passing by reference means passing objects indirectly through pointers to them. So dereferencing the pointers the function gets a direct access to the original objects and can change them.

So for objects of the type void * the function parameters will have the type void **. The function will look like

void swap( void **x, void **y )
{
    void *temp = *x;
    *x = *y;
    *y = temp;
}

Here is a demonstration program.

#include <stdio.h>

void swap( void **x, void **y )
{
    void *temp = *x;
    *x = *y;
    *y = temp;
}

int main( void ) 
{
    void *s1 = "Hello";
    void *s2 = "World";

    printf( "s1 = %s, s2 = %s\n", ( char * )s1, ( char * )s2 );

    swap( &s1, &s2 );

    printf( "s1 = %s, s2 = %s\n", ( char * )s1, ( char * )s2 );
}

The program output is

s1 = Hello, s2 = World
s1 = World, s2 = Hello
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

It cannot be done with a function because there is no generic pointer to pointer in C. For example the type void** is not compatible with char**. Technically, those pointers could have different representation what would disallow dereferencing after casting or using memcpy().

Therefore, it is better to use a macro:

#define SWAP(a, b)     \
   do {                \
     void *tmp = *(a); \
     *(a) = *(b);      \
     *(b) = tmp;       \
   } while (0)
tstanisl
  • 13,520
  • 2
  • 25
  • 40