I'm trying to self-study C using C Primer Plus from Stephen Prata and one of the end-of-chapter exercises is to "Write a function that replaces the contents of a string with the string reversed.". This is a chapter on character strings with a good dose of pointers. I'm trying to use pointers as much as possible so I can better understand, but I'm stuck.
My problem is that when I print the value of the return pointer in main, it is garbled.
When I use gdb(just learning how to use that too), I can see that the memory address returned from my function is the same address that was used in the function and it's getting assigned to my pointer in main okay as far as I can tell.
I've tried so many things, what am I missing? FWIW I have not learned about malloc yet in the book, though I see it referenced on various www pages I've frequented trying to better understand C.
$ cc -o exercise8 exercise8.c && ./exercise8
This is s1 before: abcd
This is s2 in function: dcba
This is s3 after: d`!
/* A function that replaces the contents of a string with the string reversed. */
#include <stdio.h>
#include <string.h>
char *str_rev(char * string);
int main(void)
{
char * s1 = "abcd";
char * s3;
printf("This is s1 before: %s\n", s1);
s3 = str_rev(s1);
printf("This is s3 after: %s\n", s3);
}
char *str_rev(char * string)
{
char ar3[5];
char * s2;
int len = 0;
s2 = ar3;
len = (strlen(string) - 1);
string = string + len;
while ( len >= 0 )
{
*s2 = *string;
len--;
string--;
s2++;
}
s2++;
*s2 = 0;
s2 = s2 - 5;
printf("This is s2 in function: %s\n", s2);
return s2;
}
$ gdb exercise8 GNU gdb (GDB) 7.1-ubuntu Reading symbols from exercise8...done. (gdb) break 12 Breakpoint 1 at 0x804844a: file exercise8.c, line 12. (gdb) break 40 Breakpoint 2 at 0x80484d9: file exercise8.c, line 40. (gdb) run Starting program: exercise8 This is s1 before: abcd // My original string. This is s2 in function: dcba // Good, my reversed string while in the function. Breakpoint 2, str_rev (string=0xbffff043 "dcba") at exercise8.c:40 40 return s2; (gdb) print s2 $1 = 0xbffff043 "dcba" // Location of pointer s2. (gdb) continue Continuing. Breakpoint 1, main () at exercise8.c:12 12 printf("This is s3 after: %s\n", s3); (gdb) print s3 $2 = 0xbffff043 "dcba" // Back in main same pointer as s2 from function. (gdb) step This is s3 after: d`Q // Line 12 executed. Output garbled. 14 } (gdb)
You're returning a pointer to a local variable, (automatic variable to speak in ISO standard terms,) which is allocated on the stack, as soon as you return from your function that memory is released leaving you with a dangling pointer pointing to memory that may or may not still contain the string you put there, it depends entirely on circumstances. You should provide the output buffer as a function argument, or allocate it with malloc, or in C++ with new.
edit; added some example code
or
s2
points to your localar3
array. Therefore whenstr_rev
returns, it is no longer valid to look at the memory wherear3
was vias2
. Nows2
is called a dangling pointer, and this is one of the huge pains in learning to use C pointers correctly.For a simple solution that doesn't use
malloc
and meets the exercise requirement of "replaces the contents of a string", try copying the result into the function argument pointer (the originalstring
; but be careful since your current code has since changed the pointerstring
). You know this pointer points at memory with enough characters and isn't local to your function.The problem description sounds like you can just reverse the string in place. Keep it simple.
The above code will make s2 points to a character string on the stack. This ar3 variable will be deleted once your function finishes.
You should output to some variable that you have pre-allocated. Modify it as follow
Of course, once you get to the chapter regarding malloc, you can allocate the necessary memory for s3 depending on the length of s1. Until then, read on and have fun.
Part of the problem is that you can't actually "replace the contents of a string with the string reversed" when you are dealing with string literals, ie. strings delcared in the form
char * s1 = "abcd";
Without using literals, I made a relatively easy to understand recursive example:
On my system the output is as follows: