Passing pointer to function is'nt passing by reference in C? - c

#include<stdio.h>
int func(int*);
int main(void)
{
int a = 3;
int *p = NULL;
p = &a;
printf("p = %p\n", p);
func(p);
printf("p inc: %p\n", p);
return 0;
}
int func(int *p)
{
p++;
return 0;
}
Output: p=0x7fff6f87e89c
p inc:0x7fff6f87e89c
Pointer p is passed to function func and pointer p is incremented in func, but in main function its address is still the same!! Passing pointer to function is'nt passing by reference?

Pointers are passed by value.
If you want to pass a pointer by reference, you just pass a pointer of a pointer!
Like so:
#include<stdio.h>
int func(int**);
int main(void)
{
int a = 3;
int *p = NULL;
p = &a;
printf("p = %p\n", p);
func(&p);
printf("p inc: %p\n", p);
return 0;
}
int func(int **p)
{
(*p)++;
return 0;
}

There's no passing by reference in C. When you pass a pointer to a function, you are passing a memory address by value.
When, inside the function, you do this:
int func(int *p)
{
p++;
return 0;
}
...you are only incrementing the memory address indicated by the parameter p by sizeof *p bytes.
In order to "simulate" passage by reference in C, you need to explicitly dereference the pointer to access the actual object. If p is a properly assigned and valid pointer, then *p is the object it points to. If a non-pointer expression were this:
a = a + 1;
...then with p == &a it would become this:
*p = *p + 1;
...or simply (*p)++. Notice that the parenthesis are necessary because, otherwise, C will read this as *(p++). You can also get used to writing ++*p instead.

You increment the pointer, not the value.
Try like this
(*p)++;
And
printf("p inc: %d\n", *p);
You need to understand pointers. A pointer is simply a variable that stores the memory address where the data actually is. You can access the data by using the dereference operator *, so if you want to change the data, you simply dereference the pointer, and then modify the data.
Likewise, for printing you want to see the value of the data.
In your code, you only modify the pointer. In c you always pass by value, a copy of the pointer itself is created inside the func() function, initially it holds the same address as your original pointer, but since it's a copy, increment it will only affect the address in the local copy.
Further more, since it's pointing to a variable on the stack. The increment operation on it will result in a pointer that you can't dereference because it would be undefined behavior.
If you want to increment the address of the pointer, you need to pass a pointer to the pointer, like this
void func(int **p)
{
(*p)++;
}
and in main
func(&p);
note that the body of func() is the same, because you once again need to get access to the memory pointed to by p in order to modify it.

Related

Difference in ptr,&ptr,&ptr[0]

Below is the test code:
#include <stdio.h>
int funtion(int *ptr)
{
int temp;
temp = *ptr;
printf("ptr = %p %p %p %d\n", ptr, &ptr, &ptr[0], *ptr);
printf("*ptr = %d\n", *ptr);
return temp;
}
int main()
{
int i = 10;
int *tp = &i;
printf("tp = %p %p %p %d\n", tp, &tp, &tp[0], *tp);
(void)funtion(tp);
return 0;
}
answer:
tp = 0x7ffc1117392c 0x7ffc11173930 0x7ffc1117392c 10
ptr= 0x7ffc1117392c 0x7ffc111738f8 0x7ffc1117392c 10
*ptr =10
**question:
what are the difference between tp &tp &tp[0]
Which passing parameter we should use.
is this difference only for passing parameter?**
You are passing an int pointer to function. This is passed by value. Of course, the value they point to is the same.
int funtion(int *ptr)
{
int temp = *ptr;
printf("ptr = %p %p %p %d\n", ptr, &ptr, &ptr[0], *ptr);
printf("*ptr = %d\n", *ptr);
return temp;
}
temp is initialized with the value pointed to by ptr.
The first thing you print is ptr: the memory address you passed to function by value.
The second thing you print is &ptr. This is the address of that function argument. While this may be the same between function calls due to implementation-specific handling of the stack, it may also be different.
The third thing you print is &ptr[0]. This is the address is ptr[0], which is equivalent to writing *(ptr + 0) or just *ptr. Getting the address of this in turn is equivalent to just writing ptr.
The fourth thing you print is *ptr. Again, as with initializing temp this is just the int value that ptr points to.
1. what are the difference between tp &tp &tp[0]
Its their type.
The type of tp is int *.
The type of &tp is int **.
The type of &tp[0] is int * because &tp[0] is equivalent to tp1) :
&tp[0] -> &(tp[0]) -> &(*(tp) + (0)) -> &(*tp) -> tp
Note : You do not need to use [0] with pointer to access the value of a scalar type, which the pointer is pointing at.
2. Which passing parameter we should use.
Its not clear, what exactly you want to ask.
You are passing value of tp to function() function which is nothing but &i. The ptr parameter of function() function will hold the &i when it is called. If you want to make changes to the value of i within the function() function then you can do it because ptr hold address of i and *ptr will give value at that address which is nothing but the value of variable i. If you just want to access the value of i, you can simply pass the value of variable i.
3. is this difference only for passing parameter?
Which difference? I believe, you mean - why there is difference in &tp and &ptr?
ptr is local variable of function() function and tp is local variable of main() function. Though, they both hold the address of variable i their own addresses are different because they are different variables.
1). C Standards#6.5.2.1
The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))..

