How do you reverse a string in place in C or C++?

前端 未结 30 1922
长发绾君心
长发绾君心 2020-11-22 00:37

How do you reverse a string in C or C++ without requiring a separate buffer to hold the reversed string?

30条回答
  •  忘了有多久
    2020-11-22 01:39

    The standard algorithm is to use pointers to the start / end, and walk them inward until they meet or cross in the middle. Swap as you go.


    Reverse ASCII string, i.e. a 0-terminated array where every character fits in 1 char. (Or other non-multibyte character sets).

    void strrev(char *head)
    {
      if (!head) return;
      char *tail = head;
      while(*tail) ++tail;    // find the 0 terminator, like head+strlen
      --tail;               // tail points to the last real char
                            // head still points to the first
      for( ; head < tail; ++head, --tail) {
          // walk pointers inwards until they meet or cross in the middle
          char h = *head, t = *tail;
          *head = t;           // swapping as we go
          *tail = h;
      }
    }
    

    // test program that reverses its args
    #include 
    
    int main(int argc, char **argv)
    {
      do {
        printf("%s ",  argv[argc-1]);
        strrev(argv[argc-1]);
        printf("%s\n", argv[argc-1]);
      } while(--argc);
    
      return 0;
    }
    

    The same algorithm works for integer arrays with known length, just use tail = start + length - 1 instead of the end-finding loop.

    (Editor's note: this answer originally used XOR-swap for this simple version, too. Fixed for the benefit of future readers of this popular question. XOR-swap is highly not recommended; hard to read and making your code compile less efficiently. You can see on the Godbolt compiler explorer how much more complicated the asm loop body is when xor-swap is compiled for x86-64 with gcc -O3.)


    Ok, fine, let's fix the UTF-8 chars...

    (This is XOR-swap thing. Take care to note that you must avoid swapping with self, because if *p and *q are the same location you'll zero it with a^a==0. XOR-swap depends on having two distinct locations, using them each as temporary storage.)

    Editor's note: you can replace SWP with a safe inline function using a tmp variable.

    #include 
    #include 
    
    #define SWP(x,y) (x^=y, y^=x, x^=y)
    
    void strrev(char *p)
    {
      char *q = p;
      while(q && *q) ++q; /* find eos */
      for(--q; p < q; ++p, --q) SWP(*p, *q);
    }
    
    void strrev_utf8(char *p)
    {
      char *q = p;
      strrev(p); /* call base case */
    
      /* Ok, now fix bass-ackwards UTF chars. */
      while(q && *q) ++q; /* find eos */
      while(p < --q)
        switch( (*q & 0xF0) >> 4 ) {
        case 0xF: /* U+010000-U+10FFFF: four bytes. */
          SWP(*(q-0), *(q-3));
          SWP(*(q-1), *(q-2));
          q -= 3;
          break;
        case 0xE: /* U+000800-U+00FFFF: three bytes. */
          SWP(*(q-0), *(q-2));
          q -= 2;
          break;
        case 0xC: /* fall-through */
        case 0xD: /* U+000080-U+0007FF: two bytes. */
          SWP(*(q-0), *(q-1));
          q--;
          break;
        }
    }
    
    int main(int argc, char **argv)
    {
      do {
        printf("%s ",  argv[argc-1]);
        strrev_utf8(argv[argc-1]);
        printf("%s\n", argv[argc-1]);
      } while(--argc);
    
      return 0;
    }
    
    • Why, yes, if the input is borked, this will cheerfully swap outside the place.
    • Useful link when vandalising in the UNICODE: http://www.macchiato.com/unicode/chart/
    • Also, UTF-8 over 0x10000 is untested (as I don't seem to have any font for it, nor the patience to use a hexeditor)

    Examples:

    $ ./strrev Räksmörgås ░▒▓○◔◑◕●
    
    ░▒▓○◔◑◕● ●◕◑◔○▓▒░
    
    Räksmörgås sågrömskäR
    
    ./strrev verrts/.
    

提交回复
热议问题