Pass by value and pointers - c

Can you explain why the output is 3?
I was trying to trace the answer and it shows that the line
i+=(a==b?1:0)
gives 1, but doesn't fun1() pass by value so q and p were copied to different variables?
int fun1(int* a, int* b)
{
int i = 0;
i += (&a == &b ? 1 : 0);
i += (a == b ? 1 : 0);
i += (*a == *b ? 1 : 0);
return i;
}
int fun2(int** a, int* b)
{
int i = 0;
i += (a == &b ? 1 : 0);
i += (*a == b ? 1 : 0);
return i;
}
int main(void)
{
int i = 0;
int* p = &i;
int* q = &i;
printf("%d\n", fun1(p, q) + fun2(&p, q));
return 0;
}

In fun1:
(&a==&b?1:0)
This gives 0. They are two different arguments to fun1, basically two different local variables, so they cannot have the same address.
(a==b?1:0)
This gives 1. The values are both &i from main.
(*a==*b?1:0)
This gives 1. Since a and b are equal, they point to the same thing.
In fun2:
(a==&b?1:0)
This gives 0. a and b are both arguments, so a can't equal the address of b (and in fact, it equals &p from main).
(*a==b?1:0)
This gives 1. a is equal to &p from main, so *a is equal to p from main, which is &i from main. And b is equal to q from main, which is again &i from main.
The total is therefore 3.

int fun1(int *a, int*b)
{
int i=0;
i+=(&a==&b?1:0); // 0. &a is the memory where a stands. it's different from &b.
i+=(a==b?1:0); // 1. Both pointers point to the same memory.
i+=(*a==*b?1:0); // 1. *a is the value where it points to, and that's the same as *b.
return i; // returns 2
}
int fun2(int **a, int*b)
{
int i=0;
i+=(a==&b?1:0); // 0
i+=(*a==b?1:0); // 1. *a is the value where it points to, and this is a memory value that is the same as b.
return i; // returns 1
}
That's why it returns 3.
Good question, by the way.

a==b is actually testing whether a and b points to same memory location or not. In function fun1, both a and b points to the same memory location and therefore a==b comes out to be true.

Let's consider at first the first function
int fun1(int *a, int*b)
{
int i=0;
i+=(&a==&b?1:0);
i+=(a==b?1:0);
i+=(*a==*b?1:0);
return i;
}
It was called like
fun1(p,q)
where the both pointers point to the same variable
int *p=&i;
int *q=&i;
So the function got two equal values as its argument. It is the address of variable i.
Function parameters are its local variable. You can imagine the called function like
int fun1( /*int *a, int*b */)
{
int *a = p;
int *b = q;
//...
}
These local variables occupies different extents of memory. So &a is not equal to &b.
As result the value of expression (&a==&b?1:0) will be equal to 0 and variable i in the statement below
i+=(&a==&b?1:0);
will not be changed
The values stored in variables a and b id the address of variable i in main. As it was said early the two variables contain the same value.
So expression (a==b?1:0) will yield 1 and variable i in the statement below
i+=(a==b?1:0);
will be increased.
As the both pointers points to the same object then expression (*a==*b?1:0) also will yield 1. As result variable i will be increased/
i+=(*a==*b?1:0);
The function will return value 2.
Now let's consider the second function
int fun2(int **a, int*b)
{
int i=0;
i+=(a==&b?1:0);
i+=(*a==b?1:0);
return i;
}
As it was said above parameter b is a local variable of the function. Its address does not equal to the address of argument p
So expression (a==&b?1:0) yields 0.
Expression *a is the value stored in argument p The same value is stored in parameter b
So expression (*a==b?1:0) yields 1.
In total the sum of the return values of the functions will be equal to 3.

Related

Scope of a pointer in memory

