Pass by reference in C for swapping function - c

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;
}

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.

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.]

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 );

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.

C is strictly pass-by-value - formal parameters in the function definition are always separate objects in memory that receive copies of the values from the actual parameters in the function call. To help make this clear I'm going to use different names for the formal and actual parameters:
void swap( int a, int b )
{
int tmp = a;
a = b;
b = tmp;
}
int main( void )
{
int x = 10, y = 20;
printf( "Before swap: x = %d, y = %d\n", x, y );
swap( x, y );
printf( " After swap: x = %d, y = %d\n", x, y );
return 0;
}
a and b are different objects in memory than x and y - when you call swap, the expressions x and y are fully evaluated, and the results of those evaluations (the integer values 10 and 20) are copied to a and b.
Any changes to a or b have no effect on x or y, so the output of the above program will be
Before swap: x = 10, y = 20
After swap: x = 10, y = 20
To fake pass-by-reference semantics, we use pointers:
void swap( int *a, int *b )
{
int tmp = *a;
*a = *b;
*b = tmp;
}
int main( void )
{
int x = 10, y = 20;
printf( "Before swap: x = %d, y = %d\n", x, y );
swap( &x, &y );
printf( " After swap: x = %d, y = %d\n", x, y );
return 0;
}
a and b are still separate objects in memory from x and y, but instead receiving copies of of the values of x and y, they receive the results of the expressions &x and &y, or the addresses of x and y, giving us this set of conditions:
a == &x // int * == int *
b == &y // int * == int *
*a == x // int == int
*b == y // int == int
The expressions *a and *b can kinda-sorta-but-not-really be thought of as aliases for x and y - writing to *a in swap is the same as writing to x in main.
This time, the output would be
Before swap: x = 10, y = 20
After swap: x = 20, y = 10

Related

Accessing variable value without declaring it in function prototype

In the function read, I need to access the values of integer a and integer b from the main function without declaring them in the prototype of the function read, using pointers.
Pointer x should point to integer a, and pointer y should point to integer b.
#include <stdio.h>
void read(int zzz[], int n) {
int *arr = zzz, *x=a,*y=b;
}
int main() {
int a, b;
scanf("%d", &a);
scanf("%d", &b);
return 0;
}
How this could be implemented?
There are two ways that the read function can read the values or addresses of a and b:
Pass them as parameters
Make a and b global
So if you don't want to make them parameters, you need to move them outside of the main function and before the read function.
Also, read is the name of a system function, so you should name it something else so you don't conflict with it.
You have already received the more conventional answer. It is the most logical choice for your given restriction.
However ... Silly artificial restrictions sometimes deserve a silly contrived solution in kind.
A less conventional way would be to create an understanding with the function that the values will be passed in with the array pointer in some non-standard way.
For example, you can make two extra array members to represent a and b.
int array_for_my_read[array_size + 2];
/* instead of a and b, you use those extra array members */
...
int *x = zzz + n, *y = x + 1;
Alternatively, you could create a special structure that holds the array, and the pointers. Then the function recovers the pointer to the structure from the array pointer.
struct extra_parameters {
int *a;
int *b;
int zzz[zzz_size];
};
...
struct extra_parameters x;
int a, b;
x.a = &a;
x.b = &b;
read(x.zzz, zzz_size);
...
void *p = (char *)zzz - offsetof(struct extra_parameters, zzz);
struct extra_parameters *xp = p;
int *a = xp->a, *b = xp->b;

Why the value stored in 'z' is 35? Shouldn't it be 20 since in the function 'c=*b' (c is equal to the value pointed by *b)?

In the following code:
#include <stdio.h>
void shuffle(int* a, int* b, int c) {
int temp = *a;
*a = *b + c;
c = *b;
*b = temp;
}
int main() {
int x = 10;
int y = 20;
int z = 35;
shuffle(&x,&y,z);
printf("x: %i\n", x);
printf("y: %i\n", y);
printf("z: %i\n", z);
return 0;
}
The value of 'z' remains 35. Why is that so? Shouldn't the value be 20? Since:
c = *b;
When you pass a, b and c as parameters you can notice something, that int c is not passed as a pointer. In C the parameters can be passed two ways.
The first is reference-passed parameter, the parameter is passed as the address of the variable, any change done to the content of that address will persist even out of the function.
The second way is to pass it as a by-value parameter, in that case, you only create a copy of the content of the "passed" variable to another.
Now, int* a is passed as a reference (because it is a pointer), lets say a=0x12341234(address of a) and its value is 10, and one more time, int c (not a pointer) has 0x10101010 as an address with a value of 35.
Then, when our function is called with a as a pointer and c as a normal integer, we can realize that inside the function the address of a stills 0x12341234, however, address of c is now 0x20202020(for example). We have created a copy of c in another place of the memory. Modifying a copied variable does not modify the original variable. This is like:
int original = 20;
int copy = original;//we see that copy is a COPY of original
copy = 321;//Original still being 20

