193

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

Coding Mash
  • 3,338
  • 5
  • 24
  • 45

21 Answers21

490
#include <algorithm>
std::reverse(str.begin(), str.end());

This is the simplest way in C++.

Tom
  • 1,977
  • 1
  • 20
  • 19
Greg Rogers
  • 35,641
  • 17
  • 67
  • 94
  • 7
    In C++ a string is represented by the string class. He didn't asked for "char star" or a "char brackets". Stay classy, C. – jokoon Aug 30 '11 at 21:53
  • 13
    @fredsbend, the "ridiculously long" version of the selected answer handles a case which this simple answer doesn't - UTF-8 input. It shows the importance of fully specifying the problem. Besides the question was about code that would work in C as well. – Mark Ransom Aug 16 '13 at 14:45
  • 7
    This answer does handle the case if you use a UTF-8 aware string class (or possibly a utf-8 character class with std::basic_string). Besides, the question said "C or C++", not "C and C++". C++ only is "C or C++". – Taywee Jul 05 '16 at 18:54
  • This will completely break UTF-8 multibyte strings and in this day and age a total non-starter. – Cameron Lowell Palmer Jan 27 '21 at 19:18
167

Read Kernighan and Ritchie

#include <string.h>

void reverse(char s[])
{
    int length = strlen(s) ;
    int c, i, j;

    for (i = 0, j = length - 1; i < j; i++, j--)
    {
        c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
}
Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
  • 9
    Tested on my iphone this is slower than using raw pointer addresses by about 15% – jjxtra Apr 29 '13 at 20:16
  • 3
    Shouldn't variable "c" be a char instead of an int? – Lesswire Nov 17 '13 at 17:25
  • @Lesswire - In C, whenever a character constant or variable is used in an expression in C, it is automatically converted & treated as an integer. If you have a linux termminal, you can see the ascii codes by typing `man ascii` – user1527227 Apr 09 '14 at 01:48
  • 21
    Its important to note in this example that the string `s` must be declared in an array form. In other words, `char s[] = "this is ok"` rather than `char *s="cannot do this"` because the latter results in a string constant which cannot be modified – user1527227 Apr 09 '14 at 01:50
  • 1
    `length, i, j` should be `size_t`, but then would have trouble when `length == 0`. – chux - Reinstate Monica Jun 13 '14 at 22:16
  • 2
    @PsychoDad Did you enable optimizations when you did the iPhone benchmark of array access vs pointer?? – Brandin Sep 01 '14 at 06:27
  • @brandin Hopefully I did it in release mode, but I don't remember. – jjxtra Sep 01 '14 at 14:40
  • 3
    With apologizes to "The Godfather" .... "Leave the guns, bring the K&R". As a C bigot, I'd use pointers, as they're simpler and more straight-forward for this problem, but the code would be less portable to C#, Java, etc. –  Nov 27 '14 at 02:14
  • I don't understand why this isn't the accepted answer. It's the simplest, most robust solution that performs in O(1) space. It also performs in O(log(n)) time, which is awesome. – Eric Rini Dec 07 '16 at 19:05
  • 2
    @Eric This does not run in O(log(n)) time. It runs in O(n) if you're referring to the number of character swaps the code performs, for n of string length, then n swaps are performed. If you we're talking about the amount of loops performed then its still O(n) - albeit O(n/2) but you drop the constants in Big O notation. – Stephen Fox Dec 18 '16 at 18:43
  • @Eric In addition to what Stephen says it - as user1527227 also says - requires it to be in array form. That would be another good reason it's not accepted. – Pryftan Feb 21 '20 at 17:04
  • 1
    @jjxtra Then you have a bad compiler – klutt Jan 25 '21 at 13:41
  • Sorry, but this solution is not "in place". When I used to teach C programming, one of the problems I always gave my students was to reverse the string in place using only two registers and no stack variables to hold any of the string characters. The trick was using exclusive or. It was easier back then though because we could easily write past the \0 and do a buffer overrun. This was allowed as long as they only overwrote the \0, giving them a byte to play with. – SixSigmaGuy Jul 27 '23 at 04:00
132

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 <stdio.h>

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 <bits/types.h>
#include <stdio.h>

#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/.
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Anders Eurenius
  • 4,170
  • 2
  • 24
  • 20
  • 1
    Why not "*p ^= *q, *q ^= *p, *p ^= *q"? – Chris Conway Oct 13 '08 at 17:19
  • 17
    I'd say that if you are going to ask for "In place" without being more specific, it HAS to be the xor thing. Anything else isn't in-place. That said, this has no business being in production code anywhere ever. if you're ever even tempted to use it, quit engineering now. – Bill K Oct 13 '08 at 17:24
  • 28
    You think "in-place" means "no extra memory", not even O(1) memory for temporaries? What about the space on the stack for str and the return address? – Chris Conway Oct 13 '08 at 17:30
  • 58
    @Bill, that's not what the common definition of “in-place” means. In-place algorithms *may* use additional memory. However, the amount of this additional memory must not depend on the input – i.e. it must be constant. Therefore, swapping of values using additional storage is completely in-place. – Konrad Rudolph Oct 13 '08 at 17:31
  • Oh no, Räksmörgås! Now I have to go to the fridge and make me one. :P – Jonas Engström Oct 13 '08 at 22:04
  • Perhaps you'd like to check this question I've asked specifically about how to handle this task with UTF8 strings (not an universal solution, though). http://stackoverflow.com/questions/199260/reversing-a-utf-8-string-in-place – Juan Pablo Califano Oct 13 '08 at 22:41
  • 35
    XOR swapping is slower than swapping via register on modern out-of-order processors. – Patrick Schlüter Aug 15 '11 at 17:42
  • 6
    I googled "in place string reversal" *specifically* to find an implementation of the XOR trick. Haters gonna hate, but I found what I was looking for so +1 from me. – John Dibling Oct 02 '12 at 22:06
  • 2
    I ran some tests, and it seems that the "while (q && *q)" test should be changed. It should be "while (*q)" or changed to a separate "if (!q) { return; }" (if the intention was to catch NULL pointers). The problem is in the NULL case, the next statement, for(--q; p < q; ++p, --q), causes q to roll over to 0xFFFFFFFFFFFFFFFF (at least on the 64-bit CentOS machine I was testing on), which will cause the for loop to execute (since 0 is less than 0xFFFFFFFFFFFFFFFF, and the first "*p = *p ^ *q;" will then cause a de-reference of a null pointer, and a de-reference of 0xFFFFFFFFFFFFFFFF... – mmucklo Jul 13 '13 at 20:06
  • 1
    Guys, most of you are wrong about definition of in-place. It has a strong definition: in-place algorithm uses O(logn) memory. Fox example do you consider quicksort in-place? It is in place and it uses logarithmic memory for storing data in recursion stack. – sasha.sochka Jul 18 '13 at 20:40
  • 3
    @sasha.sochka You are wrong. In-place means one thing, and one thing only: *constant* memory, not O(logn). And you got it: quicksort *isn’t* in-place. Whoever claims that is wrong. In fact, many (ostensibly “in-place”) implementations of quicksort even use O(n) additional memory in the worst case (since they don’t guarantee logarithmic recursion depth. But like I said, quicksort isn’t really in-place to begin with. – Konrad Rudolph Oct 16 '13 at 17:25
  • @KonradRudolph, yeah, I got it. Perhaps some time ago I read this article http://en.wikipedia.org/wiki/In-place_algorithm (section "In computational complexity") and forgot that this `log n` was applied there in a little bit different context. – sasha.sochka Oct 16 '13 at 19:26
  • @AndersEurenius can you clarify on why do use use `while(q && *q) ++q;` to find the eos? Isn't it the same as `while(*q) ++q;`, since q is never going to be 0? How can you be sure that q or *q are going to be 0? – AR89 Jan 17 '14 at 11:09
  • 2
    "you must avoid swapping with self, because `a^a==0`" - wrong. `a ^ a == 0`, but that's not a problem, because then you will do `a ^ (a ^ a)` which is `a ^ 0` which is `a`. So the XOR swap works even if the two swappees (is there such a word) are equal. –  Jan 21 '14 at 15:52
  • 1
    `char *q = p; while(q && *q) ++q; for(--q; p < q; ++p, --q)` to do `NULL` detection is problematic. For the code progress to `--q` when `q` is NULL and at best that is the largest legal pointer, at worst it may be UB. Then the `for()` loop would iterate for a long time. Suggest a simple `if (q != NULL) { do the rest of code }`. – chux - Reinstate Monica Jun 13 '14 at 22:08
  • 8
    As an interviewer, I *dock* points for use of the old xor-swap trick. It's less efficient on modern processors and anybody who uses it because it's "neat" is _not_ a great programmer -- "good", possibly, but not "great". – Brian White Sep 11 '15 at 01:39
  • 1
    Wow, every time I think I can't find an uglier code than last time, I find an uglier one. – Xam Sep 12 '18 at 22:03
  • @ChrisConway Yes and as a participant and winner also I can say that it's not going to confuse many people. It might have its uses there but it's not confusing either. I can think of numerous ways it might be useful in an entry but overall it's so unoriginal that it would be not relevant. They want much more balanced entries. Still there are times outside the contest where I might consider it though that's extremely limited too - and not in regular code. – Pryftan Feb 21 '20 at 16:50
  • As for *`while(q && *q) ++q;`* why not just use *`strchr(q, '\0');`* ? Probably doesn't matter but it seems more natural. Of course there are other ways too. Maybe you just didn't want to include string.h even. – Pryftan Feb 21 '20 at 17:00
43

Non-evil C, assuming the common case where the string is a null-terminated char array:

#include <stddef.h>
#include <string.h>

/* PRE: str must be either NULL or a pointer to a 
 * (possibly empty) null-terminated string. */
void strrev(char *str) {
  char temp, *end_ptr;

  /* If str is NULL or empty, do nothing */
  if( str == NULL || !(*str) )
    return;

  end_ptr = str + strlen(str) - 1;

  /* Swap the chars */
  while( end_ptr > str ) {
    temp = *str;
    *str = *end_ptr;
    *end_ptr = temp;
    str++;
    end_ptr--;
  }
}
Chris Conway
  • 55,321
  • 43
  • 129
  • 155
  • Rather than using a while loop to find the end pointer, can't you use something like end_ptr = str + strlen (str); I know that will do practically the same thing, but I find it clearer. – Peter Kühne Oct 13 '08 at 17:43
  • Fair enough. I was trying (and failing) to avoid the off-by-one error in @uvote's answer. – Chris Conway Oct 13 '08 at 19:57
  • Aside from a _potential_ performance improvement with maybe `int temp`, this solution looks best. +1 – chux - Reinstate Monica Jun 13 '14 at 22:17
  • @chux-ReinstateMonica Yes. It's beautiful. Personally I would remove the ()s from the *`!(*str)`* though. – Pryftan Feb 21 '20 at 17:08
  • @PeterKühne Yes or *`strchr()`* searching for *`'\0'`*. I thought of both. Not need for a loop. – Pryftan Feb 21 '20 at 17:10
  • Why is this considered non-evil? What is an evil implementation and why is it important to distinguish between them? Thanks – clickMe Apr 18 '21 at 07:41
  • This answer is 13 years old. You think I have any idea what I meant back then?! I think the top answer back then used XOR swap, which is non-obvious and buggy. "Evil" was probably not the right word to use. – Chris Conway Apr 19 '21 at 19:37
35

It's been a while and I don't remember which book taught me this algorithm, but I thought it was quite ingenious and simple to understand:

char input[] = "moc.wolfrevokcats";

int length = strlen(input);
int last_pos = length-1;
for(int i = 0; i < length/2; i++)
{
    char tmp = input[i];
    input[i] = input[last_pos - i];
    input[last_pos - i] = tmp;
}

printf("%s\n", input);

A visualization of this algorithm, courtesy of slashdottir:

Visualization of the algorithm to reverse a string in place

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
karlphillip
  • 92,053
  • 36
  • 243
  • 426
23

Note that the beauty of std::reverse is that it works with char * strings and std::wstrings just as well as std::strings

void strrev(char *str)
{
    if (str == NULL)
        return;
    std::reverse(str, str + strlen(str));
}
Eclipse
  • 44,851
  • 20
  • 112
  • 171
12

In the interest of completeness, it should be pointed out that there are representations of strings on various platforms in which the number of bytes per character varies depending on the character. Old-school programmers would refer to this as DBCS (Double Byte Character Set). Modern programmers more commonly encounter this in UTF-8 (as well as UTF-16 and others). There are other such encodings as well.

In any of these variable-width encoding schemes, the simple algorithms posted here (evil, non-evil or otherwise) would not work correctly at all! In fact, they could even cause the string to become illegible or even an illegal string in that encoding scheme. See Juan Pablo Califano's answer for some good examples.

std::reverse() potentially would still work in this case, as long as your platform's implementation of the Standard C++ Library (in particular, string iterators) properly took this into account.

Community
  • 1
  • 1
Tim Farley
  • 11,720
  • 4
  • 29
  • 30
  • 6
    std::reverse does NOT take this into account. It reverses value_type's. In the std::string case, it reverses char's. Not characters. – MSalters Oct 14 '08 at 07:24
  • Say rather that we old school programmers know of DBCS but also know of UTF-8: for we all know that programmers are just like addicts when they say *'one more line and I'll quit!'* I'm sure some programmers eventually quit but frankly programming really is like an addiction for me; I get withdrawals from not programming. It's a good point that you add here. I don't like C++ (I tried really really hard to like it even writing quite a bit of it but it still is for me aesthetically unappealing to say the least) so I can't comment there but you make a good point anyway so have a +1. – Pryftan Feb 21 '20 at 17:23
12

If you're looking for reversing NULL terminated buffers, most solutions posted here are OK. But, as Tim Farley already pointed out, these algorithms will work only if it's valid to assume that a string is semantically an array of bytes (i.e. single-byte strings), which is a wrong assumption, I think.

Take for example, the string "año" (year in Spanish).

The Unicode code points are 0x61, 0xf1, 0x6f.

Consider some of the most used encodings:

Latin1 / iso-8859-1 (single byte encoding, 1 character is 1 byte and vice versa):

Original:

0x61, 0xf1, 0x6f, 0x00

Reverse:

0x6f, 0xf1, 0x61, 0x00

The result is OK

UTF-8:

Original:

0x61, 0xc3, 0xb1, 0x6f, 0x00

Reverse:

0x6f, 0xb1, 0xc3, 0x61, 0x00

The result is gibberish and an illegal UTF-8 sequence

UTF-16 Big Endian:

Original:

0x00, 0x61, 0x00, 0xf1, 0x00, 0x6f, 0x00, 0x00

The first byte will be treated as a NUL-terminator. No reversing will take place.

UTF-16 Little Endian:

Original:

0x61, 0x00, 0xf1, 0x00, 0x6f, 0x00, 0x00, 0x00

The second byte will be treated as a NUL-terminator. The result will be 0x61, 0x00, a string containing the 'a' character.

Juan Pablo Califano
  • 12,213
  • 5
  • 29
  • 42
  • std::reverse will work for two-byte unicode types, as long as you're using wstring. – Eclipse Oct 13 '08 at 19:02
  • I'm not very familiar with C++, but my guess is that any respectable standard library function dealing with strings will be able to handle different encodings, so I agree with you. By "these algorithms", I meant the ad-hoc reverse functions posted here. – Juan Pablo Califano Oct 13 '08 at 19:10
  • Unfortunately, there's no such thing as "respectable function dealing with strings" in standard C++. – Jem Mar 30 '12 at 14:08
  • @Eclipse If it reverses a surrogate pair, the result won't be correct anymore. Unicode is not actually a fixed-width charset – phuclv May 17 '14 at 03:55
  • What I like about this answer is that it shows the actual ordering of bytes (though endianness might be something - ah, I see you did indeed consider it) and how it is either correct or incorrect. But I think the answer would be improved if you incorporated some code demonstrating this. – Pryftan Feb 21 '20 at 17:19
8

Another C++ way (though I would probably use std::reverse() myself :) as being more expressive and faster)

str = std::string(str.rbegin(), str.rend());

The C way (more or less :) ) and please, be careful about XOR trick for swapping, compilers sometimes cannot optimize that.

In such case it is usually much slower.

char* reverse(char* s)
{
    char* beg = s, *end = s, tmp;
    while (*end) end++;
    while (end-- > beg)
    { 
        tmp  = *beg; 
        *beg++ = *end;  
        *end =  tmp;
    }
    return s;
} // fixed: check history for details, as those are interesting ones
pprzemek
  • 2,455
  • 3
  • 25
  • 25
  • I'd use `strlen` to find the end of the string, if it's potentially long. A good library implementation will use SIMD vectors to search faster than 1 byte per iteration. But for very short strings, `while (*++end);` will be done before a library function call gets started searching. – Peter Cordes Mar 28 '17 at 07:17
  • @PeterCordes well, agreed, strlen should be used anyway for readability. For longer string you should always keep the length in a varialbe anyway. strlen on SIMD is usually given as an example with this disclaimer, that is not real life application, or at least it was 5 years ago, when the code was written. ;) – pprzemek Apr 04 '17 at 09:46
  • 1
    If you wanted this to run fast on real CPUs, you'd use SIMD shuffles to do the reverse in 16B chunks. :P e.g. on x86, `_mm_shuffle_epi8` (PSHUFB) can reverse the order of a 16B vector, given the right shuffle control vector. It can probably run at nearly memcpy speed with some careful optimization, especially with AVX2. – Peter Cordes Apr 05 '17 at 00:07
  • `char* beg = s-1` has undefined behavior (at least if `s` points to the first element of an array, which is the most common case). `while (*++end);` has undefined behavior if `s` is an empty string. – melpomene Oct 17 '18 at 04:30
  • @pprzemek Well, you are making the claim that `s-1` has defined behavior even if `s` points to the first element of an array, so it's you who should be able to cite the standard in support. – melpomene Nov 12 '18 at 21:10
  • @pprzemek Your code does not use the `--` operator. I never said anything about types. Pointer arithmetic in general is only valid if it moves the pointer within the same array (or one element past the end). See also http://c-faq.com/aryptr/non0based.html, which explicitly says what you're doing is invalid. – melpomene Nov 12 '18 at 21:52
  • @melpomene you are very wise indeed, you could have just fixed the answer as SO recommends. Nevertheless you are right I was wrong. I'll remove my comments in shame an humility, as they are no longer valid. – pprzemek Nov 13 '18 at 08:02
