#include <algorithm>
std::reverse(str.begin(), str.end());
This is the simplest way in C++.
Answer from Greg Rogers on Stack Overflow#include <algorithm>
std::reverse(str.begin(), str.end());
This is the simplest way in C++.
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;
}
}
Fastest way to reverse a string in C - Stack Overflow
algorithm - How to reverse a C style string completely - Stack Overflow
How to reverse a string in c without using strrev?
Reversing a string in C - Stack Overflow
What does it mean to reverse a string in C?
How does recursion work for reversing a string?
How do I reverse a string in C without using a library function?
Videos
Maybe something like this?
char *str_reverse_in_place(char *str, int len)
{
char *p1 = str;
char *p2 = str + len - 1;
while (p1 < p2) {
char tmp = *p1;
*p1++ = *p2;
*p2-- = tmp;
}
return str;
}
You'll find algorithms taking less instructions, like this in place reverse
char* str_reverse_in_place(char *str, int len)
{
int i;
for (i = len/2-1 ; i >= 0 ; --i) {
char c = str[i];
str[i] = str[len-i-1];
str[len-i-1] = c;
}
return str;
}
Optimizing for speed at that level, look at the inline keyword, also compile with (for gcc) with -O3 (does usually a better job that adding register ... by yourself).
If you need to have the reversed string elsewhere, either provide it in the function (being allocated for strlen(str)+1 - actually len+1 here - characters)
char* str_reverse(char *str, char *reverse, int len)
{
int i;
for (i = len-1 ; i >= 0 ; --i) {
reverse[i] = str[len-i-1];
}
reverse[len] = 0;
return reverse;
}
or malloc it (it will have to be freed by the caller).
char* str_reverse_malloc(char *str, int len)
{
char *reverse = malloc(len+1);
if ( ! reverse) return NULL;
int i;
for (i = len-1 ; i >= 0 ; --i) {
reverse[i] = str[len-i-1];
}
reverse[len] = 0;
return reverse;
}
That's actually pretty easy:
char *reversed = "";
:)
A C string starting with a '\0' is an empty string. And unless you do things (like adding +1) with the pointer or use functions which expect memory (pointer+size) instead of strings it doesn't matter what comes behind the '\0'
If you actually needed the real string to be present in memory after the '\0': Take the function which writes your reversed string to a given memory location (void strreverse(char *dest, const char *string)).
Then call it like that: char dest[ENOUGH_SPACE]; dest[0] = '\0'; strreverse(dest + 1, YOUR_STRING);
Reversing a string is actually a good task to give to a beginner, if you haven't done any programming it would require you to sit down with a piece of paper and think about how characters are stored and how you would swap them around. Also, it requires you to be careful with when you stop so that it works both with strings with an even and odd number of characters.
Hence, why don't you give it a try yourself?
However, I don't really see the point in including the null terminator in the reverse, it would only make the string look empty when used with standard string functions. Also, I hope this is not a little-endian/big-endian mixup, as endianess don't apply to strings.
If you want to practice advanced features of C, how about pointers? We can toss in macros and xor-swap for fun too!
#include <string.h> // for strlen()
// reverse the given null-terminated string in place
void inplace_reverse(char * str)
{
if (str)
{
char * end = str + strlen(str) - 1;
// swap the values in the two given variables
// XXX: fails when a and b refer to same memory location
# define XOR_SWAP(a,b) do\
{\
a ^= b;\
b ^= a;\
a ^= b;\
} while (0)
// walk inwards from both ends of the string,
// swapping until we get to the middle
while (str < end)
{
XOR_SWAP(*str, *end);
str++;
end--;
}
# undef XOR_SWAP
}
}
A pointer (e.g. char *, read from right-to-left as a pointer to a char) is a data type in C that is used
to refer to location in memory of another value. In this case,
the location where a char is stored. We can dereference
pointers by prefixing them with an *, which gives us the value
stored at that location. So the value stored at str is *str.
We can do simple arithmetic with pointers. When we increment (or decrement) a pointer, we simply move it to refer to the next (or previous) memory location for that type of value. Incrementing pointers of different types may move the pointer by a different number of bytes because different values have different byte sizes in C.
Here, we use one pointer to refer to the first unprocessed
char of the string (str) and another to refer to the last (end).
We swap their values (*str and *end), and move the pointers
inwards to the middle of the string. Once str >= end, either
they both point to the same char, which means our original string had an
odd length (and the middle char doesn't need to be reversed), or
we've processed everything.
To do the swapping, I've defined a macro. Macros are text substitution done by the C preprocessor. They are very different from functions, and it's important to know the difference. When you call a function, the function operates on a copy of the values you give it. When you call a macro, it simply does a textual substitution - so the arguments you give it are used directly.
Since I only used the XOR_SWAP macro once, it was probably overkill to define it,
but it made more clear what I was doing. After the C preprocessor expands the macro,
the while loop looks like this:
while (str < end)
{
do { *str ^= *end; *end ^= *str; *str ^= *end; } while (0);
str++;
end--;
}
Note that the macro arguments show up once for each time they're used in the macro definition. This can be very useful - but can also break your code if used incorrectly. For example, if I had compressed the increment/decrement instructions and the macro call into a single line, like
XOR_SWAP(*str++, *end--);
Then this would expand to
do { *str++ ^= *end--; *end-- ^= *str++; *str++ ^= *end--; } while (0);
Which has triple the increment/decrement operations, and doesn't actually do the swap it's supposed to do.
While we're on the subject, you should know what xor (^) means. It's a basic
arithmetic operation - like addition, subtraction, multiplication, division, except
it's not usually taught in elementary school. It combines two integers bit by bit
- like addition, but we don't care about the carry-overs. 1^1 = 0, 1^0 = 1,
0^1 = 1, 0^0 = 0.
A well known trick is to use xor to swap two values. This works because of three basic
properties of xor: x ^ 0 = x, x ^ x = 0 and x ^ y = y ^ x for all values x and y. So say we have two
variables a and b that are initially storing two values
va and vb.
// initially: // a == va // b == vb a ^= b; // now: a == va ^ vb b ^= a; // now: b == vb ^ (va ^ vb) // == va ^ (vb ^ vb) // == va ^ 0 // == va a ^= b; // now: a == (va ^ vb) ^ va // == (va ^ va) ^ vb // == 0 ^ vb // == vb
So the values are swapped. This does have one bug - when a and b are the same variable:
// initially: // a == va a ^= a; // now: a == va ^ va // == 0 a ^= a; // now: a == 0 ^ 0 // == 0 a ^= a; // now: a == 0 ^ 0 // == 0
Since we str < end, this never happens in the above code, so we're okay.
While we're concerned about correctness we should check our edge cases. The if (str) line should make sure we weren't given a NULL pointer for string. What about the empty string ""? Well strlen("") == 0, so we'll initialize end as str - 1, which means that the while (str < end) condition is never true, so we don't do anything. Which is correct.
There's a bunch of C to explore. Have fun with it!
Update: mmw brings up a good point, which is you do have to be slightly careful how you invoke this, as it does operate in-place.
char stack_string[] = "This string is copied onto the stack.";
inplace_reverse(stack_string);
This works fine, since stack_string is an array, whose contents are initialized to the given string constant. However
char * string_literal = "This string is part of the executable.";
inplace_reverse(string_literal);
Will cause your code to flame and die at runtime. That's because string_literal merely points to the string that is stored as part of your executable - which is normally memory that you are not allowed to edit by the OS. In a happier world, your compiler would know this, and cough an error when you tried to compile, telling you that string_literal needs to be of type char const * since you can't modify the contents. However, this is not the world my compiler lives in.
There are some hacks you could try to make sure that some memory is on the stack or in the heap (and is therefore editable), but they're not necessarily portable, and it could be pretty ugly. However, I'm more than happy to throw responsibility for this to the function invoker. I've told them that this function does in place memory manipulation, it's their responsibility to give me an argument that allows that.
Just a rearrangement, and safety check. I also removed your non-used return type. I think this is a safe and clean as it gets:
#include <stdio.h>
#include <string.h>
void reverse_string(char *str)
{
/* skip null */
if (str == 0)
{
return;
}
/* skip empty string */
if (*str == 0)
{
return;
}
/* get range */
char *start = str;
char *end = start + strlen(str) - 1; /* -1 for \0 */
char temp;
/* reverse */
while (end > start)
{
/* swap */
temp = *start;
*start = *end;
*end = temp;
/* move */
++start;
--end;
}
}
int main(void)
{
char s1[] = "Reverse me!";
char s2[] = "abc";
char s3[] = "ab";
char s4[] = "a";
char s5[] = "";
reverse_string(0);
reverse_string(s1);
reverse_string(s2);
reverse_string(s3);
reverse_string(s4);
reverse_string(s5);
printf("%s\n", s1);
printf("%s\n", s2);
printf("%s\n", s3);
printf("%s\n", s4);
printf("%s\n", s5);
return 0;
}
Edited so that end will not point to a possibly bad memory location when strlen is 0.
Implementation:
As of now, the code is not practical, because the limit is 500 chars including zero termination. It does unnecessary copying. You need to determine the actual length of the string by relying on the fact that C strings are null terminated.
size_t length = 0;
while (*(str + length) != 0)
{
++length;
}
Notice that I'm using size_t, because it is meant to be used to describe size of the objects in memory. Despite it is easy to do it manually, you should always use strlen when possible:
size_t length = strlen(str);
It should be noted that the function returns the length without null terminator. Then we allocate memory for result, since we are creating new string, rather than making changes in place:
char* result = malloc(length + 1);
if (result == NULL)
{
return NULL;
}
We check for succession of allocation, as was suggested in the comments. If allocation failed, further operations will definitely invoke undefined behavior, so we return NULL. length + 1 is for null terminator. Then, we immediately null terminate it:
result[length] = 0;
Now we need to capture the position of the last character in the original string, to start copying from there. It is right before null terminator, which is on index length, so needed position is length - 1. There is an edge case of length 0, so we should check for that first
if (length == 0)
{
return result;
}
size_t last = length - 1;
Then we write algorithm that writes contents of the first string into the second in reverse order:
size_t it = 0;
while (it <= last)
{
result[it] = str[last - it];
++it;
}
then simply return the result:
return result;
Although the implementation has good performance, there are some opportunities to make micro optimizations. The function input type should be const char*, since we don't modify original string. Additionally, it should be noted that the caller is responsible for freeing up malloc'd memory.
Cosmetics:
Name of the function is a little hard to read, so I'd suggest str_reverse. Also, c is not good name at all, so it would be better if it's name str
Put together:
#include <stdio.h>
#include <string.h>
char* str_reverse(const char* str)
{
size_t length = strlen(str);
char* result = malloc(length + 1);
if (result == NULL)
{
return NULL;
}
result[length] = 0;
if (length == 0)
{
return result;
}
size_t last = length - 1;
size_t it = 0;
while (it <= last)
{
result[it] = str[last - it];
++it;
}
return result;
}
int main(void) {
const char* str = "ABCD";
char* reversed = str_reverse(str);
printf("%s\n", reversed);
if (str[4] != 0)
{
printf("problems\n");
}
free(reversed);
return 0;
}
Returning a pointer to a local variable
Returning a pointer to the local variable output is incorrect. It may happen to work but it is wrong to do so, because the storage for that local variable goes out of scope the moment you return from the function. To be correct, you should either malloc a buffer and return it (preferred) or make output be static.
Empty initializer list
Initializing output to {} is nonstandard C and should be avoided. The standard way to initialize an array to zeroes is {0}.
Unnecessary variable
Your input variable is unnecessary because you can just use c wherever you used input.
Bad algorithm
Your string reversal function takes \$O(n^2)\$ time when it should only take \$O(n)\$ time. The problem is that you use strcat to append one character at a time, and strcat needs to find the end of the string each time. If you ever find yourself using strcat in a loop, it's probably not the best way.
Other things
- Using
scanf("%s",in);to read into a fixed size string is unsafe and could result in a buffer overflow. - You should also print a newline when you print the result otherwise your shell prompt will be on the same line as your output.
- Your function argument
ccould be markedconstsince you do not modify it. Also,csounds like a character not a string. - Since you are already using C99 style variable declarations, you can put the
int ideclaration inside theforloop.
Suggested rewrite
char *reverseString(const char *str)
{
size_t len = strlen(str);
char *ret = calloc(len+1, sizeof(char));
if (ret == NULL)
return NULL;
for (size_t i = 0, j = len-1; i < len; i++, j--)
ret[i] = str[j];
return ret;
}