0

Is it possible to swap two variables without using ref/out keyword in C#(i.e. by using unsafe)?

for ex,

        swap(ref x,ref y);//It is possbile to by passing the reference

But, Is there any other way of doing the same thing. In the swap function you can use a temp variable. But, How to swap the variables without using ref/out keywords in C#?

0

8 Answers 8

4

A (very!) contrived example using delegates:

class Program
{
    static void FunkySwap<T>(T a, T b, Action<T> setA, Action<T> setB)
    {
        T tempA = a;
        setA(b);
        setB(tempA);
    }
    static void Main(string[] args)
    {
        string s1 = "big";
        string s2 = "apples";
        Console.WriteLine("BEFORE, s1: {0}, s2: {1}", s1, s2);
        FunkySwap(s1, s2, a => s1 = a, b => s2 = b);
        Console.WriteLine("AFTER,  s1: {0}, s2: {1}", s1, s2);
    }
}

While the above is pretty silly, using a delegate setter method can be useful in other situations; I've used the technique for implementing undo/redo of property modifications.

Sign up to request clarification or add additional context in comments.

5 Comments

That's quite nice (well, it's quite horrible, but it's nice as an answer), since we can't pass the variables without ref or faking ref with pointers or object-containment, you pass in the function instead! Good lateral thinking.
Even though it looks nothing alike, this is a duplicate of Michael Shimmins's answer.
@Ben Voigt: how so? His allocates a new struct, mine uses delegates and changes the original references.
Ah, you're right, returning a struct is not so similar. However your use of closures is exactly the same as putting the values to be swapped into a class instance, calling a function to swap the members, and then reading them back from the class instance, because that's what the MSIL code actually does.
@Ben Voigt: well, there's a big difference in the generated MSIL code - but you're right that there's a fair amount of overhead which isn't visible from the C# code. At each call site we get two Action objects constructed, and FunkySwap() performs two virtual method calls. The Swapable solution has a much shorter call site, allocates a single new object, and only does simple field load/store in Swap() :)
3

With tuples

int a = 4, b = 8;
(a, b) = (b, a);

Comments

2

No, it's not possible to affect variables* in the caller without the use of ref or out pass-by-reference. You could affect class members, but how would you know which ones you were being asked to swap?

*(You can affect instances of reference types and the changes will be visible to the caller, but instances are not "variables".)

2 Comments

Well he's asking if unsafe Can be used and since unsafe code blocks allow pointers it's incorrect to state that it Can be done without ref or out
@Rune: You're just making a pass-by-ref parameter without using the ref keyword. That does meet the letter of the question, I just have to wonder if it meets the spirit.
1

Not really, unless your only issue with ref is a dislike of the word itself.

You can swap through pointers, like:

public unsafe void Swap(int* x, int* y)
{
    unsafe
    {//lets not use a temp, just to be different!
        *x ^= *y;
        *y ^= *x;
        *x ^= *y;
    }
}

But really the only practical difference is all the pointer pitfalls that references save you from, along with the fact that it has to be unsafe. It's basically doing the same thing.

Comments

1

I tried this

class Program
{
    static void Main(string[] args)
    {
        int x = 3;
        int y = 6;
        Console.Write(string.Format("before swap x={0} y={1}", x, y));
        Swap(x, y);
        Console.Write(string.Format("after swap x={0} y={1}", x, y));
        Console.ReadKey();
    }

    static public unsafe void Swap(int a, int b)
    {
        int* ptrToA = &a;
        int* ptrToB = &b;
        int c = a;
        *ptrToB = c;
        *ptrToB = *ptrToA;
    }
}

And completely forgot that ints are passed by value, and there is no way I can take a pointer of something that is actually COPIED from the caller to the callee stack.

so it doesn't work

So it seems, instead of being smarter, I just wasted some time but want to share that with you anyway :)

Comments

0

You could pass the values in an object and return an instance of that object with the values swapped:

public struct Swapable
{
    public int A;
    public int B;
}

public Swapable Swap(Swapable swapable)
{
    return new Swapable()
    {
        A = swapable.B;
        B = swapable.A;
    };
}

Comments

0

I have tried using unsafe and it works, see the code

namespace ConsoleApplication2
{
class myclass
{
    public unsafe void swap(int *x, int *y)
    {
        unsafe
        {
            int temp = 0;
            temp = *x;
            *x = *y;
            *y = temp;
            Console.WriteLine("Using Swap1");
            Console.WriteLine("x:"+*x);
            Console.WriteLine("y:" + *y);
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        unsafe
        {
            int x = 10;
            int y = 20;
            int* t1 = &x;
            int* t2 = &y;
            myclass m1 = new myclass();
            m1.swap(t1,t2);
            Console.WriteLine("Main");
            Console.WriteLine("x: " + x);
            Console.WriteLine("y: " + y);
            Console.ReadLine();

        }
    }
}

}

Comments

0

here i am passing object as arguments

class person1
            {
                public int x, y;
                public person1(int x,int y)
                    {
                    this.x = x;
                    this.y = y;

                    }
                public void changes(person1 p1)
                {
                   // int t;
                    this.x = x + y;  //x=30 x=10,y=20
                    this.y = x - y;  //y=30-20=10
                    this.x = x - y; //x=30-10=20
                }
    }
     static void Main(string[] args)
       {
             person1 p1 = new person1(10,20);
             p1.changes(p1);
             Console.WriteLine("swapp hoge kya ?x={0} and y={1}", p1.x, p1.y);
             Console.ReadKey();
      }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.