I have been studying C for the past weeks, but I can't fully understand how memory manages pointers.
My question arises from this example obtained from here(page 17 of 19): C-Pointer-Basics
Example code:
#include <stdio.h>
void F(int, int *);
int main()
{
int m = 3;
int n = 5;
F(m, &n);
printf("main: %d, %d\n", m, n); // print 3 7 (Where does the 7 came from?)
return 0;
}
void F(int a, int *b)
{
/*
* `a` being a local variable, gets cleaned after `F()` ends
* BUT how does `b` retain the value of `&a`?
*/
a = 7;
*b = a; // `*b = 7`
b = &a; // `b` points to `a`
*b = 4; // `a = 4` and why `*b` doesn't return 4?
printf("F: %d, %d\n", a, *b); // print 4 4
}
The question here is:
Why when main() prints the values of m and n, It showsm = 3 and n = 7?
My assumptions:
As I know, a pointer goes beyond the scope of the function where it is declared, so in void F(int a, int *b) when the function is no longer needed, it gets destroyed, same with his parameters, BUT the value of int *b remains in memory right(even though int *b no longer exists)? So if this is true, we can 'recover' it from memory and use it in main().
Best,
For the question why m and n print 3,7 is because the first parameter is passed by value hence it is only getting copied, therefore no modification of the original m is happening and in the case of n, you're passing its address so when you do *b=a the value of a gets copied to n. And then when you do b=&a the pointer b now starts pointing to the address of a instead of that of n. Which is why the second time you do *b=4, you are not modifying n but a.

Understanding pointers & memory address

#include<stdio.h>
int g(int *a, int *b);
int main()
{
int a = 2;
int b = 7;
b = g(&b , &a);
printf("a = %d\n", a);
printf("b = %d\n", b);
return 0;
}
int g(int *a, int *b)
{
(*a) = (*a) + 3;
(*b) = 2*(*a) - (*b)+5;
printf("a = %d, b = %d\n", *a, *b);
return (*a)+(*b);
}
The output is:
a = 10, b = 23
a = 23
b = 33
I'm in an Intro to C programming class and having trouble understanding how this works.
Thanks for the help!
Sequencing the events as presented in question:
int main()
{
Declaration of a and b and value assignment:
int a = 2;
int b = 7;
Here is a trick, the address passed to the parameter int* a is actually of b, and vice-versa on the second parameter:
b = g(&b , &a);
Here just printing values of a and b:
printf("a = %d\n", a);
printf("b = %d\n", b);
return 0;
}
Since the parameters are pointers, the changes made, in the scope of this function, to the variable addresses pointed by them are permanent:
int g(int *a, int *b) {
Here, dereferencing the pointer (*a, the parentheses are not needed in these cases), means you are now working with the value stored in the address pointed by a, so 7 + 3 = 10, now the value stored in the address pointed by a is = 10:
(*a) = (*a) + 3;
Here, the same thing, dereferencing pointers, so 2 * 10 - 2 + 5 = 23, the value stored in the address pointed by b will be 23:
(*b) = 2*(*a) - (*b)+5;
Here printing a = 10 and b = 23, again, dereferencing pointers means you are working with the values stored in the addresses pointed by them:
printf("a = %d, b = %d\n", *a, *b);
The returned value is 10 + 23 = 33, so for b = g(&b, &a), b will be assigned the value of 33, a is already 23 so it stays that way:
return (*a)+(*b);
}
Remember that C passes all function arguments by value - that means that the formal parameter in the function body is a separate object in memory from the actual parameter in the function call, and the value of the actual parameter is copied to the formal parameter.
For any function to modify the value of a parameter, you must pass a pointer to that parameter:
void foo( T *ptr ) // for any type T
{
*ptr = new_T_value(); // write a new value to the thing ptr points to
}
void bar( void )
{
T var;
foo( &var ); // write a new value to var
}
In the code above, all of the following are true:
ptr == &var
*ptr == var
Thus, when you write a new value to the expression *ptr, it's the same as writing a new value to var.
I think part of what's making this confusing for you is that the names of your formal parameters (a and b) and your pointers (a and b) are flipped - g:a points to main:b and vice versa.
g:a == &main:b // I'm using g: and main: here strictly to disambiguate
*g:a == main:b // which a and b I'm talking about - this is not based on
// any real C syntax.
g:b == &main:a
*g:b == main:a
With & you give the address of the variable to the function, instead of the value.
With * you can access the value of an address.
With b = g(&b , &a); you give the address of the variable b and a to the function.
But you can access the address of b with * a because you declare the function that way: int g (int * a, int * b):
*a points to the address of your b variable.
*b points to the address of your a variable.
I think the different variable names are what confuses you.
To make it easier for yourself you could change the declaration to int g (int * b, int * a)
In case you want to change it:
*b would point to the address of your b variable and
*a would point to the address of your a variable.
by using the * you access the object referenced by the pointer. As the pointers are referencing int variables a & b you do the operations on those variables. I think the same variable names are confusing you
int g(int *p1, int *p2)
{
(*p1) = (*p1) + 3;
(*p2) = 2*(*p1) - (*p2)+5;
printf("*p1 = %d, *p2 = %d\n", *p1, *p2);
return (*p1)+(*p2);
}

