Confused with C pointers - c

#include<stdio.h>
// Function to swap two values but does not work
void swapDoesNotWork (int *ptrX, int *ptrY);
// Function to swap two values and works fine
void swap (int *ptrX, int *ptrY);
void swap (int *px, int *py) {
int temp;
temp = *px;
*px = *py;
*py = temp;
}
void swapDoesNotWork (int *px, int *py) {
printf("\n\n");
int temp;
temp = *px;
px = py;
py = &temp;
}
int main() {
int x = 5;
int y = 10;
swapDoesNotWork(&x, &y);
printf("++++++++++++++++++\n");
printf("pre x:%d\n", x);
printf("pre y:%d\n", y);
printf("\n");
printf("After calling swapDoesNotWork(&x, &y)...\n");
printf("post x:%d\n", x);
printf("post y:%d\n", y);
printf("++++++++++++++++++\n\n");
x = 5;
y = 10;
printf("= = = = = = = = =\n\n");
printf("pre x:%d\n", x);
printf("pre y:%d\n", y);
swap(&x, &y);
printf("\n");
printf("After calling swap(&x, &y)...\n");
printf("post x:%d\n", x);
printf("post y:%d\n", y);
printf("= = = = = = = = =\n\n");
return 0;
The output of the above program when compiled and executed is:
infi#linux% ./swap_test.o
++++++++++++++++++
pre x:5
pre y:10
After calling swapDoesNotWork(&x, &y)...
post x:5
post y:10
++++++++++++++++++
= = = = = = = = =
= = = = = = = = =
pre x:5
pre y:10
After calling swap(&x, &y)...
post x:10
post y:5
As can be seen, the swapDoesNotWork function does not seem to change the values as is the case with the swap function.
I am new to C language, coming from mostly scripting background. Can someone help me why swapDoesNotWork functon is not changing the values?

Here are all the modifications performed by swapDoesNotWork:
temp = ...
px = ...
py = ...
All of these are assignments to local variables. Local variables are destroyed when the function returns, so swapDoesNotWork has no lasting effects. It only changes variables that are about to stop existing anyway.
On the other hand, swap contains these lines:
*px = ...
*py = ...
These are assignments to locations pointed to by px and py, respectively. Even though px and py are local variables themselves, they can point to variables outside of the current function (in this case the function is called as swap(&x, &y), so they point to the x and y variables in main).

With what you are doing you just cancelled the whole point of using pointers.
What you are doing is basically the same as this:
temp = a;
a = b;
b = temp;
which means that you are acting on a copy of the original variables. So what you do although it is changing the values of the pointers (if you try a printf inside the function the results should be correct) after the function is finished the results disappear. In order for that function to work you would have to pass as an argument a double pointer. Hope I helped

Related

Why do we pass address instead of value as arguments to a swapping function in C?

I am solving the problem of swapping the value of two variables. I need to do it using a helper function. Now I've been studying the call-by-value and call-by-reference stuff.
My only confusion is when I'm passing the arguments to the swap function, why am I sending the address(&a, &b)? What actually happens when I'm sending the address instead of the value itself?
Here's the code
#include <stdio.h>
void swap(int a, int b) {
int temp;
temp = a;
a = b;
b = temp;
printf("After swapping values in function(using call by value) a = %d, b = %d\n",a,b);
}
void swapref(int *a, int *b) {
int temp2;
temp2 = *a;
*a=*b;
*b=temp2;
printf("After swapping values in function(using call by reference) a = %d, b = %d\n",*a,*b);
}
int main() {
int a = 10, b = 20;
printf("Before swapping the values in main a = %d, b = %d\n",a,b);
swap(a,b);
printf("After swapping values in main(using call by value) a = %d, b = %d\n",a,b);
swapref(&a,&b); // <-- This is the line I'm talking about
printf("After swapping values in main(using call by reference) a = %d, b = %d\n",a,b);
return 0;
}
In the above code, what actually happens in the swapref(&a, &b) line?
Passing the address is different than giving the value since you passe the exact memory case where your original variable (a and b) are stored. Like :
void swapref(int *a, int *b)
So when in the function you modify those value, you change the original ones.
Whereas passing variables values like :
void swap(int a, int b)
You're passing a copy of each variable, so the originals won't be touched.
swap() parameters are passed by copy, while swapref() ones are passed by reference (i.e. you pass the variable memory address, instead of its content).
* operator returns the value-pointed-to of a variable
& operator returns the address-of a variable
To better understand what happens, I suggest you to print their addresses
void swap(int a, int b) {
int temp;
temp = a;
a = b;
b = temp;
printf("After swapping values in function (using call by value) [%p]a = %d, [%p]b = %d\n", &a, a, &b, b);
}
void swapref(int* a, int* b) {
int temp;
temp = *a;
*a = *b;
*b = temp;
printf("After swapping values in function (using call by reference) [%p]a = %d, [%p]b = %d\n", &(*a), *a, &(*b), *b);
}
int main()
{
int a = 10, b = 20;
printf("Before swapping the values in main [%p]a = %d, [%p]b = %d\n", &a, a, &b, b);
swap(a, b);
printf("After swapping values in main (using call by value) [%p]a = %d, [%p]b = %d\n", &a, a, &b, b);
swapref(&a, &b); // <-- This is the line I'm talking about
printf("After swapping values in main (using call by reference) [%p]a = %d, [%p]b = %d\n", &a, a, &b, b);
return 0;
}
Output:
Before swapping the values in main [000000A6B03BF834]a = 10, [000000A6B03BF854]b = 20
After swapping values in function(using call by value) [000000A6B03BF800]a = 20, [000000A6B03BF808]b = 10
After swapping values in main(using call by value) [000000A6B03BF834]a = 10, [000000A6B03BF854]b = 20
After swapping values in function(using call by reference) [000000A6B03BF834]a = 20, [000000A6B03BF854]b = 10
After swapping values in main(using call by reference) [000000A6B03BF834]a = 20, [000000A6B03BF854]b = 10
As you can notice, the variables used in swapref() present the same addresses as the ones that are passed to the function.
As you can see by the output of your program:
After swapping values in function(using call by value) a = 20, b = 10
After swapping values in main(using call by value) a = 10, b = 20
After swapping values in function(using call by reference) a = 20, b = 10
After swapping values in main(using call by reference) a = 20, b = 10
The variables are not actually swapped. Whenever passing a something as a parameter, its value is copied into the argument.
void by_val(int i) {
i = 2;
// the variable i in main will NOT be changed,
// because this one is a copy
}
void by_ptr(int* i) {
// This will change the i in main, because we didn't copy its value,
// but copied the memory address of i variable in main.
*i = 2;
// Now we can make i point to an other variable than the main function i.
// This will not update i, but it will update num.
int num = 2;
i = &num;
*i = 3;
}
int main() {
int i = 1;
by_val(i);
printf("%d\n", i); // "1"
by_ptr(&i);
printf("%d\n", i); // "2"
}
So in your first swap function, the values of the copies of (main) a and b are being swapped, not the values of (main) a and b. But in your second function, the values of (main) a and b are swapped, because you passed the memory addresses of the (main). The * operator makes the program use the values in the variables, the memory address is pointing to.
It doesn't help that you're using the same names for different things. For the purpose of this answer, we're going to assume the variables in main are named x and y instead:
int main( void )
{
int x = 10, y = 20;
...
swap(x, y);
...
swapref(&x, &y);
...
}
That will make the following discussion easier to follow.
The formal parameters a and b in swap are different objects in memory from the local variables x and y in main.
When you call
swap(x, y);
in main, the expressions x and y are fully evaluated and the results of those evaluations (10 and 20, respectively) are passed to swap and copied into its formal arguments.
Since a and b are different objects from x and y, exchanging the values of a and b has no effect on the values of x and y.
Just like with swap, the formal parameters a and b in swapref are different objects in memory from the local variables x and y. When you call
swapref(&x, &y);
the expressions &x and &y are fully evaluated, and the results of those evaluations (the addresses of x and y) are passed to swapref and copied into the formal arguments a and b.
This means the following relationships are true:
a == &x // int * == int *
*a == x // int == int
b == &y // int * == int *
*b == y // int == int
Again, since a and b in swapref are different objects in memory from x and y in main, changing the values of a and b in swapref has no effect on x and y. However, when you write new values to the expressions *a and *b in swapref, you're not changing the values of a and b but rather what a and b point to, which in this case is x and y.
You can kinda-sorta think of *a and *b as aliases for x and y - they're alternate names for the same objects. Writing
temp = *a;
*a = *b;
*b = temp;
is equivalent to writing
temp = x;
x = y;
y = temp;

use pointer, but An error occurs(terminated with exit code: 3221225477)

Using pointers, GCD and LCM are solved using a single function and pointer. I'm not used to pointers yet. Anyway, I wrote the code below. However, errors such as terminated with exit code: 3221225477 continue to appear. According to a search on the Internet, the exit code above is due to incorrect memory references. But I don't know which part is wrong.
#include <stdio.h>
void gcdlcm(int a, int b, int* p_gcd, int* p_lcm){
int tmp, n, result_gcd, result_lcm;
int gcd_a, gcd_b;
p_gcd = &result_gcd;
p_lcm = &result_lcm;
if(a < b){
tmp = a;
a = b;
b = tmp;
}
gcd_a = a;
gcd_b = b;
if(gcd_b == 0){
result_gcd = 0;
}
while (gcd_b != 0)
{
n = gcd_a % gcd_b;
gcd_a = gcd_b;
gcd_b = n;
}
result_gcd = gcd_a;
printf("result_gcd = %d\n", result_gcd);
result_lcm = a * b / result_gcd;
printf("result_lcm = %d\n", result_lcm);
}
int main(){
int x, y;
int *p_gcd, *p_lcm;
scanf("%d %d", &x, &y);
gcdlcm(x, y, p_gcd, p_lcm);
printf("%d %d", *p_gcd, *p_lcm);
return 0;
}
Here:
p_gcd = &result_gcd;
you change the local variable p_gcd. This wil not affect the p_gcd in main, which after returning from gcdlcm has the same undefined value as before. Dereferencing it leads to your exception.
I you want to pass arguments as pointers so that your function can fill in the correct data, you must create variables to hold the data, then pass pointers to them with the address-of operator &:
int gcd, lcm;
scanf("%d %d", &x, &y);
gcdlcm(x, y, &gcd, &lcm);
(By the way, that's exactly the same how the scanf function one line above your call works.)
In your function, assign the result to what the pointer points to:
*p_gcd = gcd_a;
This modifies the variable gcd in main via the pointer p_gcd. Now, after returning from gcdlcm, gcd has the desired value.
the error is in this line printf("%d %d", *p_gcd, *p_lcm);. and the reason is that both will point to some random data.
This happens because your function will copy these values. p_gcd and p_lcm from your function are copies of the values in main. so when you set them, just the copies are modified to point to the variable, not the actual values. you should add a & or another * there, but even doing that will give you an error. because you try to return addresses of result_gcd and result_lcm which are local to your function.. and their addresses are invalid after the function ends
the best way around this would be (in my opinion) to return both values in a struct:
struct Result {
int gdc;
int lcm
};
struct Result gcdlcm(int a, int b){
//...
struct Result r;
r.gdc = result_gcd;
r.lcm = result_lcm;
return r;
}
if you dont like the solution, you can use pass pointers to variables in main and set them up in the function:
void gcdlcm(int a, int b, int* p_gcd, int* p_lcm){
int tmp, n, result_gcd, result_lcm;
int gcd_a, gcd_b;
if(a < b){
tmp = a;
a = b;
b = tmp;
}
gcd_a = a;
gcd_b = b;
if(gcd_b == 0){
result_gcd = 0;
}
while (gcd_b != 0)
{
n = gcd_a % gcd_b;
gcd_a = gcd_b;
gcd_b = n;
}
result_gcd = gcd_a;
printf("result_gcd = %d\n", result_gcd);
result_lcm = a * b / result_gcd;
printf("result_lcm = %d\n", result_lcm);
*p_gcd = result_gcd;
*p_lcm = result_lcm;
}
int main(){
int x, y;
int p_gcd, p_lcm;
scanf("%d %d", &x, &y);
gcdlcm(x, y, &p_gcd, &p_lcm);
printf("%d %d", p_gcd, p_lcm);
return 0;
}
You declared uninitialized pointers:
int *p_gcd, *p_lcm;
that have indeterminate values.
These pointers are passed by you to a function by value:
gcdlcm(x, y, p_gcd, p_lcm);
That is the function deals with copies of the values of the pointers p_gcd and p_lcm. So changing the copies do not affect the original pointers.
As a result dereferencing these initializing pointers in the statement:
printf("%d %d", *p_gcd, *p_lcm);
results in undefined behavior.
If you want to change the original pointers in the function you need to pass them by reference.
In C passing by reference means passing objects indirectly through pointers to them. So dereferencing the pointers you will get a direct access to the objects.
For example:
void gcdlcm(int a, int b, int **p_gcd, int **p_lcm){
int tmp, n, result_gcd, result_lcm;
int gcd_a, gcd_b;
*p_gcd = &result_gcd;
*p_lcm = &result_lcm;
//...
and in main:
gcdlcm(x, y, &p_gcd, &p_lcm);

Both call by value and call by reference work?

I thought that calling function by value will never work, and I should always use call by reference, but trying this code...
// call by value
#include<stdio.h>
int Add(int a, int b)
{
int c = a + b ;
return c ;
}
int main()
{
int x = 2 , y = 4 ;
int z = Add(x,y);
printf("%d\n",z);
}
output will be: 6
it works fine in both ways (call by value & call by reference),
// call by reference
#include<stdio.h>
int Add(int* a, int* b)
{
int c = *a + *b ;
return c ;
}
int main()
{
int x = 2 , y = 4 ;
int z = Add(&x,&y);
printf("%d\n",z);
}
output will be: 6
not like the famous swap function example - when calling by value it doesn't swap -
// call by value
#include <stdio.h>
void swap(int a, int b)
{
int temp;
temp = b;
b = a;
a = temp;
}
int main()
{
int x = 1 , y = 2;
printf("x = %d , y = %d\n", x,y);
swap(x, y);
printf("after swapping\n");
printf("x = %d , y = %d\n", x,y);
return 0;
}
.. it only worked calling by reference
// call by reference
#include <stdio.h>
void swap(int *a, int *b)
{
int temp;
temp = *b;
*b = *a;
*a = temp;
}
int main()
{
int x = 1 , y = 2;
printf("x = %d , y = %d\n", x,y);
swap(&x, &y);
printf("after swapping\n");
printf("x = %d , y = %d\n", x,y);
return 0;
}
So How can I judge if "calling by value" going to work or not ?!
So How can I judge that call by value method is valid or not ?!
Well, it depends on what your function is about to do.
In your above example, you only need the values of (x,y) for computing, but you never plan to change their value during your function. While call-by-reference will work in this case, it is unneccessary.
In the other (indirectly given) example you obviously want to change two variable's content (that is - swap it). You can access these variables from the main-function in your Swap-function, but how can you make the change persistent? That's only possible by call-by-reference, because you have to write the changed content into a variable that survives the function.
The following will not work:
// call by value
#include<stdio.h>
void Swap(int a, int b)
{
int c = a;
a = b;
b = c;
// from here on a, b, c will be destroyed
// therefore the change cannot be seen outside the function
}
int main()
{
int x = 2 , y = 4 ;
Swap(x,y);
printf("x: %d --- y: %d\n",x,y);
}
So as a rule to keep in mind:
If you want to make a change that's supposed to survive the function's end, use call-by-reference. If you just work with some data but do not want to (or must not) change their value, use call-by-value.

Why the same variable print the different output?

#include <stdlib.h>
#include <stdio.h>
void roll_three(int* one, int* two, int* three)
{
int x,y,z;
x = rand()%6+1;
y = rand()%6+1;
z = rand()%6+1;
one = &x;
two = &y;
three = &z;
printf("%d %d %d\n", *one,*two,*three);
}
int main()
{
int seed;
printf("Enter Seed: ");
scanf("%d", &seed);
srand(seed);
int x,y,z;
roll_three(&x,&y,&z);
printf("pai: %d %d %d\n", x,y,z);
if((x==y)&&(y==z))
printf("%d %d %d Triple!\n",x,y,z);
else if((x==y)||(y==z)||(x==z))
printf("%d %d %d Double!\n",x,y,z);
else
printf("%d %d %d\n",x,y,z);
return 0;
}
This the terminal, I type 123 for the seed. However, the printf in roll_three and the printf in main give me different output? Why *one and x are different?
The problem is here:
one = &x;
two = &y;
three = &z;
Since one, two, and three are pointers you've changed what they point to, but now they no longer point to main's x, y and z. It is similar to this...
void foo(int input) {
input = 6;
}
int num = 10;
foo(num);
printf("%d\n", num); // it will be 10, not 6.
Instead you want to change the value stored in the memory they point to. So dereference them and assign them the new value.
*one = x;
*two = y;
*three = z;
You can even eliminate the intermediate values.
*one = rand()%6+1;
*two = rand()%6+1;
*three = rand()%6+1;
In roll_three, you need to change the following:
one = &x;
two = &y;
three = &z;
To:
*one = x;
*two = y;
*three = z;
The first version just points to them to the local variables. The corrected version updates the values in the caller.
Why *one and x are different?
one = &x;
should be
*one = x;
The way you did it ( one = &x ) is wrong, because you assign pointer one to the address of local variable x which no longer exists after function roll_three.
You function should look like this:
void roll_three(int* one, int* two, int* three)
{
int x,y,z;
x = rand()%6+1;
y = rand()%6+1;
z = rand()%6+1;
*one = x;
*two = y;
*three = z;
printf("%d %d %d\n", *one,*two,*three);
}
In your roll_three function,
void roll_three(int* one, int* two, int* three)
{
int x,y,z;
x = rand()%6+1; // local variable x will have a value
y = rand()%6+1;
z = rand()%6+1;
one = &x; // variable one is assigned with local variable x's address
// so *one equals to x inside the function.
// However, variable one supposed is the variable x's address in
// the main function, but now it is changed to the local x's address,
// the main function variable x's value can't be updated as expected.
// *one = x is the way you want to go.
two = &y;
three = &z;
printf("%d %d %d\n", *one,*two,*three);
}

Using pointers in C programming?

Right now I'm working on a program in C that takes 3 parameters; the address of a "first" integer, address of the "second" integer and the address in which to store the maximum of the two integers. So far I have the following basic code:
void max(int* x, int* y, int* z)
{
if (x > y) {
z = x;
}
else if (y > x){
z = y;
}
}
int main()
{
int x = 6;
int y = 4;
int z;
max(&x, &y, &z);
printf("max of %d and %d = %d\n", x, y, z);
x = 12;
y = 17;
max(&x, &y, &x);
printf("x = %d, y = %d\n", x, y);
}
When executed it outputs the following:
max of 6 and 4 = 32767
x = 12, y = 17
HOWEVER! I want it to output this instead:
max of 6 and 4 = 6
x = 17, y = 17
I'm not sure where I'm going wrong in my max function. Z should not be so huge and in the second print statement x should equal y. Any help is greatly appreciated, thanks!
As you probably already know, a pointer is a variable which contains the address in memory of another variable.
To access that memory we use The Unary operator & which gives us the address of a variable.
But accessing that memory is not all what a Pointer can do, we can with that pointer modify the value of that variable where the pointer points to.
For that we need to supply * to that pointer like this *ptr.
Let's take a look at the following program:
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
int main(void){
int a = 5;
int b = 10;
printf("A = %d\nB = %d\n\n\n",a,b);
int *pa = &a;
int *pb = &b;
*pa = 50;
*pb = 100;
printf("A = %d\nB = %d\n*PA = %d\n*PB = %d\n",a,b,*pa,*pb);
return 0;
}
The output will be:
A = 5
B = 10
A = 50
B = 100
*PA = 50
*PB = 100
As you can see A and B got new values. I hope you understand that.
when you pass things by pointer, if you want to get to the values, you need to do
(*x > *y)
Which gets the value pointed at by the pointer. (x and y are pointers, so they are going to contain memory addresses of the where the values are stored)
Needs to be:
if (*x > *y) {
*z = *x;
}
else if (*y > *x){
*z = *y;
}
You are comparing pointer addresses. You should de-reference the pointers for comparisons and assignments.
void max(int* x, int* y, int* z)
{
if (*x > *y) {
*z = *x;
}
else if (*y > *x){
*z = *y;
}
}

Resources