Updating pointers in a function - c

I am passing a pointer a function that updates it. However when the function returns the pointer it returns to the value it had prior to the function call.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
static void func(char *pSrc) {
int x;
for ( x = 0; x < 10; x++ ) {
*pSrc++;
}
printf("Pointer Within Function: %p\n", pSrc );
}
int main(void) {
char *pSrc = "Good morning Dr. Chandra. This is Hal. I am ready for my first lesson.";
printf("Pointer Value Before Function: %p\n", pSrc );
func(pSrc);
printf("Pointer Value After Function: %p\n", pSrc );
return EXIT_SUCCESS;
}
Here is the output
Pointer Value Before Function: 0x100403050
Pointer Within Function: 0x10040305a
Pointer Value After Function: 0x100403050
What I was expecting was the value after the function to match the one from within the function.
I tried switching to char **pSrc but that did not have the desired affect.
I am sure the answer is fairly simple, but I am a recovering hardware engineer and can't seem to figure it out :-)

The pointer inside the function is a copy of the passed pointer.
They both hold the same address but have different addresses, so changing the address held by one of them doesn't affect the other.
If you want to increment the pointer inside the function pass it's address instead, like this
static void func(char **pSrc) {
int x;
for ( x = 0; x < 10; x++ ) {
(*pSrc)++;
}
printf("Pointer Within Function: %p\n", pSrc );
}
and
func(&pSrc);
Also, be careful not to modify the contents, because your pointer points to a string literal, and string literals cannot be modified.

When you give a pointer to a function, you have a copy of the reference value that you originally had.
Then, if you modify your pointer, you're modifying a copy.
If you want to update the original one, you need to pass it with a double pointer ** which will let you modify the original pointer, passing a "reference to a reference" (double pointer).

C uses pass-by-value for function parameter passing. The value of pSrc is just a copy of the pSrc present in main(), not the same entity as the pSrc from main(). That is why, any changes made to pSrc inside the function func()won't be reflected in main() (caller function).
However, all the changes to *pSrc will sustain.
Solution: To change the pSrc of main() from func(), you need to pass a pointer to pSrc (pointer to a pointer) from main() and adjust the data types accordingly. Also, in that case, please note, the pSrc should be modifiable (present in read-write memory). As it is currently written, the pSrc in main() is not modifiable.

C is passing parameters by value, so it makes a copy of pSrc inside your function, and all the changes you've made are applied to a copy of pSrc. If you want to change the value of pSrc, then you should pass a pointer to pSrc, like this:
static void func(char **pSrc){ // pointer to char*
int x;
for (x = 0; x < 10; x++)
(*pSrc)++
}

You call func by passing pSrc. You think you are passing the same variable - That is func will operate on the same memory location when it alters pSrc. This is false.
func gets a copy of pSrc. The stack frame built in calling func will have its own pSrc. What is modified is its version not the calling function's.
To let func operate on the actual variable in main you got to pass address of pSrc - &pSrc.
Relevant concepts - Pass by Value and Pass by Reference.

Related

Double Pointers in C and their scope

