passing a pointer address vs pointer to a pointer in C - c

I'm slightly confused between these two pieces of code:
version 1: (gives warnings after compiling)
int func(int *ptr2)
{
*ptr2 += 1;
}
int main()
{
int a = 5;
int *ptr = &a;
printf("Address of a: %x\n", a);
printf("Before: %x\n", ptr);
func(&ptr);
printf("After: %x\n", ptr);
return 0;
}
Output:
Address of a: 5770a18c
Before: 5770a18c
After: 5770a18d
version 2:
int func(int **ptr2)
{
*ptr2 += 1;
}
int main()
{
int a = 5;
int *ptr = &a;
printf("address of a: %x\n", &a);
printf("Before: %x\n", ptr);
func(&ptr);
printf("After: %x\n", ptr);
return 0;
}
Output:
Address of a: cc29385c
Before: cc29385c
After: cc293860
If I'm understanding pointers in C correctly when we pass by reference, we are creating a pointer to that location. This allows us to change the value at the address held by the pointer through the dereference operator.
However, if we want to change the value held by a pointer, we use a pointer to a pointer. We pass the address of the pointer and create a new pointer to hold said address. If we want to change the value, we use the dereference operator to access our pointer's (defined elsewhere) value.
Hopefully I'm on the right track, but I'm struggling to visualize what's happening with version 1 specifically. Mainly, I'd just like to understand the difference in make-up and output between these two programs. I assume version 1 is still a pointer to a pointer, but why are the incremented values different between both programs? If version 1 is successfully incrementing ptr's value (which I suspect is not), why is that I cannot find code with the same syntax? I think I'm missing something fairly trivial here... Any help is appreciated

Based on your output, you appear to be compiling for a 32-bit system where addresses and int are of that size.
When you increment the value at *ptr with that type being int, it will simply add 1.
When *ptr resolves to an int* then it will increment by sizeof(int) because the value at the current address in this case is 4 bytes long, so we have to increase the address by the number of bytes that an int consumes so that we're pointing at the next int. Note that doing this is only valid if you actually have allocated memory at the subsequent address.
Generally you pass a T** when the callee needs to modify the address to point to - such as say, the callee performs a malloc() to allocate space for the pointer.