Unable to dereference double pointer in c

The output of this code is 20 20 10. The first 20 is easy to understand. But I am unable to understand how function change1 and change2 are accessing the variable b.
#include<stdio.h>
int a = 5, b = 10;
void change1(int *p);
void change2(int **pp);
main( )
{
int x=20, *ptr=&x;
printf("%d ",*ptr);
change1(ptr);
printf("%d ",*ptr);
change2(&ptr);
printf("%d\n",*ptr);
}
void change1(int *p)
{
p = &a;
}
void change2(int **pp)
{
*pp = &b;
}
But I am unable to understand how function change1 and change2 are accessing the variable b.
There is a misunderstanding of what change1 does.
It changes where p points to but that change is local to the function. It does not change where ptr points to in main since the pointer is passed by value. change1 does not have any code that accesses the variable b. It's not clear to me whey you think it does.
In change2, you are changing where the pointer points to, to b. The change affects where ptr points to in main since you are passing the address of ptr to change2 and you are changing where that dereferenced pointer points to.
In change1, p is a pointer to int that is passed by value. Assigning a value to p in change1 therefore has no effect because p is local to change1. This is the reason for the 2nd 20.
In change2, pp is a pointer to a pointer to int. It too is passed by value, but this time dereferencing pp (*pp) gives access to the location of the pointer (ptr), and it is into this location that the address of b (&b) is stored.
void change1(int *p)
{
p = &a;
}
The variable p is assigned with the address of a, but this is only valid within the function. p acts as a local variable within the function change1. After this function terminates, the pointer ptr would still be pointing at x(=20). This is the reason behind the second 20.
void change2(int **pp)
{
*pp = &b;
}
But this, is one of the correct ways to make changes to a pointer variable within the function so that it would still be valid outside. pp acts as a pointer pointing to the original ptr variable. As a result, ptr will end up pointing at b(=10) after change 2 terminates. This is the reason behind your third 10.
When you invoke change1() function, you're passing the pointer ptr as an argument. Let's suppose ptr = 0xcafebabe, and obviously *ptr = 20. Under the hood, you're writing the value 0xcafebabe on the stack, and the change1() function will only overwrite this value with &a on the stack frame corresponding to this function.
In the second case, you're passing a pointer to ptr as an argument. Let's suppose this pointer new_ptr has a value of 0xdeadbeef. In this case, *new_ptr = 0xcafebabe and you overwrite 0xcafebabe with &b (hence you are changing where the pointer is pointing.

Why can't I pass a pointer as an argument?

I am attempting to retrieve a pointer via a function in c. If the pointer is a return value from the function then it works. But if I pass the address of the pointer to the function, I can't update the dereferenced pointer value (which should be the address stored in the pointer) from within the function.
Please see the code and the output. Why don't I get the same results with both GetPointer1() and GetPointer2()? What am I missing?
#include <stdio.h>
#include <stdint.h>
uint8_t SrcArray[2][3] = {{11,12,13},{21,22,23}};
uint8_t *p1;
uint8_t *p2;
void GetPointer1(uint8_t *p);
uint8_t* GetPointer2(void);
int main()
{
printf ("&SrcArray[0][0]: %d\n", &SrcArray[0][0]);
GetPointer1(p1);
p2 = GetPointer2();
printf ("p1: %d\n",p1);
printf ("p2: %d\n",p2);
return 0;
}
void GetPointer1(uint8_t *p)
{
p = &SrcArray[0][0];
}
uint8_t* GetPointer2(void)
{
return &SrcArray[0][0];
}
Output:
&SrcArray[0][0]: 6295604
p1: 0
p2: 6295604
That is because the pointer you have in the function signature of GetPointer1(uint8_t *p) is passed by value. If you want to modify the pointer itself, you have to pass a pointer to a pointer:
void GetPointer1(uint8_t **p) {
*p = &SrcArray[0][0];
}
Otherwise, you may modify the piece memory to which the pointer points, but not the pointer itself.
Its is local to function GetPointer1 because it is a local variable which is passed as an value not as an address.
Here is the output details of your code for better understanding
inside main: &SrcArray[0][0]: 6295616
value of pointer p1: 0
address of pointer p1: 6295640
inside GetPointer1: 0
value of pointer p: 0 //which ur taking to a pointer p and modifying p whihc is local to that function.
address of pointer p: 64030024
inside GetPointer1 after assignment:value of pointer p: 6295616
address of pointer p: 64030024
If you want to pass address you need to use & before the variable say &p1.
Also as mentioned in one of the answer by IGarFieldI you can use pointer to a pointer.
void GetPointer1(uint8_t **p) {
*p = &SrcArray[0][0];
}
One more point since P1 is global variable, its accessible to all the functions you can directly use P1=SrcArray; which is allowed and does the same task.
ScrArray is equivalent &ScrArray[][] both gives the address of the array.
You have a variable p1 that is pointing to something. Then you pass it to a function GetPointer1. What happens there is that the value of the variable p1 (this is the address of the value it is pointing to!!!) is copied (!) to the function stack. This means that you can modify the pointed value (*p1), but not the original pointer (p1) itself, as you only have a copy of it. If you want to be able to modify the original pointer, then you have to retrieve the address of the pointer and pass this one to the function, i. e. you need a pointer to the pointer. You get this via the address-of operator &. So you need this:
getPointer1(uint8_t** p) { *p = /*...*/; }
and call it via
getPointer1(&p1);
#include <stdio.h>
#include <stdint.h>
int SrcArray[2][3] = {{11,12,13},{21,22,23}};
int *p1;
int *p2;
void GetPointer1(int **p);
int* GetPointer2(void);
int main()
{
printf ("&SrcArray[0][0]: %d\n", SrcArray[0][0]);
GetPointer1(&p1); /*<-- passing the reference of pointer p1 */
p2 = GetPointer2();
printf ("p1: %d\n",*p1);
printf ("p2: %d\n",*p2);
return 0;
}
void GetPointer1(int **p) /*<-- using double pointer */
{
*p = &SrcArray[0][0];
}
int* GetPointer2(void)
{
return &SrcArray[0][0];
}
o/p
rabi#rabi-VirtualBox:~/rabi/c$ gcc -g stack3.c
rabi#rabi-VirtualBox:~/rabi/c$ ./a.out
&SrcArray[0][0]: 11
p1: 11
p2: 11
rabi#rabi-VirtualBox:~/rabi/c$
" But if I pass the address of the pointer to the function." But you're not passing the address of the pointer, you're passing a copy of the pointer; changing the copy (as you noticed), doesn't change the original. If you actually pass in the &p (address of p) like you intended, you will be able to modify it - I'm unsure of syntax. edit: void GetPointer1(uint8_t **p) maybe?

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.

If p is a pointer to int where would one use &p

In the following code p is pointer to an int. It is quite clear that p points to the address of i. Through my research i know &p points to the address of pointer p. But i don't get why would you need separate address for that. And also when would you use &p.
int main() {
int i = 3, *p = &i;
printf("%p",&p);
printf("%p",p);
return 0;
}
If p is pointer to int then
int **q = &p;
When you want to use pointer to pointer, then use the address of a single pointer to assign it to pointer to pointer.
Just to make a point that pointer is also a data-type and it stored in the memory location and it holds a valid memory location as its value. The address in which this valid memory location is stored is given by &p
Your printf() also needs to be fixed. %p expects void *
printf("%p",(void *)p);
But i don't get why would you need separate address for that
You don't, but there exists the address of operator so you can take the address of a pointer, which is what
printf("%p\n", &p);
is printing.
And also when would you use &p
There are cases where this might be useful, consider for example that you need to pass a pointer to a function which could be reassigned into the function, you can do something like this
int allocateIntegerArray(int **pointerToPointer, size_t someSize)
{
if (pointerToPointer == NULL)
return 0;
*pointerToPointer = malloc(someSize * sizeof(int));
return (*pointerToPointer != NULL);
}
then you could use this funciton the following way
int *pointer;
if (allocateIntergerArray(&pointer, 10) == 0)
{
fprintf(stderr, "Error, cannot allocate integer array\n");
/* do some extra cleanup or recover from this error, or exit() */
exit(0);
}
The pointers themselves are also variables and as such they need to be sotred somewhere, so the address of a pointer tells you where is the pointer stored, it's value tells you where it is pointing to.
By knowing where it is stored you can do things like the one explained above.
A trivial example:
int nochange(int *c, int *val)
{
c = val; // Changes local pointer c to point to val
// Note that C passes copies of the arguments, not actual references.
}
int do_change(int **c, int *val)
{
*c = val; // Accesses the real pointer c at its real location and makes
// that one point to val
// Even though c is a pointer-to-pointer copy, its value is
// copied too, and the value is the address of the real c
}
int main()
{
int a = 1;
int b = 2;
int *c = &a; // A pointer is also a datatype that resides in memory
printf("%d\n", *c); // Will print 1
nochange(c, &b);
printf("%d\n", *c); // Will print 1
do_change(&c, &b);
printf("%d\n", *c); // Will print 2 because c now points to b
}
I have a similar answer with a bit more detail here about pointer vs pointer-to-pointer: pointer of a pointer in linked list append

Resources