I have this code:
void alloc2(int** p) {
*p = (int*)malloc(sizeof(int));
**p = 10;
}
void alloc1(int* p) {
p = (int*)malloc(sizeof(int));
*p = 10;
}
int main(){
int *p;
alloc1(p);
//printf("%d ",*p);//value is undefined
alloc2(&p);
printf("%d ",*p);//will print 10
free(p);
return 0;
}
So, I understand that alloc1 just makes a local copy so it's not effecting outside the function the pointer which is given as a parameter.
But what is happening with alloc2?
tl;dr;
And why this alloc1(&p); won't work?
Update
I think i answered my question. The crucial thing is that & makes you a pointer and then a was built to a double pointer bei dereferencing once. Then the double pointer points to the address given be malloc. Finally the address was filled with 10.
And alloc1(&p); would work, but you couldn't derefence the double pointer since it takes a single pointer.
Thanks to all of you
It didn't become a double pointer, in alloc2() you are passing a pointer containing the address of main()'s p. When you dereference it you are actually modifying the address stored in main()'s p. And that's why it's working.
Since there is no pass by reference in c, the only way you can modify a parameter inside a function is by passing a pointer with it's address, for example if you have to pass an integer to a function and the function needs to modify it then you make a pointer using the address of & operator and pass that pointer to the function, example
void
modify(int *pointer)
{
*pointer += 1;
}
int
main(void)
{
int value;
value = 0;
modify(&value);
printf("%d\n", value);
modify(&value);
printf("%d\n", value);
}
would output
1
2
A double pointer is a pointer to a pointer, so you are making a pointer from p in main() which stores the address of p in main(), the pointer itself is stored somewhere, so you are passing the address where the pointer is stored and hence you can modify it's contents from within alloc2().
Note: It's bad style to cast the return valud of malloc(), read more about it here.
It would be clearer if you gave the variables in different functions different names. Since you have multiple variables and arguments named p, and they are distinct from each other, it is easy to confuse yourself.
void alloc2(int** pa2)
{
*pa2 = (int*)malloc(sizeof(int));
**pa2 = 10;
}
void alloc1(int* pa1)
{
pa1 = (int*)malloc(sizeof(int));
*pa1 = 10;
}
int main()
{
int *p = 0;
alloc1(p);
//printf("%d ",*p);//value is undefined
alloc2(&p);
printf("%d ",*p);//will print 10
free(p);
return 0;
}
Apart from renaming the arguments of functions, I've also initialised p in main() to zero (the NULL pointer). You had it uninitialised, which means that even accessing its value (to pass it to alloc1()) gives undefined behaviour.
With p being NULL, alloc1() also receives the NULL pointer as the value of pa1. This is a local copy of the value of p from main(). The malloc() call then changes the value of pa1 (and has no effect on p in main(), since it is a different variable). The statement *pa1 = 10 sets the malloced int to be 10. Since pa1 is local to alloc1() it ceases to exist when alloc1() returns. The memory returned by malloc() is not free()d though (pa1 ceases to exist, but what it points to doesn't) so the result is a memory leak. When control passes back to main(), the value of p is still zero (NULL).
The call of alloc2() is different, since main() passes the address of p. That is the value of pa2 in alloc2(). The *pa2 = (int *)malloc(sizeof(int)) statement does change the value of p in main() - to be the value returned by malloc(). The statement **pa2 = 10 then changes that dynamically allocated int to be 10.
Note also that the (int *) on the result of malloc() is unnecessary in C. If you need it, it means one of
You have not done #include <stdlib.h>. The type conversion forces the code to compile, but any usage of the int - strictly speaking - gives undefined behaviour. If this is the case, remove the int * and add #include <stdlib.h>.
You are compiling your C code using a C++ compiler.

Passing address, but it is working like call by value in C?

Hello I am a beginner in C programming language. Recently I read about call by value and call by address. I have learned that in call by address changes in the called functions reflects the callee. However the following code does not work like that.
int x = 10,y = 20;
void change_by_add(int *ptr) {
ptr = &y;
printf("\n Inside change_by_add\t %d",*ptr);
// here *ptr is printing 20
}
void main(){
int *p;
p = &x;
change_by_add(p);
printf("\nInside main\t %d", *p);
// here *p is still pointing to address of x and printing 10
}
When I am passing address then why the changes made by called function does not reflect caller?
The function is assigning a new address to the pointer but the pointer itself is being passed by value, as all arguments are in C. To change the value of a pointer variable the address of the pointer itself must be passed:
void change_by_add(int **ptr)
{
*ptr = &y;
}
change_by_add(&p);
See C FAQ Question 4.8.
Passing by reference does not exist in C but can be achieved by passing the address of the variable who's value is to be changed to a function. For example:
void add_to_int(int* a_value, int a_increment)
{
*a_value += a_increment;
}
You are simply setting the value of the pointer in the function, not the value of the pointed to variable. The function should use the following code:
*ptr = y;
This derefences the pointer (exposing the value pointed to), and therefore when you use the equals operator, the memory pointed at is modified, not the pointer itself. I hope this helps to clarify things.
Changes made by called function does not get reflected by the caller because you are overriding the pointer address in the called function i.e ptr = &y;.
Initially, you passed the address of x but you are changing it with the address of y.
If you really want to implement the concept of call by address then change value instead of address.
Example:
void change_by_add(int *ptr) {
*ptr = y; //changing value
printf("\nInside change_by_add\t %d",*ptr);
}
void main(){
int *p;
p = &x;
change_by_add(p);
printf("\nInside main\t %d \n", *p);
return 0;
}
Output
Inside change_by_add 20
Inside main 20
There is no such thing as call by address in C. There is only call by value. What one does when a function needs to modify an argument in a way that is visible to the caller is to have the caller pass a pointer to something, and have the called function write the update though that pointer. Note that the pointer itself is still sent as call-by-value - that is: the called function gets its own copy of the pointer and could change it to point to anything else if it wants to.

What is byValue and byReference argument passing In C? [duplicate]

This question already has answers here:
What's the difference between passing by reference vs. passing by value?
(18 answers)
Closed 9 years ago.
I dont understand what this means. If I were to try and guess I'd say byValue argument passing is when you pass an argument based on the value of an variable, so I'm thinking:
if (a == 1){
PassAnArgumentOrSomething()
}
However that is probably wrong :/
As for byReference, I have no idea.
If anyone can help me out that be awesome of you :)
With the exception of arrays and functions (see below), C always passes arguments `by value': a copy of the value of each argument is passed to the function; the function cannot modify the actual argument passed to it:
void foo(int j) {
j = 0; /* modifies the copy of the argument received by the function */
}
int main(void) {
int k=10;
foo(k);
/* k still equals 10 */
}
If you do want a function to modify its argument you can obtain the desired effect using pointer arguments instead:
void foo(int *j) {
*j = 0;
}
int main(void) {
int k=10;
foo(&k);
/* k now equals 0 */
}
This is sometimes known as `pass by reference' in other languages.
There is no pass by reference in c language
Passing by value: means that you are creating a temporary copy of the variable and sending to the parameter.
Passing by reference(no such concept in c language): means that you are just giving another name to the original variable while calling and no temporary copy of the variable is being created.
Calling by value:
int foo(int temp)
{
/.../
}
int main()
{
int x;
foo(x); /* here a temporary copy of the 'x' is created and sent to the foo function.*/
}
Calling by reference(no such concept in c language)
int foo(int& temp)
{
/.../
}
int main()
{
int x;
foo(x); /* here no temporary copy of 'x' is being created rather the variable *temp* in the calling function is just another name of the variable a in the main function*/
}
Passing an argument by value means you are passing a copy:
void f(int x)
{
x = 7;
// x is 7 here, but we only changed our local copy
}
void g()
{
int y = 3;
f(y);
// y is still 3 here!
}
Passing an argument by reference means you are not passing a copy, but instead passing some way of referencing the original variable. In C, all arguments are pass by value, but what is typically done to get the same effect as passing by reference is to pass a pointer:
void f(int *x_ptr) { *x_ptr = 7; }
void g()
{
int y = 3;
f(&y);
// y is 7 here
}
Arrays are passed in such a way that it appears similar to pass-by-reference, however what is actually happening is more complicated. For example:
void f(int a[]) { a[0] = 7; }
void g()
{
int b[3] = {1,2,3};
f(b);
// b[0] is 7 here! looks like it was passed by reference.
}
What is actually happening here is that the array b is implicitly converted to a pointer to the first element (this is known as decay). The int a[] notation for the parameter to f is actually syntactic sugar for a pointer. The above code is equivalent to:
void f(int *a) { a[0] = 7; }
void g()
{
int b[3] = {1,2,3};
f(&b[0]);
// b[0] is 7 here
}
Passing by value is passing the value itself; it makes a copy of the value, and any changes you make in the new function are NOT saved to the original variable:
void foo(int num)
{
num = 5; // Does not save to the original variable that was passed when foo was called
...
}
Passing by reference is passing the location of the variable; it allows the new function to directly edit the original variable:
void bar(int * num)
{
*num = 5; // Changes the variable in the original function
...
}
in-depth explanation
whenever a program loads, it gets a memory area so called address space which gets divided into various regions
code/text : contains the statements of program (collections of statements).
global : contains the global variable if any.
constant : used for constant or literal storage.
heap : used for dynamic memory need.
stack : function used its for variable.
consider a function so defined as
void doSomething(int x)
{
x++;
}//end of function
is called as doSomething(5) or doSomething(y) in another function or main function .
here
x is local variable to function "doSomething". It gets its home (memory location) somewhere in stack region.
When doSomething(5) is called 5 gets copied to x's memory or doSomething(y) is called value/content of y (different memory location) gets copied to x's memory. Whatever operations applied on x, will not affect y 's content/value at all. Since its memory location is different.
Whenever execution flow reachs at end of function x dies/gets destroyed. Whatever value of x is not accessible/available. In short, update is lost and y is unaffected (Change is not reflected).
This is what so called Call by Value
Now
Consider an another function so defined as
void doSomething(int *x)
{
(*x)++;
}
is called as doSomething(&y)
here x is called pointer (conceptually called reference*).It will also gets home somewhere in stack region
When doSomething(&y) is called address of y gets copied to x's location block. Since this x is special variable so called pointer that holds address and it is said that x refers/points to y.
When (*x)++ is applied, here * is indirection operator which will bring whom x refer to the context ie. (*x)++ will indirectly change the value of y by 1. Nothing will happen to x's value itself.
Whenever execution flow reach at end of function *x dies/gets destroyed as expected but this time change is made to y (indirectly) which is still alive somewhere in stack region (change is reflected).
Also not that this time doSomething(&5) or doSomething(any literal) is not possible because it's illegal to get address of any literal.
This is what so called Call by Reference/Call by Pointer.
note that Call by Reference has another meaning in C++ but conceptually remains same.
Let's look at the "calling" of functions first.
In C, the arguments to a function are typically "by value". Below, after calling sqrt(x), the value x is not changed for sqrt() received a copy of the value x, thus never gaining an ability to affect x.
y = sqrt(x);
// x did not change
printf("%f is the square root of %f\n", y, x);
Array parameters to a function appear to be "by reference". After fgets() is called, buf is expected to be altered. fgets() did not receive a copy of, but a "reference" to the char array. Thus fgets() could affect the contents of the array.
char buf[80] = { 0 }; // array 80 of char
printf("Before <%s>\n", buf); // "<>"
fgets(buf, sizeof buf, stdin);
printf("After <%s>\n", buf); // "<Hello World!>"
Let's now look at the "receiving" part: the function.
Function parameters of type double, int, struct types are received by value. The value of f here is the copy of the x above. Any changes made to f do not affect the x in the calling code.
double sqrt(double f) {
double y;
... // lots of code
return y;
}
Now comes the tricky bit and this is where there is lots of discussion in C.
The parameter s in fgets() below was not assigned the buf above (array 80 of char), instead s was assigned the pointer type derived from buf: address of the first element of an buf. By knowing the address of the array elements of buf (via s), fgets() affects what was printed above.
char *fgets(char * restrict s, int n, FILE * restrict stream) {
// code
s[i] = ThisAndThat();
// code
return s;
}
Let's now see how fgets() otherwise might be called:
char *p = malloc(80);
*p = '\0';
printf("Before <%s>\n", p); // "<>"
fgets(p, 80, stdin);
printf("After <%s>\n", p); // "<Hello World!>"
In this 2nd example, p is a "pointer to char". It is passed by value to fgets(). fgets() received, via s, a copy of p.
The central idea: fgets() does not know if it received an "address of the first element of an array" or a copy of a "pointer to char". In both cases, it treats s as a "pointer to char".
Let's assume fgets() did the following. Before s being changed, it affects the data pointed to by s. Then s, the pointer, changed. s is a local variable and this assignment does not change the calling routines variables buf nor p.
char *fgets(char * restrict s, int n, FILE * restrict stream) {
// lots of code
s[0] = '\0';
// more code
s = NULL;
return s;
}
Note: There are other issues such as passing functions as parameters and encapsulating arrays in structures to consider.

