Reputation: 51
My question is to understand why this happens.
My goal is to pass a first name 'Joe' and last name 'Bloggs' into the swap function I created and have it switch them around. (So First name will now contain Bloggs vice versa)
I've created a swap function that takes pointers to the first and last name as arguments. The function appears to work because using the print statement I can see the values of the two strings has changed.
#include <stdio.h>
void swap(char * first, char * last) {
char * temp;
temp = first;
first = last;
last = temp;
printf("at end of swap func the first name is: %s\n", first);
printf("at end of swap func the last name is: %s\n", last);
}
Now here appears to be the problem, after the swap function is called, I print the first and last name again, but they aren't displaying the results of the swap function.
int main() {
char * first = "Joe";
char * last = "Bloggs";
printf("The original format: %s %s\n", first, last);
swap(first, last);
printf("The new format: %s %s", first, last);//new format was supposed to be Bloggs Joe
}
I have searched SO but the questions I've found are not specific to mine. As I said earlier, I'd really like to know why this happens. I have very little knowledge of C so any suggestions will be appreciated.
Upvotes: 4
Views: 2669
Reputation: 224387
In C, all parameters are pass by value. That means that first
and last
in the function are distinct from first
and last
in main
. Changes to a local variable are not reflected in the caller.
You need to pass the address of the variables you want to change. Then in the function, you dereference the given pointers to change what they point to.
So change your function as follows:
void swap(char ** first, char ** last) {
char * temp;
temp = *first;
*first = *last;
*last = temp;
printf("at end of swap func the first name is: %s\n", *first);
printf("at end of swap func the last name is: %s\n", *last);
}
And call it like this:
swap(&first, &last);
Note that what's actually being swapped are the pointer values, not what the pointers actually point to. You could swap the characters between the two strings, but the strings in question are string literals which cannot be modified.
If you had char
arrays that contained strings, then you could swap the characters. In fact, you would have to do it that way because arrays are not the same as pointers.
Here's a full example of how you would do a full string swap:
#include <stdio.h>
#include <string.h>
// assumes that each array is big enough to hold the contents of the other
void swap(char *first, char *last) {
int len1 = strlen(first);
int len2 = strlen(last);
int maxlen = (len1 > len2) ? len1 : len2;
char temp[maxlen+1];
strcpy(temp, first);
strcpy(first, last);
strcpy(last, temp);
printf("at end of swap func the first name is: %s\n", first);
printf("at end of swap func the last name is: %s\n", last);
}
int main() {
char first[10] = "Joe";
char last[10] = "Bloggs";
printf("The original format: %s %s\n", first, last);
swap(first, last);
printf("The new format: %s %s", first, last);
}
Upvotes: 11
Reputation: 70472
Swapping variables is idiomatically done inline with a temporary:
char *temp;
temp = first;
first = last;
last = first;
This doesn't translate well into a C function call, which uses pass by value. This means the function receives a copy of the value as its parameters. You could write a macro instead, but a general purpose macro has to take care of issues like arguments being expressions, and avoid name collisions of its own internal variables from the parameters being passed in.
#define swap(A, B) do { \
char **swap_A__ = &(A); \
char **swap_B__ = &(B); \
char *swap_temp__ = *swap_A__; \
*swap_A__ = *swap_B__; \
*swap_B__ = swap_temp__; \
} while (0)
This saves you from writing a function, but the implementation loses the simplicity of the idiomatic approach.
While the function call would be preferred, it loses the appearance of a pass by reference interface. If you were able to implement a generic swapping function:
void swap_generic(void *a, void *b, size_t sz);
Then, you could wrap your swap macro to call the generic function, and give you the ability to simulate a "call by reference" interface, but passing the appropriate arguments to the generic function:
#define swap(A, B) do { \
_Static_assert(sizeof(A) == sizeof(B), "unswappable"); \
_Static_assert(sizeof(&(A) - &(B)), "type check"); \
swap_generic(&(A), &(B), sizeof(A)); \
} while (0)
Implementing the generic swapping function could be done as follows:
void swap_generic (void *a, void *b, size_t sz) {
char *aa = a;
char *bb = b;
while (sz--) {
char temp = *aa;
*aa++ = *bb;
*bb++ = temp;
}
}
Upvotes: 1
Reputation: 3244
#include <stdio.h>
void swap(char ** first, char ** last) {
char * temp;
temp = *first;
*first = *last;
*last = temp;
printf("at end of swap func the first name is: %s\n", *first);
printf("at end of swap func the last name is: %s\n", *last);
}
int main() {
char * first = "Joe";
char * last = "Bloggs";
printf("The original format: %s %s\n", first, last);
swap(&first, &last);
printf("The new format: %s %s", first, last);//new format was supposed to be Bloggs Joe
}
Pass the address of parameters if you want to change it, not the values.
Upvotes: 0