6
#include <cstdio>
#include <cstdlib>
#include <string>

void strrev(char *str)
{
        if( str == NULL )
                return;

        char *end_ptr = &str[strlen(str) - 1];
        char temp;
        while( end_ptr > str )
        {
                temp = *str;
                *str++ = *end_ptr;
                *end_ptr-- = temp;
        }
}

int main(int argc, char *argv[])
{
        char buffer[32];

        strcpy(buffer, "testing");
        strrev(buffer);
        printf("%s\n", buffer);

        strcpy(buffer, "a");
        strrev(buffer);
        printf("%s\n", buffer);

        strcpy(buffer, "abc");
        strrev(buffer);
        printf("%s\n", buffer);

        strcpy(buffer, "");
        strrev(buffer);
        printf("%s\n", buffer);

        strrev(NULL);

        return 0;
}

This code produces this output:

gnitset
a
cba
  • 2
    @uvote, Don't use strcpy. Ever. If you have to use something like strcpy use strncpy. strcpy is dangerous. By the way C and C++ are two separate languages with separate facilities. I think you're using header files only available in C++ so do you really need an answer in C? – Onorio Catenacci Oct 13 '08 at 16:48
  • If the string is empty, strlen will return 0 and you will index outside the array which is illegal in C (you can address one element past the end of an array but not one element before). – Robert Gamble Oct 13 '08 at 16:48
  • 6
    strcpy is perfectly safe if the programmer can keep track of the size of his arrays, many would argue that strncpy is less safe since it does not guarantee the resulting string is null terminated. In any case, there is nothing wrong with uvote's use of strcpy here. – Robert Gamble Oct 13 '08 at 16:52
  • 1
    @Onorio Catenacci, strcpy is not dangerous if you know that the source string will fit inside the destination buffer, as in the cases given in the above code. Also, strncpy zero-fills up to the number of chars specified in the size parameter if there is left-over room, which may not be desired. – Chris Young Oct 13 '08 at 16:54
  • I would consider strcpy to be in the same class of potentially dangerous language features as operator overloading--fine and safe if someone knows how to use it properly but most developers don't know how to use it properly. Hence it should simply be avoided. I stand by my advice. – Onorio Catenacci Oct 13 '08 at 17:27
  • 3
    Anyone that can't use strcpy properly shouldn't be programming in C. – Robert Gamble Oct 13 '08 at 18:15
  • 2
    @Robert Gamble, I agree. However, since I don't know of any way to keep people from programming in C no matter what their competence, I usually recommend against this. – Onorio Catenacci Oct 13 '08 at 18:35
  • @Robert Gamble: Now there's an obscure C rule (indexing one before an array). Now that you mentioned it, I do remember it, and that's a good catch. But of course it works in gcc on x86, as my test shows. (and I'm OK with my use of strcpy) –  Oct 14 '08 at 05:30
  • @OnorioCatenacci Rubbish. It's perfectly safe if you keep track of things. That black and white attitude you have comes from non-defensive programming and/or repeating what they've read/heard. It's simply not true. And just like Robert points out some - myself included - consider `strncpy()` less safe. You don't know a better way than to recommend against this? Why not recommend that they actually check for errors etc. instead? That's far more valuable than blacklisting something because some people use it incorrectly. – Pryftan Feb 21 '20 at 17:27
  • @Pryftan I'd say that if the SEI thinks being careful about strcpy is a good thing then I agree: https://wiki.sei.cmu.edu/confluence/display/c/STR07-C.+Use+the+bounds-checking+interfaces+for+string+manipulation. Strcpy relies on programmer discipline and potentially relies on knowledge that a programmer may simply not possess. There's a safer alternative--why not use it? – Onorio Catenacci Feb 21 '20 at 20:14
  • @OnorioCatenacci Because it's not always safer maybe? Someone else already pointed this out. The point anyway is you can make anything unsafe if you want to. But if you know the correct size then guess what? You could also do testing right. This is common sense. Being careful with `strcpy` as you say isn't the same thing as your earlier **Don't use strcpy. Ever.**. Big difference. Huge difference. **Your earlier comment is black and white.** Being safe is not the same thing. Black and white is rarely a good idea. Life isn't that simple. `strncpy` can also create unterminated strings. Unsafe. – Pryftan Feb 22 '20 at 00:46
4

In case you are using GLib, it has two functions for that, g_strreverse() and g_utf8_strreverse()

dmityugov
  • 4,390
  • 23
  • 18
4

I like Evgeny's K&R answer. However, it is nice to see a version using pointers. Otherwise, it's essentially the same:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char *reverse(char *str) {
    if( str == NULL || !(*str) ) return NULL;
    int i, j = strlen(str)-1;
    char *sallocd;
    sallocd = malloc(sizeof(char) * (j+1));
    for(i=0; j>=0; i++, j--) {
        *(sallocd+i) = *(str+j);
    }
    return sallocd;
}

int main(void) {
    char *s = "a man a plan a canal panama";
    char *sret = reverse(s);
    printf("%s\n", reverse(sret));
    free(sret);
    return 0;
}
Rob
  • 4,093
  • 5
  • 44
  • 54
4

Recursive function to reverse a string in place (no extra buffer, malloc).

Short, sexy code. Bad, bad stack usage.

#include <stdio.h>

/* Store the each value and move to next char going down
 * the stack. Assign value to start ptr and increment 
 * when coming back up the stack (return).
 * Neat code, horrible stack usage.
 *
 * val - value of current pointer.
 * s - start pointer
 * n - next char pointer in string.
 */
char *reverse_r(char val, char *s, char *n)
{
    if (*n)
        s = reverse_r(*n, s, n+1);
   *s = val;
   return s+1;
}

/*
 * expect the string to be passed as argv[1]
 */
int main(int argc, char *argv[])
{
    char *aString;

    if (argc < 2)
    {
        printf("Usage: RSIP <string>\n");
        return 0;
    }

    aString = argv[1];
    printf("String to reverse: %s\n", aString );

    reverse_r(*aString, aString, aString+1); 
    printf("Reversed String:   %s\n", aString );

    return 0;
}
Simon Peverett
  • 4,128
  • 3
  • 32
  • 37
  • 1
    That's a quite fun solution, you should add some tracing like printf("%*s > [%d] reverse_r('%c', %p=\"%s\", %p=\"%s\")\n", depth, " ", depth, val, s, (s ? s : "null"), n, (n ? n : "null")); at the start and < at the end. – Benoît Oct 15 '13 at 20:59
  • Pushing each `char` onto the stack does not count as "in place". Especially not when you're actually pushing 4 * 8B per character (on a 64-bit machine: 3 args + a return address). – Peter Cordes Mar 28 '17 at 07:15
  • The original question is "How do you reverse a string in C or C++ without requiring a separate buffer to hold the reversed string?" - there was no requirement to swap 'in place'. Also,this solution mentions the bad stack usage from the start. Am I being down voted because of other people's poor reading comprehension? – Simon Peverett Oct 24 '17 at 12:33
  • 1
    I wouldn't call it 'sexy' but I would say that it's demonstrative and instructional. If recursion is used properly it can be very valuable. However it should be pointed out that - last I knew - C does not even require a stack per se; however it does recursion. Either way it's an example of recursion which if used properly can be very useful and valuable. I don't think I've ever seen it used to reverse a string though. – Pryftan Feb 21 '20 at 17:30
2

If you are using ATL/MFC CString, simply call CString::MakeReverse().

Ajay
  • 18,086
  • 12
  • 59
  • 105
Michael Haephrati
  • 3,660
  • 1
  • 33
  • 56
0

Yet another:

#include <stdio.h>
#include <strings.h>

int main(int argc, char **argv) {

  char *reverse = argv[argc-1];
  char *left = reverse;
  int length = strlen(reverse);
  char *right = reverse+length-1;
  char temp;

  while(right-left>=1){

    temp=*left;
    *left=*right;
    *right=temp;
    ++left;
    --right;

  }

  printf("%s\n", reverse);

}
  • This demonstrates pointer arithmetic, much like my answer, but combines it with Swap. I believe this answer adds a lot, actually. You should be able to understand this type of code before adding a billion libraries as dependencies just to get some simple text box (something I see way too often in modern applications I get to work with) – Stephen J Nov 26 '18 at 21:26
0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

unsigned char * utf8_reverse(const unsigned char *, int);
void assert_true(bool);

int main(void)
{
    unsigned char str[] = "mañana mañana";
    unsigned char *ret = utf8_reverse(str,  strlen((const char *) str) + 1);

    printf("%s\n", ret);
    assert_true(0 == strncmp((const char *) ret, "anãnam anañam", strlen("anãnam anañam") + 1));

    free(ret);

    return EXIT_SUCCESS;
}

unsigned char * utf8_reverse(const unsigned char *str, int size)
{
    unsigned char *ret = calloc(size, sizeof(unsigned char*));
    int ret_size = 0;
    int pos = size - 2;
    int char_size = 0;

    if (str ==  NULL) {
        fprintf(stderr, "failed to allocate memory.\n");
        exit(EXIT_FAILURE);
    }

    while (pos > -1) {

        if (str[pos] < 0x80) {
            char_size = 1;
        } else if (pos > 0 && str[pos - 1] > 0xC1 && str[pos - 1] < 0xE0) {
            char_size = 2;
        } else if (pos > 1 && str[pos - 2] > 0xDF && str[pos - 2] < 0xF0) {
            char_size = 3;
        } else if (pos > 2 && str[pos - 3] > 0xEF && str[pos - 3] < 0xF5) {
            char_size = 4;
        } else {
            char_size = 1;
        }

        pos -= char_size;
        memcpy(ret + ret_size, str + pos + 1, char_size);
        ret_size += char_size;
    }    

    ret[ret_size] = '\0';

    return ret;
}

void assert_true(bool boolean)
{
    puts(boolean == true ? "true" : "false");
}
masakielastic
  • 4,540
  • 1
  • 39
  • 42
0

C++ multi-byte UTF-8 reverser

My thought is that you can never just swap ends, you must always move from beginning-to-end, move through the string and look for "how many bytes will this character require?" I attach the character starting at the original end position, and remove the character from the front of the string.

void StringReverser(std::string *original)
{
  int eos = original->length() - 1;
  while (eos > 0) {
    char c = (*original)[0];
    int characterBytes;
    switch( (c & 0xF0) >> 4 ) {
    case 0xC:
    case 0xD: /* U+000080-U+0007FF: two bytes. */
      characterBytes = 2;
      break;
    case 0xE: /* U+000800-U+00FFFF: three bytes. */
      characterBytes = 3;
      break;
    case 0xF: /* U+010000-U+10FFFF: four bytes. */
      characterBytes = 4;
      break;
    default:
      characterBytes = 1;
      break;
    }

    for (int i = 0; i < characterBytes; i++) {
      original->insert(eos+i, 1, (*original)[i]);
    }
    original->erase(0, characterBytes);
    eos -= characterBytes;
  }
}
Cameron Lowell Palmer
  • 21,528
  • 7
  • 125
  • 126
0
void reverseString(vector<char>& s) {
        int l = s.size();
        char ch ;
        int i = 0 ;
        int j = l-1;
        while(i < j){
                s[i] = s[i]^s[j];
                s[j] = s[i]^s[j];
                s[i] = s[i]^s[j];
                i++;
                j--;
        }
        for(char c : s)
                cout <<c ;
        cout<< endl;
}
RobinSingh
  • 166
  • 2
  • 10
0

input string, return string, No other library required

std::string reverse_string(std::string &str)
{   
  const char*buf = str.c_str();
  char *start = const_cast<char*>(buf);
  char *end = start + strlen(buf) - 1;
  char t;

  while(start < end)
  {
      t = *start;
      *start = *end;
      *end = t;
      start ++;
      end --;
  }
  str = buf;
  return str;
}
std::string md1 = "abcdefghijklmnopqrstuvwxyz0123456789";
std::cout << reverse_string(md1) << std::endl;

//9876543210zyxwvutsrqponmlkjihgfedcba
Driver
  • 11
  • 1
-1

If you don't need to store it, you can reduce the time spent like this:

void showReverse(char s[], int length)
{
    printf("Reversed String without storing is ");
    //could use another variable to test for length, keeping length whole.
    //assumes contiguous memory
    for (; length > 0; length--)
    {
        printf("%c", *(s+ length-1) );
    }
    printf("\n");
}
Stephen J
  • 2,367
  • 2
  • 25
  • 31
  • I seem to be the only answer that doesn't have a buffer, or temp variable. I use length of string, but the others that do this add another one for the head (vs tail). I'm assuming the standard reverse func stores the variable, via a swap or something. Thus, I am under the impression, assuming pointer math and UTF type line up, that this is possibly the only answer that actually answers the question. The added printf()'s can be taken out, I just did it to look nicer for the result. I wrote this for speed. No extra allocations or vars. Probably the fastest algorithm for displaying reverse str() – Stephen J Apr 27 '20 at 07:06
-1

In C++ the reverse can be done in a function:

#include <algorithm>
#include <string>

void backwards(vector<string> &inputs_ref) {
    for (auto i = inputs_ref.begin(); i != inputs_ref.end(); ++i) {
        reverse(i->begin(), i->end());
    }
}
Kateridzhe
  • 227
  • 3
  • 4