Can somebody explain the difference between **param and *param in C using a visual diagram?

In particular, why changes to parameters like *param aren't propagated back to the caller of a function but changes to parameters like **param do propagate back?
In both the cases the changes will be propagated but it depends on calling function.
see the case below (Since you have not given any code so, I am assuming a general scenario)
Famous swap function
int a=5,b=10;
swap(&a,&b) // Calling by address
void swap(int *paramA,int *paramB)
{
// Do the swap
}
You see that even in the function definition only *params but changes is reflected back to calling environment.
But in other case *param may not reflect when it is passed by value, means,
see this code ,
int a;
int *p = &a;
foo(p); // calling by value
void foo(int *param)
{
// if you do anything or change param to point to some other memory location
// then it will not be reflected back and p still be pointing to a.
}
while if you do this
foo(&p); //calling
void foo(int **param)
{
// if you do anything or change param to point to some other memory location
// then it must be reflected back in calling environment.
}
These things are called Pass by value and Pass by Address in C when calling functions.
I hope you got it.
int param is a variable, i.e. data.
int * param is a pointer to a variable, i.e. the memory address of data.
int * * param is a pointer to a pointer to a variable, i.e. the memory address of a memory address of data.
And so on.
When a function is called with a variable as argument, that argument gets copied to the stack (call-by-value). Any changes that the function does on its parameter is actually done on the copy, which gets destroyed with the rest of the stack frame when the function returns.
void foo( int x )
{
x = 23; // any changes done on x are strictly local
}
int main()
{
int a = 42;
foo( a ); // no matter what foo() does, a will still be 42.
return 0;
}
If you pass a pointer to a variable as argument to a function, it likewise gets copied - but the copy of a memory address still points to the same memory address, so the function can access that memory address (i.e., the original variable, not its copy on the stack). Changes that the function does on the contents of that memory address affect the function's caller.
void foo( int * x )
{
*x = 23; // changing the contents of the memory address pointed to by x
}
int main()
{
int a = 42;
foo( &a ); // passing the address of a; a will be changed to 23.
return 0;
}
You should be able to take it from there yourself.

