Difficulty in understanding the pointers output - c

Please have a look at code below :
#include <stdio.h>
void main()
{
int a=30;
int *var=&a;
Change(&var);
printf("%d %d",*var,a);
}
int Change(int**ptr)
{
**ptr=40;
}
#include <stdio.h>
void main()
{
int a=30;
int *var=&a;
Change(var);
printf("%d %d",*var,a);
}
int Change( int *ptr)
{
*ptr=40;
}
The output from both programs is 40 40
We are passing the copy of address of var so why it is reflected in actual main function and producing output 40 40?
Why both of these programs are producing same output?

Both programs are equivalent. In first one, you passing pointer to pointer (i.e. address of pointer variable), and then dereferencing it twice. In second one, you are are just passing pointer (i.e. address of actual variable) and dereferencing it once.

It seems to me you need the following illustration to get the answer on your q:

The output is the same because you write 40 via the same pointer to int. In the second case you pass pointer-to-int, which you successfully dereference with * operator and obtain lvalue with type int, to which you then write 40. In the first case you pass pointer-to-pointer-to-int. And then you do double dereferencing: **ptr or the same as *(*ptr). Inner * is applied first and makes the expression with type pointer-to-int inside braces, and that pointer-to-int is the same as was passed to Change() in the second case. And at the end - outer * works just like for the second case.

&var passes the address of var and Change uses double pointer because, var is pointing to address of a. So, Derefrencing single pointer on &var (address of var) will point to the value stored in var i.e., a's address, so again derefrencing it, will point to the value of a i.e., 30.
For single pointer Change, I think, you should figure that out now from the above details.

Related

Copy of address in C?

I know that this code:
void incVar(int i){
i++;
}
We know this will create a copy of the integer and then increase that value, but not the actual value.
By nature: Methods in C create copies of parameters in their Stack Frame and not the original variable.
But:
void incVar(int *i){
(*i)++;
}
Is supposed to increase the actual value of the integer by the pointer dereference.
But then, why doesn't C just create a copy of the pointer *i instead? If this is the normal behavior with regular integers, then why doesn't the same thing happen with pointers?
It is the same with pointers. All variables in C are passed by value, even pointers.
You copy the address stored in the pointer outside the function, into its parameter.
But you can use that address to reference a variable which can be allocated anywhere. So in the following code:
int j = 0;
incVar(&j);
incVar receives by-copy the address of j. But it can use that address to read or modify j (in)directly.
In fact the same thing as with values happens with pointers. Just make sure to understand the syntax correctly. You are not passing the integer *i by copy to incVar, but you are passing the pointer i of type int* by copy. No matter how often you copy the pointer to an address, it always points to the same address. So i in your second incVar example points to the integer the caller took the address of. So by derefencing the copy of the pointer (in (*i)++), you are acessing the integer of the caller.
Its better to see int *i; as a variable named i of type pointer-to-int, instead of a pointer named *i.
In your example:
void incVar(int *i) {
(*i)++;
}
We probably use it as such in the main function:
int a = 5;
incVar(&a); //After this line, a is now 6.
What happens in incVar(..) is this:
A variable i is created, of type pointer-to-int.
It holds a copy of the value of &a.
Although i is a copy, its value is the same as that of the value of &a, and it still points to the same integer a.
As a result, by de-referencing i, I refer to the integer a.
Increment the integer a, which obviously is at the address pointed to by i.

How does a pointer to the constant pointer of the first element of an array work?