Swapping two integers using pointers using c

I am trying to swap the value of two integers using pointers, see code below: swapping number using pointer in c:
{
int a = 10;
int b = 20;
swapr(&a, &b);
printf("a=%d\n", a);
printf("b=%d\n", b);
return 0;
}
void swapr(int *x, int *y) //function
{
int t;
t=*x;
*x=*y;
*y=t;
}
In the code why is swap(&A, &B); used when *x and *y point to a value not an address
When you say (int *x, int *y) you're just declaring x and y as pointers. In all future usages, when you say x, it means the pointer and when you say *x, it means the value it points to.
In a declaration, the * in the declarator indicates that the object has pointer type. Take the declaration
int *p;
The type of p is "pointer to int". This type is specified by the combination of the type specifier int and the declarator *p.
Pointer-ness, array-ness, and function-ness are all specified as part of the declarator:
T *p; // p is a pointer to T
T a[N]; // a is an N-element array of T
T f(); // f is a function returning T
T *ap[N]; // ap is an array of pointers to T
T (*pa)[N]; // pa is a pointer to an array of T
T *fp(); // fp is a function returning pointer to T
T (*pf)(); // pf is a pointer to a function returning T
etc.
In C, declaration mimics use - if you have a pointer to an int named p and you want to access the value it points to, you dereference it with the * operator, like so:
x = *p;
The expression *p has type int, so the declaration of p is
int *p;
In main, the expressions &a and &b have type int *, so the corresponding parameters have to be declared as int *.
x == &a // int * == int *
y == &b // int * == int *
*x == a // int == int
*y == b // int == int
Basically the way var declarations work is if you declare a variable
int c;
You've just declared an integer and you can assign values to it or retrieve its value like this
int a;
int b;
a = 10; // assign 10
b = a; //assign value of a to b
Pointers are a bit different though. If you declare a pointer and you want to assign a value to it then you must dereference it with the * operator
int * a; // declare a pointer
int b; // declare a var
b = 10; // assign 10 to b
*a = b; // assign 10 as the value of a
b = 20; // b is now 20 but the var a remains 10
But you can also assign a pointer to point at a memory address
int * a;
int b;
b = 10; // assign 10 to b
a = &b; // assign address of b to a (a points at b)
b = 20; // value of b changes (thus value of a is also 20 since it is pointing at b
So if you have a function signature
int func (int * a, int * b);
All this is means is that the function takes the address of two variable
int a;
int b;
int * x;
int * y;
func(&a, &b); // send it the address of a and b
func(x, y); // send it the address of x and y
func(x, &b);
Basically a normal var's address can be accessed with the & operator.

Pointing to a local variable

