Pointing to a local variable - c

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.

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;

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

Pass by value and pointers

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.

Why can't I swap memory address of two variables using a function? C

static void swapAddr(int *numOne, int *numTwo)
{
int *tmp;
tmp = numOne;
numOne = numTwo;
numTwo = tmp;
}
int main(void)
{
int a = 15;
int b = 10;
printf("a is: %d\n", a);
printf("Address of a: %p\n", &a);
printf("b is: %d\n", b);
printf("Address of b: %p\n", &b);
swapAddr(&a, &b);
printf("\n");
printf("a is: %d\n", a);
printf("Address of a: %p\n", &a);
printf("b is: %d\n", b);
printf("Address of b: %p\n", &b);
return 0;
}
When I compile and run this piece of code, the output is
a is: 15
Address of a: 0x7fff57f39b98
b is: 10
Address of b: 0x7fff57f39b94
a is: 15
Address of a: 0x7fff57f39b98
b is: 10
Address of b: 0x7fff57f39b94
Clearly the result is not what I intended, since the address does not seem to have been swapped at all.
You generally can't change the address of a variable.
Your 'swapAddr' function changes its parameter values, but these are local to the function - you're not changing anything outside the function. Perhaps the best way of understanding it is that a function parameter always receives a copy of the value that was passed to the function. In this case, you get a copy of the address of a and a copy of the address of b. You can and do change the values of the variables holding those copies (numOne and numTwo), and seeing as they are pointers you could (but don't) change the values that they point at (the values of variables a and b) - but you can't change the addresses of the original variables.
To break it down:
static void swapAddr(int *numOne, int *numTwo)
{
int *tmp;
tmp = numOne;
At this point, tmp and numOne both point to the value of the a variable...
numOne = numTwo;
Now, numOne points instead to the value of the b variable...
numTwo = tmp;
}
And finally, numTwo now points to the value of the a variable. The function returns and numOne and numTwo no longer exist after that point. The addresses of the variables a and b did not change at any stage.
You could however write a function which exchanges the addresses in two pointer variables:
static void swapAddr(int **ptrOne, int **ptrTwo)
{
int *tmp;
tmp = *ptrOne;
*ptrOne = *ptrTwo;
*ptrTwo = tmp;
}
This would allow you to pass the address of two pointer variables, and on return the pointers would be swapped - each one pointing at what the other did previously. But again, this would not change the address of any variable that those pointers happened to point to.
The pointers are passed to the function by value, so changing what they point to isn't going to change the value of the passed parameters in the calling function.
When the function is called, a copy of each pointer is made and saved to the stack. Then the function reads each pointer value off the stack and manipulates them. It never changes the value of the original pointer that was copied onto the stack.
Remember that in C values are passed by value to functions, meaning that the values are copied. When you modify an argument in a function you only modify the local copy inside the function, not the original value that was passed to the function. This goes for pointers as well.
To solve your problem you must pass the arguments by reference, but unfortunately C doesn't have that, it only have pass by value. However, pass by reference can be emulated by passing pointers to the data, just like you do in the function. You must however dereference the pointer to get the values from where the pointers point to, and use those values to do the actual swapping:
int temp = *numOne; // Note: temp is a value not a pointer
*numOne = *numTwo;
*numTwo = temp;
static void swapAddr(int *numOne, int *numTwo)
In this function you are passing 2 pointers by value. This allows you to modify the int pointed to by the pointers but not the pointers themselves.
Use this function definition instead that passes pointers to pointers and allows modifying the pointers themselves
static void swapAddr(int **numOne, int **numTwo) {
int *tmp = *numOne;
numOne = *numTwo;
numTwo = tmp;
}
You could use it like this for example:
int *a = malloc(sizeof(int));
int *b = malloc(sizeof(int));
*a = 15;
*b = 10;
swapAddr(&a, &b);
You canlt change the addresses. The adderss of a is the address of a and that will remain the same until the end of days.
You can do:
static void swapAddr(int **numOne, int **numTwo)
{
int *tmp;
tmp = *numOne;
*numOne = *numTwo;
*numTwo = tmp;
}
int main(void)
{
int a = 15;
int b = 10;
int *pa= &a;
int *pb= &b;
swapAddr(&pa, &pb);
}
What you want to achieve is something like
int *c = &a;
&a = &b;
&b = &a;
This is not possible (you can check: it will not compile). A variable that is created is placed at one place in memory and stays there. So when you create a variable a it will stay variable a and it will not be able to change its identity to that of another variable b.
What you can do is use two pointers int *p1, *p2 to int. These pointers can change their value and point to other objects during lifetime:
p1 = a;
p2 = b;
p1 = b;
p2 = a;
a and b will stay the same, but p1 and p2 can point to different objects over time.
So a thing that would be possible:
static void swapaddr(int **pp1, int **pp2)
{
int *pp;
pp = *pp1;
*pp1 = *pp2;
*pp2 = pp;
}
int main(void)
{
int a = 15, b = 10;
int *pA = &a, *pB = &b;
swapAddr(&pA, &pB);
}
In this example a and b would keep their identity and address, but pA and pB would change their value and pA would point to b and pB would point to pA.
You cannot change the addresses of the variables.however you can change values of pointers,which store addresses as their value,here is an example :
#include <stdio.h>
void swapAddr(int **numOne, int **numTwo)
{
int *tmp;
tmp = *numOne;
*numOne = *numTwo;
*numTwo = tmp;
}
int main(void)
{
int a = 15;
int b = 10;
int *p_a = &a;
int *p_b = &b;
printf("Address of a: %p\n", p_a);
printf("Address of b: %p\n", p_b);
swapAddr(&p_a,&p_b);
printf("\n");
printf("p_a : %p\n",p_a);
printf("p_b : %p\n",p_b);
return 0;
}

Resources