Double pointers are also sometimes employed to pass pointers to functions by reference

" Double pointers are also sometimes employed to pass pointers to functions by reference "
can somebody can explain me the above statement, what exactly does point to function by reference means ?
I believe this example makes it clearer :
//Double pointer is taken as argument
void allocate(int** p, int n)
{
//Change the value of *p, this modification is available outside the function
*p = (int*)malloc(sizeof(int) * n);
}
int main()
{
int* p = NULL;
//Pass the address of the pointer
allocate(&p,1);
//The pointer has been modified to point to proper memory location
//Hence this statement will work
*p=10;
//Free the memory allocated
free(p);
return 0;
}
It means that you have a function that takes a pointer pointer (type int ** for example). This allows you to modify the pointer (what data it is pointing to) much in the way passing a pointer by reference would allow.
void change (int *p) {*p = 7;}
void Really_Change (int **pp) {*pp = null;}
int p = 1;
int *pp = &p;
// now, pp is pointing to p. Let's say it has address 0x10;
// this makes a copy of the address of p. The value of &p is still 0x10 (points to p).
// but, it uses that address to change p to 7.
change(&p);
printf("%d\n", p); // prints 7;
// this call gets the address of pp. It can change pp's value
// much like p was changed above.
Really_Change(&pp);
// pp has been set to null, much like p was set to 7.
printf("%d\n", *pp); // error dereference null. Ka-BOOM!!!
So, in the same way that you can pass a pointer to an int and change the value, you can pass a pointer to a pointer and change its value (which changes what it points to.)
I'll try to explain with both code and plain english :). The explanation may get long, but it will be worth the while.
Suppose we have a program, running its main() function, and we make a call to another function that takes an int parameter.
Conceptually, When you pass a variable as a parameter to a function, you can do so in (roughly speaking) two ways: by value, or by reference.
"By value" means giving the function a copy of your variable. The function will receive its "content" (value), but it won't be able to change the actual variable outside its own body of code, because it was only given a copy.
"By reference", on the other hand, means giving the function the actual memory address of our variable. Using that, the function can find out the variable's value, but it can also go to that specified address and modify the variable's content.
In our C program, "by value" means passing a copy of the int (just taking int as argument), and "by reference" means passing a pointer to it.
Let's see a small code example:
void foo(int n) {
n = 10;
printf("%d\n", n);
}
int main() {
int n = 5;
foo(n);
printf("%d\n", n);
return 0;
}
What will the output of this program be? 10 10? Nope. 10 5! Because we passed a copy of the int, by value and not by reference, foo() only modified the number stored in its copy, unable to reach main()'s copy.
Now, if we do it this way:
void foo(int* n) {
*n = 10;
printf("%d\n", *n);
}
int main() {
int n = 5;
foo(&n);
printf("%d\n", n);
return 0;
}
This time we gave foo() our integer by reference: it's actual memory address. foo() has full power to modify it by accessing it's position in memory, foo() and main() are working with the same copy, and so the output will be 10 10.
As you see, a pointer is a referece,... but also a numerical position in memory. It's similar to an int, only the number contained inside is interpreted differently. Think of it this way: when we pass our int by reference, we're passing an int pointer by value!. So the same by value/by reference logic can be applied to pointers, even though they already are references.
If our actual variable was not an int, but an int reference (pointer), and we wanted main() and foo() to share the same copy of that reference so that foo() can modifiy it, what would we do? Why of course, we'd need a reference to our reference! A pointer to a pointer. That is:
int n; /* integer */
int* n; /* integer reference(pointer). Stores an int's position in memory */
int** n; /* reference to integer reference, or double pointer.
Stores int*'s memory address so we can pass int*s by reference. */
I hope this was useful.

Resources