Why does a swap function only work when using pointers?

Here is an example of what I mean. This example is without using pointers and the variables do not swap.
void swap(int x, int y);
main()
{
int a = 33, b = 55;
swap (a, b);
printf("a = %d, b = %d\n", a, b);
}
void swap(int x, int y)
{
int temp;
temp = x;
x = y;
y = temp;
}
Now if you use pointers the variables a and b swap. Why is it that it only works with pointers?
C is a pass-by-value language. Always. That means with this:
void swap(int x, int y)
{
int temp = x;
x = y;
y = temp;
}
you're swapping the values of x and y, obtained from the values passed to the function. When you invoke like this:
int main()
{
int a = 33, b = 55;
swap (a, b); // passing values of a and b
printf("a = %d, b = %d\n", a, b);
}
the values of a and b are passed. So this is your problem. The solution is to make the values passed something that can be used to modify the caller's variables. If you want to modify those variables they need to somehow be addressable from the called code. Hmmm...
The mechanism is called "pass by address", and though it sounds fancy in reality it isn't. It is simply a retooling of pass-by-value, but with a different value type. Whereas before we were passing values of type int we will instead pass addresses of the integer variables and declare the formal parameters to be pointers to int instead. Make no mistake. They're still values, but not of the basic int type. Rather the values passed are addresses of int variables. To access the data at those addresses pointers are used in conjunction with the dereference operator (of which there are several kinds, only one shown here):
void swap(int *ptrToX, int *ptrToY)
{
int temp = *ptrToX; // dereference right, store value in temp
*ptrToX = *ptrToY; // dereference both, assigning value from right to left.
*ptrToY = temp; // dereference left, assign temp value
}
and invoked like this:
int main()
{
int a = 33, b = 55;
swap (&a, &b); // passing addresses of a and b
printf("a = %d, b = %d\n", a, b);
}
Note: Often ill-quoted as the exception to pass-by-value is passing an array. Though the phrase "decays to a pointer" is thrown about like confetti on New Years Eve, I abhor that vernacular. The verb itself implies a functional operation where there is, in fact, none.
The language specifies the value of an array used in an expression is the address of its first element. In other words, its "value" is already an address and as such can simply be passed by-value to a function expecting a pointer to the same base type. Because it is an address, the receiving parameter (a pointer, because thats what holds address values) can then be used to modify the array content from the caller. Second only to multiple levels of indirection (pointers to pointers, etc) it is easily the hardest thing for people new to C to wrap their head around, yet it is important you do so.
When you call swap, the value of the variables a and b are passed to it. These values are passed by copy. When you swap those values in swap, you are only swapping local copies of a and b.
When you pass pointers to variables to a function, you are able to modify the values of the variables in the calling function.
That's called pass by value.
You are just passing values of a & b to the swap function. The swap function copies that value into its variables x & y which are different from a & b. Hence in swap you are working on x & y instead of a & b.
On the other hand, when you pass pointers, you are passing the address where a & b are stored. Your x & y point to the same address and hence you are manipulating the content at that address where a & b are stored. Hence, main gets to see the updated values.
This is the best example to define the advantage/use of function call by reference V/s call by value
In the main() function the two variables has the value
int a = 33, b = 55;
so using these variables in the swap(a,b) function, it just passes the values to the function definition where
void swap(int x, int y)
{
int temp;
temp = x;
x = y;
y = temp;
}
they declare again two variables x,y and the values in this variables are swapped. But the variables x and y are only known to function swap() after execution of the swap() function that variables are no longer valid. So nothing happens to the variables a,b in the main function.
So in order to swap variables using function you've to use
swap(&a,&b);
in main() function , and modify function swap()
void swap(int *x, int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
Which passes the address of variables a and b , and the pointers are used to swap the variables,It gets swapped effectively. Since pointer points to the address of the variables the value of the variables get changed.
For more google "call by referece and call by value in c"

Why do these swap functions behave differently?

#include <stdio.h>
void swap1(int a, int b)
{
int temp = a;
a = b;
b = temp;
}
void swap2(int *a, int *b)
{
int *temp = a;
a = b;
b = temp;
}
void swap3(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
main()
{
int a = 9, b = 4;
printf("%d , %d\n", a, b);
swap1(a, b);
printf("%d , %d\n", a, b);
swap2(&a, &b);
printf("%d , %d\n", a, b);
swap3(&a, &b);
printf("%d , %d\n", a, b);
}
C has value semantics for function parameters. This means the a and b for all your three swap variants are local variables of the respective functions. They are copies of the values you pass as arguments. In other words:
swap1 exchanges values of two local integer variables - no visible effect outside the function
swap2 exchanges values of two local variables, which are pointers in this case, - same, no visible effect
swap3 finally gets it right and exchanges the values pointed to by local pointer variables.
You're swap2 function has no effect.
You are passing in two pointers. Inside the function, the (parameter) variables a and b are local to the function. The swap2 function just swaps the values of these local variables around - having no effect outside the function itself.
As Anon pointed out, swap1 has the same problem - you're just modifying local variables.
swap1 will not work because the function just copied the arguments, not affecting the variables in main.
swap2 will not work either.
swap1() and swap2() have an effect limited to the scope of the function itself: the variables they swap are parameters passed by copy, and any change applied to them does not impact the source variable of your main() that were copied during the function call.
swap3 works as it acts on the values pointed by the parameters, instead of acting on the parameters themselves. It is the only of the three that chage the value located at the memory adress in which your main()'s a and b variables are stored.
Just for fun, exchange values without the use of a temporary variable
x = x ^ y
y = x ^ y
x = x ^ y

Simple swap function...why doesn't this one swap?

I'm new to C and still trying to grasp the concept of pointers. I know how to write a swap function that works...I'm more concerned as to why this particular one doesn't.
void swap(int* a, int* b)
{
int* temp = a;
a = b;
b = temp;
}
int main()
{
int x = 5, y = 10;
int *a = &x, *b = &y;
swap(a, b);
printf(ā€œ%d %d\nā€), *a, *b);
}
You're missing *s in the swap function. Try:
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
That way, instead of just swapping the pointers, you're swapping the ints that the pointers are pointing to.
Your swap() function does work, after a fashion - it swaps the values of the variables a and b that are local to swap(). Unfortunately, those are distinct from the a and b in main() - so you don't actually see any effect from swapping them.
When thinking about pointers, you need to be clear on a few abstractions.
An object in memory. This can be of any type (and size). An integer object, for example, will occupy 4 bytes in memory (on 32 bit machines). A pointer object will occupy 4 bytes in memory (on 32 bit machines). As should be obvious, the integer object holds integer values; a pointer object holds addresses of other objects.
The C programming language lets symbols (variables) represent these objects in memory. When you declare,
int i;
the symbol (variable) i represents some integer object in memory. More specifically, it represents the value of this object. You can manipulate this value by using i in the program.
&i will give you the address of this object in memory.
A pointer object can hold the address of another object. You declare a pointer object by using the syntax,
int* ptr;
Just like other variables, the pointer variable represents the value of an object, a pointer object. This value just happens to be an address of some other object. You set the value of a pointer object like so,
ptr = &i;
Now, when you say ptr in the program, you are referring to its value, which is the address of i. But if you say *ptr, you are referring to not the value of ptr, but rather the value of the object whose address is in ptr i.e. i.
The problem with your swap function is that you are swapping values of pointers, not the values of objects that these pointers hold addresses for. To get to the values of objects, you would have to use *ptr.
C is a pass-by-value language. Your swap routine doesn't dereference the pointers passed to it, so from main's perspective nothing has happened.
The pointers are passed by value. This means a & b are still a and b when the come back from the function;
try something like this
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
The right way to do it:
void swap(int* a, int* b)
{
int temp = *a; // Temp is set to the value stored at a (5)
*a = *b; // value stored at a is changed to the value stored at b (10)
*b = temp; // value stored in address b is changed to 5.
}
It does swap. It swaps local pointers a and b inside swap function. It swaps them perfectly fine, as it should.
If you want to swap the values these pointers are pointing to, you should re-implement your swap function accordingly, i.e. make it swap the pointed values, not the pointers.
Umm maybe using this
void swap(int** a, int** b)
{
int** temp = a;
a = b;
b = temp;
}
int main()
{
int x = 5, y = 10;
int *a = &x, *b = &y;
swap(&a, &b);
printf(ā€œ%d %d\nā€), *a, *b);
}
Without using a third variable (temp)
void swap(int* a,int* b)
{
// a = 10, b = 5;
*a = *a + *b; // a now becomes 15
*b = *a - *b; // b becomes 10
*a = *a - *b; // a becomes 5
}
zildjohn1's answer is the easiest and clearest way to do it. However if you insist on swapping the pointers, then you have to pass the pointer to the pointer because the pointer itself is passed by value.
You need to send the address of a and b for swap function so while calling swap function you must call ass swap (&a,&b)
So that you pass the address, and alter the address
#define SWAP(a,b) ((a)=(b)+(a),(b)=(a)-(b),(a)=(a)-(b))
Works good.

Resources