I wanted to test if I could change the constant pointer that points to the first element of an array in C. While testing I got some strange output that I don't understand:
//Constant pointer to pointer to constant value
void test(int const * * const a) {
//printf("%d", **a); //Program crashes (2)
(*a)++;
}
int main()
{
int a[5] = { 1,2,3,4,5 };
test(&a);
printf("%d", *a); //Prints 5 as output (1)
return 0;
}
I expected the compiler to give an error when I try to compile (*a)++ but instead I can run the code, but when I try to print the element I get a strange value (1).
Then I wanted to print out the value (2) of the first element of the array. When I tried this, the program crashes.
By doing &a you are making a pointer to an array (int (*)[]).
Then when this pointer to array is passed to the test function, it's converted to a pointer to a pointer(int **);
Then (*a)++; is UB.
1. So why 5?
On modern implementation of C like GCC, pointer to a array has the same numerical value as the beginning of the array, so is the address value when the array decays to a pointer: they all are the beginning address of the array.
So, in test, int **a points to the beginning of the array, (*a)++ deferences the pointer as int * and increment the pointer by 1 int element, which is usually implemented as adding the sizeof(int) to the numerical value of the pointer.
Then, 1+sizeof(int) gives you 5.
2. Why it crashed in the second case?
Assuming you are using a 32bit x86 machine, or some machine whose pointer type has the same size as int type, then *a equal to 1. Then further dereferencing the pointer at a memory address at 1 usually gives you a segfault.
The program crashes at the printf because test assumes that when it dereferences a the resulting object is a pointer. If it were one and contained a valid address, the second dereferencing would yield an int object. Alas, a contains the address of the array, which is numerically the address of its first element. The 4 or 8 bytes there are considered an address (because test thinks that *a is a pointer) and the code then tries to access the memory at address 1 in order to print the int value assumed at that address. The address is invalid though, so the program crashes.
Now that we have established that the program considers the data at the beginning of the array a pointer to int, we know what (*a)++ does: it increments the value there by sizeof(int) so that the "pointer" point to the next int "element". I guess an int on your machine is 4 bytes long because 1+4=5, which is printed.
This code is illegal in C, you should get a compiler diagnostic. (If not, turn up your warning level). The results of running any executable produced are meaningless.
The code is illegal because int (*)[5] does not implicitly convert to int const **.
the constant pointer that points to the first element of an array in C
There is no such thing. You misunderstand what arrays are. Arrays are a series of contiguous elements. int a[5] is like int a; except that there are 5 ints instead of 1.
int a; and int a[1]; cause identical memory layout. The only difference is the syntax used to access that memory.

What's the different between args and &args?