&ptr is a pointer to a pointer, but what is passed to func() is a pointer to int converted from &ptr in implementation-defined manner. Then, *ptr2 += 1; is incrementing int and add 1 to what is pointed by ptr2 (the pointer ptr in main(), which eventually have the same reepresentation as `int in your system).
In version 2, the pointer to a pointer is correctly passed to func(). Therefore, pointer aritimetic is performed and the size of int is added to the address.
Note that you invoked undefined behavior by passing data having wrong type to printf(). The correct way to print pointers is like this:
printf("Before: %p\n", (void*)ptr);
As you see, cast the pointer to void* and use %p specifier.

Related

Warning: pointer is used uninitialized when printing its address

I'm new to learning programming by the way so don't be too harsh. Why exactly am I getting this warning and how do I fix it?
Here's the full code:
#include <stdio.h>
int main()
{
int a; // this declares the 'a' variable
int *ptr_a; // this declares the pointer variable
printf("a:");
scanf("%d", &a);
printf("a is %d\n", a); // this prints the value of 'a' that is read from the keyboard
printf("the address of the pointer is %p\n", ptr_a); // this prints the address of the pointer
ptr_a = &a; // this points the pointer to the 'a' variable
*ptr_a = *ptr_a + 5; // this modifies the 'a' variable with its pointer
printf("the value of the modified a is %d\n", a); // this prints the modified value of 'a'
printf("the address of the modified pointer is %p\n", ptr_a); // this prints the modified address of the pointer
return 0;
}
This line:
printf("the address of the pointer is %p\n", ptr_a); // this prints the address of the pointer
does not print the address of the pointer. It attempts to print the value of ptr_a. Since ptr_a has not been initialized, the compiler warns you that you are using it uninitialized.
If you printed the address of ptr_a, with:
printf("the address of the pointer is %p\n", (void *) &ptr_a);
Then the compiler will not warn use, because this does not use the value of ptr_a (which is not initialized), just its address (which is set when ptr_a is created).
After the line ptr_a = &a;, ptr_a is initialized with a value, and a line like this:
printf("The address of a is %p.\n", (void *) ptr_a);
will print the value without a compiler warning.
The warnings are to take seriously, even though they may seem unnecessary at times, doing so will create good programming habits, you can initialize the pointer to NULL then reassign it later, when you need to:
int *ptr_a = NULL;
However what's triggering the problem here is the fact that you are printing the value of the pointer not its address, which would be perfectly fine as it still has an address even when uninitialized, it only has a value when you assign it the address of a variable or otherwise make it point to some memory location.
If you want to print the address of the pointer you'll need &ptr_a and for good measure, being pedantic I'll admit, cast it to void* as %p specifier expects a pointer to void, not to int:
printf("the address of the pointer is %p\n", (void*)&ptr_a);

Difference between **ptr and &ptr

According to my knowledge
**ptr = the address of memory location of the pointer variable ptr
&ptr = the address of memory location where the value of ptr is stored.
Am I correct or **ptr == &ptr?
If they are equal whether I can pass &ptr as a pass by address for a function as a replacement to ptr? Knowledge me on this.
It might help if you understand that for any pointer (or array) p and index i the expression *(p + i) is equivalent to p[i].
Now if i is zero that means we have *(p + 0) which is equal to *p, and its equivalent expression p[0]. That means when you do dereference a pointer you get the value of where it points.
Double-dereferencing a pointer only works if the pointer is pointing to another pointer.
You understanding of the address-of operator & is correct though.
Lets work on an example:
int a = 10;
int *p = &a; // Makes p point to the variable a
int **pp = &p; // Makes pp point to the variable p
Now if we do *pp we get the pointer p, and if we to **pp we get the variable a and its value.
printf("Value of a is %d\n", a); // Will print "Value of a is 10\n"
printf("Value of *p is %d\n", *p); // Will print "Value of *p is 10\n"
printf("Value of **pp is %d\n", **pp); // Will print "Value of **pp is 10\n"
Also, using pointer to pointer might seem not very usable, but if you think about dynamically allocated arrays things change. For a dynamically allocated array you need to use a pointer, and if you want a matrix (i.e. an array of arrays) you need to use pointer to pointer, if you want to allocate both "dimensions" dynamically.
Furthermore, while C doesn't support passing arguments by reference, it can be emulated using pointers, and if you need to pass a pointer by reference you do it by passing a pointer to a pointer (using the address-of operator).
Lastly a small fun fact. I started this answer by telling you that *(p + i) and p[i] are equivalent. Because of the commutative property of addition, the expression *(p + i) is equivalent to *(i + p) which means that p[i] is equivalent to i[p]. Don't do it in real code though, it will only obfuscate the code and cause confusion for new readers of the code.
Pay attention to the context: There is a difference when declaring and when using the pointer. In general, & is taking the address and ** is dereferencing the pointer twice. Obviously, these are not the same.
But in variable decfinitions, ** declares a pointer to a pointer. The declared variable can the take the address of a pointer as value:
int d = 10;
int *p = &d;
int **pp = &p;
This still doesn't mean that **p and & are the same: Here, the ** is part of the variable's type: pointer to pointer to int.
The same applies to function argumets: The function
void f(int **p);
takes a pointer to pointer to int as argument and you can pass it the address of a pointer to int.
'*' operator is used to hold a memory address.
'&' operator returns the address at which the variable is held.
for example
int a = 10; (10 is located in memory at, for example, 0xddffff0
int *b = &a; (&a is the same thing as 0xddffff0, so b now points to that address)
So '&' operator returns the address while '*' operator point at the address.
Actually my knowledge on double pointer was wrong .
**ptr - Value of the variable pointed by another pointer or we can say it is a pointer to a pointer
let me clarify with an ex
#include<stdio.h>
int main()
{
int num = 100 , *p , **ptr2ptr ;//Address of num=2000 ,p=3000 ,ptr2ptr=4000
p = &num;
ptr2ptr = &p;
printf("Single pointer *p =%d\n",*p);
printf("Double pointer **ptr2ptr=%d \n", **ptr2ptr);
printf("Address stored in p variable =%d \n", p);
printf("Address of p variable=%d\n", &p);
printf("Address of ptr2ptr=%d", &ptr2ptr);
return(0);
}
Output
Single pointer *p = 100
Double pointer **ptr2ptr= 100
Address stored in p variable =2000
Address of p variable=3000
Address of ptr2ptr=4000
From the above example it is clear **ptr2ptr(100) not equal to &ptr2ptr(4000) .
So I have found answer for my question .

How to pass by reference in this case?

I try to use the change() function to change the content of y.
I want to ask why y cannot change when I remove the * when assigning x to "abc"?
Also, I found that &*x is the same as &y, does that mean the address of pointer x is assigned to be the same as the address of the content that *y pointed to? Also, why &x does not equals to "abc"?
My Code:
void change(char *x) {
*x = "abc";
printf("S3: %x\n", &x);
printf("S4: %x\n", &*x);
}
int main() {
char *y = "def";
printf("S1: %x\n", &y);
printf("S2: %x\n", &*y);
change(&y);
printf("result: %s\n", y);
return 0;
}
There are many issues in your code, to point out some of them
y points to a string literal. Any attempt to modify a string literal is undefined behaviour.
To print an address, use %p format specifier, with a cast to (void*) for the argument, Using incorrect type of argument is undefined behaviour. Similarly, to print a char, you need %c, to print a string you need %s. Read more here
Inside change() function, *x is of type char, and you're trying to assign a pointer (base address of the string literal "abc") to it.
Enough!! Ask your compiler to tell you 'bout the rest. (In other words, please enable compiler warnings and try to fix the reported issues.)
why &x does not equals to "abc"?
Because &x gives address of x not value it points to . To get value you need *x.
y can't be changed because it points to string literals which is constant . Any try to change it will cause UB.
does that mean the address of pointer x is assigned to be the same as the address of the content that *y pointed to?
Pointer x has address of pointer y as you pass in function the address of y as argument.
You have to read more about pointers and parameters passing.
A pointer is a variable that holds the address in memory of another variable.
When you refer to a variable in your code the compiler use the value of such variable, for this reason when you refer to a pointer you'll get its content that is an address.
The operator & give back the address of a variable, so in the snippet:
int a = 10;
int *p = &a;
The pointer p will hold the memory address of variable a. If we use the operator * on p we will get the content of the memory address hold by a:
printf("%d", *p);
Will print 10.
If we write &*p, while it is not fully correct and many compilers will even issue a warning, we are getting the value pointed to by the pointer, and than requiring the address of that content, that is to have back again the address of data that is the content of the pointer.
Now the functions, when you pass a parameter in a function a copy of the variable is pushed on the stack from where will be accessed inside the function.
These values are local and any change made to them is lost when you leave the function. Of course if you pass a pointer, the address of your variable, then change the value using the pointer you can reflect the change on the real variable.
But you made a big error in your code, while you are declaring a pointer to char in your function proto:
void change(char *x)
You are passing change(&y); that is a char ** (y is a char *, &y is a char **). You should have got a lot of warnings for that.
Anyway the concept is correct on the caller side, you pass the address where is stored the address of your string, changing it y will point to the new string. It is perfectly legal because you're updating a pointer with another constant string (not changing a constant string that is illegal).
But you need the address of the pointer to the string, your function must be:
void change(char **x)
{
*x = "abc";
printf("S3: %p\n", (void *)&x);
printf("S4: %p\n", (void *)&*x);
}
int main(int argc, char *argv[])
{
char *y = "def";
printf("S1: %p\n", (void *)&y);
printf("S2: %p\n", &*y);
change(&y);
printf("result: %s\n", y);
return 0;
}
Last use the correct formatting in printf for pointer it is %p.
it should be change(y) not change(&y), change(&y) is address of *y not address in y. So y gives address of first character in a string, where &y gives address to y not address to first string.
HTH

Why Pointer is not incrementing?

Consider the following code
#include<stdio.h>
int main()
{
int a[5];
int *ptr=a;
printf("\n%u", &ptr);
++ptr;
printf("\n%u", &ptr);
}
On Output I'm getting same address value, Why pointer address is not incrementing.
The pointer is being incremented. The problem is that you are looking at the address of the pointer itself. The address of a variable cannot change. You mean to look at the value of the pointer, that is, the address it stores:
printf("\n%p", ptr);
On Output I'm getting same address value, Why pointer address is not incrementing.
The value of ptr is different from address of ptr.
By using ++ptr;, you are changing the value of ptr. That does not change the address of ptr. Once a variable is created, its address cannot be changed at all.
An analogy:
int i = 10;
int *ip = &ip;
++i; // This changes the value of i, not the address of i.
// The value of ip, which is the address of i, remains
// same no matter what you do to the value of i.
Let's go through the basics.
When you declare a pointer variable, you use a * with the type of whatever is being pointed to.
When you dereference a pointer (take the value this pointer is pointing to), you put * before it.
When you get the address of something (an address which can be stored in a pointer variable), you put & before whatever you're trying to get the address of.
Let's go through your code.
int *ptr=a; - ptr is a pointer-to-int, pointing to the first element of a.
printf("\n%u", &ptr); this prints the address of ptr. As ptr is a pointer, &ptr is a pointer-to-pointer. That is not what you wanted to see (as I understand), and you'd need to remove &.
++ptr; you inscrease the value of ptr, which is all right, but
printf("\n%u", &ptr); will still output the same thing, because although the contents of the pointer ptr have changed, its address has not.
So, you just need to replace each of the printf calls with printf("\n%u", ptr); to get the desired results.

Variation in Pointer address values

I tested a small program which is written below.My question is why there is a 12 bytes difference between the pointer to a value and a pointer to the first pointer.But if you look at other pointer addresses there is only a difference of 8 bytes every time.I executed this program multiple times and always I see this difference.Can anyone explain me what could be the reason?Thanks in advance..
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int val;
int *ptr;
int **ptrptr;
int ***ptrptrptr;
int ****ptrptrptrptr;
int *****ptrptrptrptrptr;
val=10;
ptr=&val;
ptrptr=&ptr;
ptrptrptr=&ptrptr;
ptrptrptrptr=&ptrptrptr;
ptrptrptrptrptr=&ptrptrptrptr;
printf("Value-%d\n",val);
printf("Value address - %d\n",ptr);
printf("Pointer address - %d\n",ptrptr);
printf("Pointer Pointer Address -%d\n",ptrptrptr);
printf("Pointer Pointer Pointer Address -%d\n",ptrptrptrptr);
printf("Pointer Pointer Pointer Pointer Address -%d\n",ptrptrptrptrptr);
return 0;
}
The results are:
Value-10
Value address - -1308521884
Pointer address - -1308521896
Pointer Pointer Address --1308521904
Pointer Pointer Pointer Address --1308521912
Pointer Pointer Pointer Pointer Address --1308521920
It's just the stack layout your compiler chose, f.e. it could be for alignment reasons. Things would most likely still work with other layouts.
Side note, you should use %p to print addresses.

Resources