I am trying to understand pass by value and reference and I thought c was a language of pass by reference and tried to implement a swap function, that changes the values of two numbers to have values of each other, but the values don't seem to change at all. so can you please see the ff code and point out what I am doing wrong? in my thought, since we are assigning the pointer variables to have a value of another variable(which points to a certain number) it should have swapped the values but it's not what is happening(i.e. The values don't get swapped) so there must be some thing I am not understanding. would appreciate if you can help
#include <stdio.h>
void swap(int *a, int *b){
int *temp;
temp = a;
a=b;
b=temp;
}
int main()
{
int a = 78;
int b = 98;
int *c=&a;
int *d=&b;
swap(c,d);
//swap(&a,&b)
printf(" a is %d and b is %d \n",*c,*d);
return 0;
}
CodePudding user response:
C is always pass-by-value.
what you're looking for is
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
This way you will be passing the addresses of the integers you want to swap, and the swap function will swap the values written in those address.
CodePudding user response:
I am trying to understand pass by value and reference and I thought c was a language of pass by reference
No, C is a language of pass by value.
C has reference parameters. In C , you could have written something very close to your original, and it would have worked:
void swap(int &a, int &b){
int temp;
temp = a;
a = b;
b = temp;
}
Declarations like `` say that the parameter will be passed by reference. So when you say things like temp = a
and a = b
, you're actually affecting the caller's variable, as you want to. (The other change I made here is that temp
is a plain int
.)
But that was C . In C, there are no reference parameters, and everything [note 1] is passed by value. But you can use pointers to explicitly simulate pass by reference. It looks like this:
void swap(int *a, int *b){
int temp;
temp = *a;
*a = *b;
*b = temp;
}
This is also close to what you originally wrote, with the exception that we are explicitly manipulating *a
and *b
. If a
and b
are pointers to variables in the caller, then we write *a
and *b
to say that we are manipulating what the pointer points to, that is, the variables in the caller.
In this case we must call
swap(&a, &b)
in the caller (as in fact you had in a comment).
[Note 1: Arguably, there is one place in C that does have pass by reference, and that's when you pass an array to a function. See more discussion at this question.]
CodePudding user response:
In C the term pass by reference means passing an object indirectly through a pointer to it. So dereferencing the pointer you have a direct access to the object pointed to by the pointer.
Thus if you want to change values of the variables a
and b
within the function swap
you need to dereference the passed pointers that point to the variables to get the access to them.
void swap(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
}
If you want to swap the pointers themselves to make the pointer c
to point to the variable b
and the pointer d
to point to the variable a
then again you need to pass them to the function by reference through pointers to them.
In this case the function will look the following way
void swap(int **a, int **b){
int *temp = *a;
*a = *b;
*b = temp;
}
and can be called like
swap( &c, &d );
CodePudding user response:
You are just swapping the local copies of your pointers, not the things the pointer point to, as you forgot to dereference your pointers. Also, your temp value holds a pointer too, which doesn't make sense - it should hold one of the values you are swapping.
Instead of this...
int *temp;
temp = a;
a = b;
b = temp;
...you need this:
int temp;
temp = *a;
*a = *b;
*b = temp;
For better understanding, let's explain this with an analogy.
Suppose your memory is a cabinet full of drawers. Each draw is labelled with some letter (its address), and in the drawers, there are pieces of paper with other numbers or letters written on them (the values stored at each address). In this explanation I use letters as addresses even though in reality, addresses are numbers as well.
Now let's see what happens in your original code. To simplify the explanation, I will inline the function.
This is what we have then:
int a = 78;
int b = 98;
int *c = &a;
int *d = &b;
int *temp = c;
c = d;
d = temp;
And this is what it does:
// Let's put a note with `78` written on it into drawer `A`.
int a = 78;
// Now we have: A="78"
// Let's put a note with `98` written on it into drawer `B`.
int b = 98;
// Now we have: A="78", B="98"
// Let's put a note with `A` written on it into drawer `C`.
int *c = &a;
// Now we have: A="78", B="98", C="A"
// Let's put a note with `B` written on it into drawer `D`.
int *d = &b;
// Now we have: A="78", B="98", C="A", D="B"
// Let's check the note in drawer `C` (which currently says `A`)
// and put a similar note into drawer `T`.
int *temp = c;
// Now we have: A="78", B="98", C="A", D="B", T="A"
// Let's check the note in drawer `D` (which currently says `B`)
// and put a similar note into drawer `C` (discarding what is
// already there).
c = d;
// Now we have: A="78", B="98", C="B", D="B", T="A"
// Let's check the note in drawer `T` (which currently says `A`)
// and put a similar note into drawer `D` (discarding what is
// already there).
d = temp;
// Now we have A="78", B="98", C="B", D="A", T="A"
If you look at the final result, you will see that the contents of the drawers A
and B
never changed. We just fiddled around a bit with our drawers C
, D
and T
.
Now let's look at the working solution, again inlined for simplicity:
int a = 78;
int b = 98;
int *c = &a;
int *d = &b;
int temp = *c;
*c = *d;
*d = temp;
And see how it works now:
// Let's put a note with `78` written on it into drawer `A`.
int a = 78;
// Now we have: A="78"
// Let's put a note with `98` written on it into drawer `B`.
int b = 98;
// Now we have: A="78", B="98"
// Let's put a note with `A` written on it into drawer `C`.
int *c = &a;
// Now we have: A="78", B="98", C="A"
// Let's put a note with `B` written on it into drawer `D`.
int *d = &b;
// Now we have: A="78", B="98", C="A", D="B"
// ==== SO FAR SO GOOD, NOW LET'S SEE WHAT IS DIFFERENT THIS TIME ===
// Let's check the note in drawer `C` (which currently says `A`).
// Then LOOK INTO ANOTHER DRAWER according to the note we just found
// (which said `A`), look at the note in there (which currently says
// `78`) and put a similar note into drawer `T`.
int temp = *c;
// Now we have: A="78", B="98", C="A", D="B", T="78"
// Let's check the note in drawer `D` (which currently says `B`).
// Then LOOK INTO ANOTHER DRAWER according to the note we just found
// (which said `B`), look at the note in there (which currently says
// `98`) and prepare a similar note.
// Then check the note in drawer `T` (which currently says `A`).
// Then OPEN ANOTHER DRAWER according to the second note we just found
// (which said `A`), and put the copied note that we got before
// (which said `98`) into that drawer.
*c = *d;
// Now we have: A="98", B="98", C="A", D="B", T="78"
// Let's check the note in drawer `T` (which currently says `78`)
// and prepare a similar note.
// Then check the note in drawer `D` (which currently says `B`).
// Then OPEN ANOTHER DRAWER according to the second note we just found
// (which said `B`), and put the copied note that we got before
// (which said `78`) into that drawer.
*d = temp;
// Now we have A="98", B="78", C="A", D="B", T="78"
The difference is that this time we use C
and D
only to store a "pointer" to A
and B
, and not directly any numbers, so we always looked into C
or D
to find another drawer's letter in there and then continue accessing that drawer, so we ended up actually swapping the numbers in A
and B
as we wanted.
You may say, "why did we even have to use extra drawers C
and D
then?", and you would be right - but only because this example inlined the function call. If you call a function, you have to pass some "notes" (arguments) to it which it will put in its own drawers (argument variables) - you can't pass whole drawers (i.e. values by reference). So instead of being able to pass the drawers A
and B
directly, you do the next best thing and pass two notes with A
and B
written on them - your pointers - which the function will put into its own drawers C
and D
at that point. The function can then check what's written on these notes to know which actual drawers (with your numbers in them) you wanted the function to operate on.
By the way, C is pass-by-value, not pass-by-reference. C can be both because it has a reference type, but C doesn't. All you can do is use pointers, but then you are technically still passing a pointer by value, although logically speaking, you can view the pointer as reference to some value so you could say you are passing that value by reference, even though syntactically you aren't.
For comparison, in C you could do this:
// The & here is *not* related to pointers but means
// "pass this argument by reference", essentially
void swap (int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
// ...
int a = 123;
int b = 456;
swap(a, b);
In terms of the analogy above, this would be equivalent to passing the whole drawers A
and B
to the function so that the function can temporarily put them into its own cabinet and swap the notes inside of them, instead of passing notes with the labels of your own drawers.