Reputation: 497
I am practicing for interviews. The problem Im currently stuck on is reversing a constant string in C. I know that since str2 is const, I can modify the location str2 points to, but not its value. I have a function below called reverse_const. It will reverse the const char *str_const in place and print it. However, when I try to print st2 after reversal from the main method, the string isn't reversed anymore. Its like reverse_const() is temporarily changing the memory location of str2. What am I doing wrong here?
#include <stdio.h>
#include <string.h>
void reverse(char *str){
int c_size = strlen(str);
char *c_begin = str, *c_end = str + (c_size - 1);
int i;
for(i = 0; i < c_size / 2; i++){
*c_begin ^= *c_end;
*c_end ^= *c_begin;
*c_begin ^= *c_end;
c_begin++;
c_end--;
}
}
void reverse_const(const char *str_const){
int c_size = strlen(str_const);
char str[c_size];
strcpy(str, str_const);
char *c_begin = str, *c_end = str + (c_size - 1);
int i;
for(i = 0; i < c_size / 2; i++){
*c_begin ^= *c_end;
*c_end ^= *c_begin;
*c_begin ^= *c_end;
c_begin++;
c_end--;
}
str_const = str;
printf("%s\n", str_const);
}
int main(){
char str1[] = "Indiana";
char *str2 = "Kentucky";
printf("TESTS:\nString 1 pre-reversal: %s\n", str1);
reverse(str1);
printf("String 1 post-reversal: %s\n", str1);
printf("Constant string 2 pre-reversal: %s\n", str2);
reverse_const(str2);
printf("Constant string 2 post-reversal: %s\n", str2);
}
Upvotes: 0
Views: 4639
Reputation: 84559
If you want the reversed str2
back in main()
, you will either need to pass an adequately sized buffer to reverse_const
to hold the reversed string, or you will need to dynamically allocate storage for it in reverse_const
(a local variable length array won't do):
#include <stdlib.h>
...
void reverse_const (const char **str_const)
{
int c_size = strlen (*str_const);
char *str = calloc (c_size + 1, sizeof *str);
strcpy (str, *str_const);
char *c_begin = str, *c_end = str + (c_size - 1);
int i;
for (i = 0; i < c_size / 2; i++) {
*c_begin ^= *c_end;
*c_end ^= *c_begin;
*c_begin ^= *c_end;
c_begin++;
c_end--;
}
*str_const = str;
printf ("%s\n", *str_const);
}
int main (void) {
char str1[] = "Indiana";
char *str2 = "Kentucky";
printf ("TESTS:\nString 1 pre-reversal: %s\n", str1);
reverse (str1);
printf ("String 1 post-reversal: %s\n", str1);
printf ("Constant string 2 pre-reversal: %s\n", str2);
reverse_const ((const char **)&str2);
printf ("Constant string 2 post-reversal: %s\n", str2);
free (str2);
return 0;
}
Output
$ ./bin/revconststr
TESTS:
String 1 pre-reversal: Indiana
String 1 post-reversal: anaidnI
Constant string 2 pre-reversal: Kentucky
ykcutneK
Constant string 2 post-reversal: ykcutneK
Returning The Pointer
You have an additional option to return the pointer to str
to assign to str2
in main()
. This is more what you would normally expect to see. Let me know if you have any questions:
char *reverse_const2 (const char **str_const)
{
int c_size = strlen (*str_const);
char *str = calloc (c_size + 1, sizeof *str);
strcpy (str, *str_const);
char *c_begin = str, *c_end = str + (c_size - 1);
int i;
for (i = 0; i < c_size / 2; i++) {
*c_begin ^= *c_end;
*c_end ^= *c_begin;
*c_begin ^= *c_end;
c_begin++;
c_end--;
}
//*str_const = str;
printf ("%s\n", *str_const);
return str;
}
int main (void)
{
char str1[] = "Indiana";
char *str2 = "Kentucky";
printf ("TESTS:\nString 1 pre-reversal: %s\n", str1);
reverse (str1);
printf ("String 1 post-reversal: %s\n", str1);
printf ("Constant string 2 pre-reversal: %s\n", str2);
str2 = reverse_const2 ((const char **)&str2);
printf ("Constant string 2 post-reversal: %s\n", str2);
free (str2);
return 0;
}
Upvotes: 2
Reputation: 25579
You need to write your function so that you have some way to return the argument modified.
One such solution is pass-by-reference:
void reverse_const(const char **str_const){
const char *in = *str_const;
char *out = malloc(strlen(in)+1);
/* write to out */
*str_const = out;
}
But a better way would be to use the return value:
char *reverse_const(const char *str_const){
const char *in = str_const;
char *out = malloc(strlen(in)+1);
/* write to out */
return out;
}
The return type could be const char *
, but that's an unnecessary restriction since you know the returned string may be safely modified.
Note that both examples use malloc
. Arrays cannot be passed back, in this manner, in C, as they exist on the stack and are destroyed when the function exits.
Whenever a long-running program uses malloc
, there really ought to be a matching free
somewhere in the code, or else you'll have a memory leak. It's a pain, but something all C programmers must master.
Upvotes: 2
Reputation: 60067
When you pass by arguments, the function gets a copy. str_const = str;
assigns to that copy. You could pass a pointer to pointer to be able change the value of a pointer outside of your function, however you're allocating the string copy on the stack, and therefore the string copy becomes invalid once you leave the scope of reverse_const
so this wouldn't make sense here.
If you want a string copy that survives the end of the reverse_const
, allocate the array with malloc
or do both the allocation and the copying with strdup
. That you have to return the malloc'ed
pointer somehow (by a return value of via a pointer to pointer argument) and the caller will then have the responsibility to free
that malloc
'ed memory once it's done with it.
Upvotes: 2
Reputation: 409196
The problem here is that you modify the argument passed to reverse_const
, but arguments in C are passed by value meaning that they are copied. The variable you modify in the function is a copy of the original pointer, changing a copy will of course not change the original.
C doesn't have pass by reference which is needed here, but it can be emulated by using pointers, in the case of your function you need to pass a pointer to the pointer, then use the dereference operator *
to modify what the pointer to pointer points to, and use the address-of operator &
when calling the function.
Upvotes: 1