Is there a built-in way to swap two variables in C

后端 未结 10 1520
夕颜
夕颜 2020-12-01 14:53

I know how to swap 2 variables in c++ , ie you use std::swap(a,b).

question:

Does the C standard library have a similar function

相关标签:
10条回答
  • 2020-12-01 14:57

    Yes you need to define it yourself.

    1. C doesn't have templates.
    2. If such function does exist it would look like void swap(void* a, void* b, size_t length), but unlike std::swap, it's not type-safe.
    3. And there's no hint such function could be inlined, which is important if swapping is frequent (in C99 there's inline keyword).
    4. We could also define a macro like

      #define SWAP(a,b,type) {type ttttttttt=a;a=b;b=ttttttttt;}
      

      but it shadows the ttttttttt variable, and you need to repeat the type of a. (In gcc there's typeof(a) to solve this, but you still cannot SWAP(ttttttttt,anything_else);.)

    5. And writing a swap in place isn't that difficult either — it's just 3 simple lines of code!

    0 讨论(0)
  • 2020-12-01 14:57

    You can do something similar with a macro if you don't mind using a gcc extension to the C language, typeof:

    #include <stdio.h>
    
    #define SWAP(a, b) do { typeof(a) temp = a; a = b; b = temp; } while (0)
    
    int main(void)
    {
        int a = 4, b = 5;
        float x = 4.0f, y = 5.0f;
        char *p1 = "Hello";
        char *p2 = "World";
    
        SWAP(a, b); // swap two ints, a and b
        SWAP(x, y); // swap two floats, x and y
        SWAP(p1, p2); // swap two char * pointers, p1 and p2
    
        printf("a = %d, b = %d\n", a, b);
        printf("x = %g, y = %g\n", x, y);
        printf("p1 = %s, p2 = %s\n", p1, p2);
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-01 15:02

    Another macro not already mentioned here: You don't need to give the type if you give the temporary variable instead. Additionally the comma operator is useful here to avoid the do-while(0) trick. But usually I don't care and simply write the three commands. On the other hand a temporary macro is useful if a and b are more complex.

    #define SWAP(a,b,t) ((t)=(a), (a)=(b), (b)=(t))
    
    void mix_the_array (....)
    {
        int tmp;
        .....
        SWAP(pointer->array[counter+17], pointer->array[counter+20], tmp);
        .....
    }
    
    #undef SWAP
    
    0 讨论(0)
  • 2020-12-01 15:07

    in essence, swap function is to swap two memory block. with two addresses and the size of block in bytes, we can swap pointers, integers, doubles, arrays, structs, ...

    a pointer has three parts, e.g. we can break down short* p into three pieces

    1. address: void* p
    2. size: reading two bytes at void*p, we get a short integer.
    3. usage: e.g. print a short integer with %hu

    using the first two parts, we will be able to build a generic swap function:

    #include<stdint.h> 
    #ifdef _WIN32
    #define alloca _alloca
    #else
    #include <alloca.h>
    #endif
    
    void gswap(void * const a, void * const b, int const sz) {
        // for most case, 8 bytes will be sufficient.
        int64_t tmp; // equivalent to char tmp[8];
        void * p;
        bool needfree = false;
        if (sz > sizeof(int64_t)) {
            // if sz exceed 8 bytes, we allocate memory in stack with little cost.
            p = alloca(sz);
            if (p == NULL) {
                // if sz is too large to fit in stack, we fall back to use heap.
                p = malloc(sz);
                //assert(p != NULL, "not enough memory");
                needfree = true;
            }
        }
        else {
            p = &tmp;
        }
    
        memcpy(p, b, sz);
        memcpy(b, a, sz);
        memcpy(a, p, sz);
    
        if (needfree) {
            free(p);
        }
    
    }
    

    e.g.:

    {// swap int 
        int a = 3;
        int b = 4;
        printf("%d,%d\n", a, b);//3,4
        gswap(&a, &b, sizeof(int));
        printf("%d,%d\n", a, b);//4,3
    }
    {// swap int64
        int64_t a = 3;
        int64_t b = 4;
        printf("%lld,%lld\n", a, b);//3,4
        gswap(&a, &b, sizeof(int64_t));
        printf("%lld,%lld\n", a, b);//4,3
    }
    {// swap arrays
        int64_t a[2] = { 3,4 };
        int64_t b[2] = { 5,6 };
        printf("%lld,%lld,%lld,%lld\n", a[0], a[1], b[0], b[1]);//3,4,5,6
        gswap(&a, &b, sizeof(a));
        printf("%lld,%lld,%lld,%lld\n", a[0], a[1], b[0], b[1]);//5,6,3,4
    }
    {// swap arrays
        double a[2] = { 3.,4. };
        double b[2] = { 5.,6. };
        printf("%lf,%lf,%lf,%lf\n", a[0], a[1], b[0], b[1]);//3.000000, 4.000000, 5.000000, 6.000000
        arrswap(&a, &b, sizeof(a));
        printf("%lf,%lf,%lf,%lf\n", a[0], a[1], b[0], b[1]);//5.000000, 6.000000, 3.000000, 4.000000
    }
    
    0 讨论(0)
  • 2020-12-01 15:09

    Lots of nice solutions in the other answers! Just another quick swap macro for C that I came up with when reading K&R:

    #define SWAP(TYPE,x,y) TYPE a = x, x=y, y=a
    
    0 讨论(0)
  • 2020-12-01 15:16

    In C this is often done using a macro,
    there are very simplistic examples, eg:
    #define SWAP(type,a,b) {type _tmp=a;a=b;b=_tmp;}
    ... but I wouldn't recommend using them because they have some non-obvious flaws.

    This is a macro written to avoid accidental errors.

    #define SWAP(type, a_, b_) \
    do { \
        struct { type *a; type *b; type t; } SWAP; \
        SWAP.a  = &(a_); \
        SWAP.b  = &(b_); \
        SWAP.t  = *SWAP.a; \
        *SWAP.a = *SWAP.b; \
        *SWAP.b =  SWAP.t; \
    } while (0)
    
    • Each argument is instantiated only once,
      so SWAP(a[i++], b[j++]) doesn't give problem side effects.
    • temp variable name is also SWAP, so as not to cause bugs if a different name happens to collide with the hard-coded name chosen.
    • It doesn't call memcpy (which in fact ended up doing real function calls in my tests, even though a compiler may optimize them out).
    • Its type-checked
      (comparing as pointers makes the compiler warn if they don't match).
    0 讨论(0)
提交回复
热议问题