Here is my code snip
#include <stdio.h>
void change(int a[]){
printf("%p\n",&a);
}
int main(){
int b[] = {1,2} ;
printf("%p\n",&b);
change(b);
return 0;
}
I run it and it get the result following
0x7fff5def1c60
0x7fff5def1c38
As we can see the actual parameter address is defferent from the formal parameter address
Then I edited my following
#include <stdio.h>
void change(int a[]){
printf("%p\n",a);
}
int main(){
int b[] = {1,2} ;
printf("%p\n",b);
change(b);
return 0;
}
Then I get the results
0x7fff56501c60
0x7fff56501c60
So it seems that the actual parameter and the formal parameter have the same address.
I am confused that what's the different between &a and a(a is a array),and why I get the different address from the first snippet?
Thanks!
In:
printf("%p\n",&b);
you are printing the address to the first array cell.
In:
change(b);
and specifically in:
void change(int a[]){
printf("%p\n",&a);
}
you are printing the address of the variable a which in itself is a decayed pointer. So it is semantically equivalent to:
void change(int* a){
printf("%p\n",&a);
}
To retrieve the array first cell you would need to write the function as:
void change(int* a){
printf("%p\n", a);
// ^^
}
You can think of a is the starting address of the memory where to store array[1, 2].
Please also think of a is a variable that stores the array address. A variable means itself is somewhere in the memory. So &a is the address of the variable a. All in all, address &a in memory stores the address of the array[1,2].
In your first case, you are passing the address of variable b to function change so that the function variable a stores the address of variable b. But &a is the address of a not the content of a. That's the reason cause the difference.
Because I don't think that the answers so far stress it enough, I'll give another answer:
There is no difference between b and &b, if b is an array. An array is almost like a pointer, but not 100%. A pointer is a variable that stores an address, as you know. So when you create a pointer p, you create a new variable and then assign some address to it. Now the pointer variable p has an address, and it's value is also an address. You can do three things with it:
- Get ps address with &p
- Get ps value with p
- Get ps dereferenced value with *p
With an array ar, it is different. It acts like a pointer, but it is not a distinct variable where an adress is stored! By creating an array, you just allocate the memory for the elements you want to store, but not for a variable that stores the address of these elements. The variable ar just 'stands for' the address of the first element, but it is not saved somewhere in an extra space; the compiler makes sure to translate ar to the memory of the first element - this is important to understand. So what you can do with it is:
- Get ars address with &ar or with ar
- Get ars value with ar[0]
This is the reason why in your change function, int a[] is the same as int *a but in your main function, int b[] is not the same as int *b. The latter allocates memory for an address, while the first just creates memory for a specified amount of elements, and just uses b as a placeholder for the first address of these elements - there is no extra memory allocated for the first element's address, as it would be with a pointer.
This is also the reason why in main, you can't do b = some_pointer, but you can do it in change - because one is a pointer that has memory allocated and thus can change it's value like every other variable, and the other one is just a placeholder for it's first element and thus cannot change it's value.
I hope now it is clear why &b is the same as b - Since b is not a distinct variable with a place in memory, you cannot ask for it's address - it will just give you the address that b stand for anyway.
In main(), b is an array which size if derived from the initialisation, and &b denotes the adress of the array.
In change(), a is an array of unknown size, which as parameter is handled as a pointer. &a is the adress of this pointer.
In the second version of your code, without the & you refer in both case to the value of the pointer.
Here the relevant extracts from the C11 standard:
6.5.3 Unary operators, pt 3: The unary & operator yields the address of its operand.
6.7.6.3 Function declarators, pt 7: A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within
the [ and ] of the array type derivation.
The "&" operator returns the address of a variable and the "%p" construct in printf returns the address of the pointer.
In your example, these calls in main() are equivalent:
printf("%p\n",b);
printf("%p\n",&b);
Both return the memory position of b, which is 0x7fff56501c60 in your example
When you define a function, you introduce a local variable a:
void change(int a[]){
This is a pointer (equivalent to int * a) and has its own memory address.
When you call this inside the function:
printf("%p\n",a);
you get the same as above: The address of b: The value of pointer b is copied to a and printf tells you where it points at.
However if you do this:
printf("%p\n",&a);
Then you get the address of the local variable a, which is distinct to b. It does not matter what is inside a and in your example the value of b is not even used by function "change", you could also run this:
#include <stdio.h>
void change(int a[]){
printf("%p\n",&a);
}
int main(){
int b[] = {1,2} ;
printf("%p\n",&b);
change((int *)0);
return 0;
}
This runs "change" with a Nullpointer and it is still equivalent to your first example: "change" just prints out the address of the local variable a, regardless of contents.

Dereferencing array pointer in a function

How do you deference a pointer to an array to get the value stored in it? For example:
void testFunction(int **test){
printf("%d", *test[1]);
}
int main()
{ int test[10];
test[1] = 5;
testFunction(&test);
return 0;
}
I get an error. Anyone could explain?
How do you deference a pointer to an array to get the value stored in it?
You use the * operator, as for every pointer. (Oh, and pay attention to operator precedence!)
void foo(int (*arr)[5])
{
printf("%d\n", (*arr)[0]);
}
int main()
{
int arr[5] = { 0, 1, 2, 3, 4 };
foo(&arr);
return 0;
}
Your code would have generated a diagnostic about an incompatible type being passed to the function. For example, GCC complains:
prog.c: In function 'main':
prog.c:9: warning: passing argument 1 of 'testFunction' from incompatible pointer type
You should pay attention to all diagnostics issued by your compiler, and make sure you understand them, and take the appropriate measures to address them. For this particular one, if you intend to pass in a pointer to an array, you need to write your function to accept such a thing. Then, when you dereference the pointer, you have an array. So, you access it like one.
void testFunction(int (*test)[10]){
printf("%d", (*test)[1]);
}
The [] has higher precedence that *, so the parentheses are required both for the function parameter argument, and for accessing the value in the printf(). When the pointer to int[10] is derferenced, the resulting value is the address of the first element of the array test defined in main. The [] operation then access the 2nd element of the array, and you get the value you expected.
You may be more convinced that your use of int **test is wrong for a pointer to an array if you note that the assertion below will always be true:
int test[10];
assert(&test == (void *)test);
As the compiler warning indicates, a pointer to a pointer to int is not the same as a pointer to an int[10]. The type being pointed to determines the type that results from a dereference.
So:
int test[10] = { [1] = 5 };
testFunction(&test);
This passes the address of test to testFunction. The address of a variable corresponds to its location in memory. This is not so different for an array, but the location in memory for an array variable is the address of its first element. So, the address returned by &test above is the same address returned by test alone.
This gives a disastrous consequence when you treat this pointer value as a pointer to a pointer to int in your testFunction. First, note that you ignore proper operator precedence, so the first dereference is:
test[1]
Since you declare the test parameter to be a pointer to a pointer to int, this increments the address in test by sizeof(int *) and treats the result as an int *. Then, you dereference again:
*test[1]
This now takes the value of test[1] and dereferences it again in an attempt to get an int. However, the address returned by test[1] has no relationship with the array test defined in main, and you are accessing a totally nonsensical memory location.
Even if you paid attention to the precedence with your pointer to pointer to int parameter type, a similar problem would have resulted.
(*test)[1]
Now, the pointer to int[10] is treated as a pointer to pointer to int is derferenced first. This results in the first sizeof(int **) bytes of the test array in main to be treated as a pointer to int. This is already a nonsensical value at this point, but the array dereference now increments this value by sizeof(int) bytes and dereferences that value in an attempt to obtain an int.
The other user gave an example of how it is usually done already, but if you insist on passing an int ** then because of operator precedence the syntax would be like:
void testFunction(int **test){
printf("%d", (*test)[1]);
}
int main()
{ int test[10];
test[1] = 5;
int *testptr= &test[0]; // or int *testptr= test;
testFunction(&testptr); // this passes an int **
return 0;
}
But in c the name of an array is a pointer to the array elements, so int *ptrtest and ptrtest[1] is more commonly used.

Is passing a variable declared to be a pointer to a function the same as passing the address of a variable not declared to be a pointer?

Even after years of C, pointers still confuse me.
Are these two the same:
int *num;
someFunc(num)
and
int num;
someFunc(&num);
Declaring a variable with * makes it a pointer, & turns a variable (momentarily) into a pointer?
No they are not the same. In the first case you have a pointer which is pointing to some random memory location (as you have not initialized it). In the second case, the pointer obtained in someFunc will be pointing to a valid location (the address of variable num).
They are the same in terms of the function call. However
The difference is....
int num is an actual integer, which you take the address of. Which can then be placed into a pointer
int *num is a pointer to an int, however, with your code as is, it does not point to an actual int that can hold a value.
so only the second example is working code.
first one would be working if...
int x;
int *num = &x;
someFunc(num)
someFunc would look like
void someFunc(int *blah)
{
}
so basically int* num = &x is whats going on when you do the function call someFunc(&num) ie, its effectively just doing int* blah = &num
The second passes the address of the integer num, a perfectly reasonable thing to do. The first passes whatever happens to be stored in the pointer num. That should be the address of an int, but in your example num is uninitialized and the address probably points to garbage (at best).
& doesn't "turn a variable into a pointer", its an operator that returns the address of the variable. Which is, by definition, a pointer. Hence, no difference, the function someFunc receives a pointer value either way (in the first case it receives a copy the value of the pointer variable, in the second case it receives a copy of the return value of the operator &).
In the first case, you're declaring num to be a pointer to an integer. In the second case num is an integer.
To the someFunc function, in both cases the argument passed is a pointer to integer. So, to print the value you'll need to dereference printf("%d\n", *num).
In both cases the value would be some garbage since you haven't initialized.
Hope that helps.
Update On FreeBSD I got segmentation fault with the first one since the pointer which is not initialized may have pointed to somewhere that it is not supposed to.

Resources