I would like help understanding this code:
void F (int a, int *b)
{
a = 7 ;
*b = a ;
*b = 4 ;
printf("%d, %d\n", a, *b);
b = &a ;
}
int main()
{
int m = 3, n = 5;
F(m, &n) ;
printf("%d, %d\n", m, n) ;
return 0;
}
I am confused why this does not result in unexpected behavior. At the end of the function F, the value of b is 7. But when I return it is clear that nothing after ' b = &a ' impacts the value of n/b.
I thought that pointing to a local variable would result in garbage/unexpected behavior when the scope changed, but that doesn't appear to be the case.
When you call F, you pass the value of m and the address of n.
In F, b is a pointer to n so that when you change the value of *b, the value of n is changed. However, in "b = &a;" you are changing where b points. After that line, b no longer points to n. Instead, it points to a. That line does nothing at all to the variable n back in main(). After that point, if you change the value of *b, you will change the value of *b and its alias, a. It will not change the value of n in main.
At the end of the function F, the value of b is 7
The value of b is not 7; b is set to point to a, which has the value of 7
But when I return it is clear that nothing after b = &a impacts the value of n
Although b is a pointer, it is passed by value. b inside F behaves as if it were a separate, fully independent, local variable. Any modifications to it made inside F are local to F.
In fact, you cannot trigger undefined behavior in main by actions inside F, because main is not receiving any pointers from F. If you want to make undefined behavior, pass a pointer to pointer into F, and assign it to point to a local variable:
void CauseUB(int a, int **b) {
*b = &a;
}
int main() {
int x = 5, *y = &x;
printf("This is OK: %d\n", *y);
CauseUB(x, &y); // Pointer to pointer
printf("This is UB: %d\n", *y);
return 0;
}
Demo.

Pointer as a parameter in C

Let's say a have a pointer as a parameter, why doesn't it's value remain modified after the and of a function, and i have to use this syntax :
void function_name (int **p)
{
// code
}
and in main() :
int *v;
function name (&v);
I want to specify that i use a pointer to a struct type as a parameter.
C passes arguments by value. If you want to modify something in a function and make the modification take effect in the calling function, a pointer to the variable in the calling function has to be passed. Otherwise, any changes made to the variable in a function are only local changes and does not affect the value of the variable in the calling function.
Let's start with an int type variable.
void foo(int x)
{
x = 10;
}
int main()
{
int a = 100;
foo(a); // Value of a does not change in this function
}
In the above program, the value of a remains 100 in main. The line
x = 10;
in foo only affects the value of the variable in foo. To make the change in foo affect the value in main, you'll need to pass a pointer to a.
void foo(int* x)
{
*x = 10;
}
int main()
{
int a = 100;
foo(&a); // Value of a changes in this function
}
Take that analogy to a pointer.
void bar(int* x)
{
x = malloc(10*sizeof(int));
}
int main()
{
int* ptr = NULL;
bar(ptr); // Value of ptr does not change in this function
}
bar allocates memory for an array of 10 ints and assigns the memory to x but that change is local. main does not see it. In main, ptr is still NULL. To make the change in bar affect ptr, a pointer to ptr has to be passed to bar.
void bar(int** x)
{
*x = malloc(10*sizeof(int));
}
int main()
{
int* ptr = NULL;
bar(&ptr); // Value of ptr changes in this function
}
In C, arguments are passed by value. This means that when you pass an argument to a function, a copy of that variable is made. For example
int main()
{
int x = 6;
repchar(x, 'r');
printf("%d\n", x);
return 0;
}
void repchar(int n, char c)
{
while (--n >= 0)
putchar(c);
}
This program prints the letter r six times, and then at the last printf, prints out 6, not -1. The reason is that when repchar was called, x was copied. That way, when repchar decrements n, the caller's copy is not changed.
If we passed a pointer, however, n would be modified.
int main()
{
int x = 6;
repchar(&x, 'r');
printf("%d\n", x);
return 0;
}
void repchar(int *n, char c)
{
while (--(*n) >= 0)
putchar(c);
}
Instead of the variable being copied, now the address of the variable is being copied. Inside of repchar, *n is being counted down. This accesses the value that is being referenced by n, which is the same address as x and decrements it. As a result, the last printf will give -1.

Resources