#include<stdio.h>
int main(){
int a[5] = {0,1,2,3,4};
int * ptr;
ptr =(int *) &a;
printf("\n&a:%u,&a[0]:%u,ptr:%u\n",&a,&a[0],ptr);
ptr = (int*)(&a+1);
printf("\n&a:%u,&a[0]:%u,ptr:%u\n",&a,&a[0],ptr);
ptr = (int*)(&a);
ptr = (int*)(&a[0]+4);
printf("\n&a:%u,&a[0]:%u,ptr:%u,*ptr:%d\n",&a,&a[0],ptr,*ptr);
return 0;
}
o/p:
&a:3213284540,&a[0]:3213284540,ptr:3213284540
&a:3213284540,&a[0]:3213284540,ptr:3213284560
&a:3213284540,&a[0]:3213284540,ptr:3213284556,*ptr:4
In the above code &a and &a[0] gives the same address 3213284540. But the two cases when added with 1 gives different address.
&a[0]+1 => 3213284540 + 4 = 3213284544 [The value stored in this address is '1']
&a+1 => 3213284540 + (5*4) = 3213284560 [Goes Out of bounds of the array]
&a+1 is equivalent to sizeof(array)+1.
But how the compiler interprets this &a[0]+1 and &a+1 ?
But how the compiler interprets this &a[0]+1 and &a+1
It's pointer arithmetic, so it's always important to know the pointed types and one basic thing: adding 1 to a pointer makes it point to some "next" element.
In your example &a[0] is of type int * so adding 1 moves the
pointer to the next int. So the address should increase by 4/8
bytes or so, depending on sizeof(int)
However, &a is of type int (*)[5]. So adding 1 to it moves the
pointer to the next array. In effect, the address should increase
by sizeof(a).
Side note: use %p when printing pointer values.
Related
I'm reading a book about the C language and it says
The assignment of an array name to a pointer to an array of ints, such as a, is implicitly converted into a pointer to the array’s first element, not a pointer to the whole array and it requires an explicit type conversion.
So the following code would give "Error: mismatched pointer types".
int(*arrPtr)[4] = NULL;
int a[4] = {7, 8, 9, 5};
arrPtr = a;
We should change it to
arrPtr = (int(*)[4])a;
My question is why it's required to do type casting when we can simply get the address of the whole array a using & operator.
arrPtr = &a;
Is there any advantage in doing the cast? aren't they both the same?
An explicit cast is needed here:
arrPtr = (int(*)[4])a;
Because the pointer types are not compatible. However, that doesn't mean that such a conversion is valid. Taking the address as you stated:
arrPtr = &a;
Would be the correct thing to do, and elements of a can then be access via arrPtr with notation such as (*arrPtr)[n].
To clarify, here a is a pointer of type int* and points to the 0th element of the array.
arrPtr is a pointer that can point to an array of 4 integers.
So arrPtr and a are two different pointer types. And the compiler throws a warning if you try to assign a to arrPtr. But you can still do this assignment in C however it is not the way to do it.
Note that arrPtr = a & arrPtr = &a assigns the same memory address to arrPtr. But for &a the compiler doesn't show any warning.
See the below progarm output to get more clarity on this,
int main()
{
int(*arrPtr)[4] = NULL;
int(*arrPtrtemp)[4] = NULL;
int *ptr;
int a[4] = {7, 8, 9, 5};
arrPtr = a;
arrPtrtemp = &a;
ptr = a;
printf("arrPtr:%p\n", arrPtr);
printf("arrPtrtemp:%p\n", arrPtrtemp);
printf("ptr:%p\n", ptr);
arrPtr++;
arrPtrtemp++;
ptr++;
printf("arrPtr:%p\n", arrPtr);
printf("arrPtrtemp:%p\n", arrPtrtemp);
printf("ptr:%p\n", ptr);
return 0;
}
Will give the following output:
arrPtr:0x7ffc1bf19820
arrPtrtemp:0x7ffc1bf19820
ptr:0x7ffc1bf19820
arrPtr:0x7ffc1bf19830
arrPtrtemp:0x7ffc1bf19830
ptr:0x7ffc1bf19824
Note that arrPtr & arrPtrtemp are same and works same irrespective of the compiler warning. The purpose of this typecasting arrPtr = (int(*)[4])a; is to convet int* to int(*)[4].
The main difference between int & int()[4]** comes in pointer arithmetic.
so if we assume the size of an integer is 4 bytes in our system, an operation like ptr++(an int* pointer) will increment the address by 4 bytes. And arrPtr++ (an int(*)[4] pointer) will increment the address by 16 bytes.
Edit:-
here a is a pointer of type int* and points to the 0th element of the array. Change to the following,
When using the array name a to assign the address of the 0th element of the array, the compiler checks the pointer type of a as int*. And by using & operator to get the address of array a, the compiler will treat the pointer type of &a as int (*)[4] in this case. And no warning will be displayed.
Pointer to array of elements when dereferenced return an address.
Since it is holding the address of the first element of the array, dereferencing it should return a value.
int arr[] = { 3, 5, 6, 7, 9 };
int *p = arr;
int (*ptr)[5] = &arr;
printf("p = %p, ptr = %p\n", p, ptr);
printf("*p = %d, *ptr = %p\n", *p, *ptr);
Output:
p = 0x7fff6ea72d10, ptr = 0x7fff6ea72d10
*p = 3, *ptr = 0x7fff6ea72d10
Why does *ptr return the base address of the array, shouldn't it return the value at that address??
Why does *ptr return the base address of the array, shouldn't it
return the value at that address??
(p3) Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary '&' operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue. C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3)
int (*ptr)[5] = &arr;
ptr is a pointer-to-array of int [5]. When you dereference ptr you get array of int[5]. How is an array of int[5] accessed?
Rule 6.3.2.1 provides the answer:
"array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object...
Now if you dereference again (e.g. **ptr), then you get the value of the 1st element.
The question was
"Why does *ptr return the base address of the array, shouldn't it return the value at that address?"
It does return the value at that address, which is the array arr.
Think about a queue of people: you can point to the first person and say "that person over there" or you can point to the same person and say "that queue over there". There are 2 things at the same location: a person and a queue. Same thing happens with arrays: person * for that "person over there" and person (*)[42] "for that queue of 42 people". If you dereference a pointer to queue, you get a queue. If you take the first from the queue you get a person.
But then the array itself will decay to address to the first element when it is given as an argument to printf. Thus here,
int arr[] = { 3, 5, 6, 7, 9 };
int (*ptr)[5] = &arr;
// undefined behaviour really, all pointers should be cast to void *
printf("%p %p %p %p", *ptr, &ptr[0], arr, &arr[0]);
all these 4 expressions will result in pointer to int, and the value is the address of the first element in the array (the address of 3 in arr).
Here is a simple, less technical explanation.
How are you setting p? = arr;
How are you setting ptr? = &arr;
Your question really has nothing to do with arrays at all. arr could be literally any type and the answer would be the same: & gets the address of arr, so whatever arr is, ptr is storing its address while p is storing arr itself.
If you do *ptr, you will dereference that address and thus get a value equal to p.
int arr = 3;
// clearly these are different!
int p = arr;
int* ptr = &arr;
Similarly
int x = 3;
int* arr = &x;
// clearly these are different!
int* p = arr;
int** ptr = &arr;
// so of course they dereference differently
printf("*p = %d, *ptr = %p\n", *p, *ptr);
The behavior you see is a result of 'c' interpreting arr as a pointer to the memory location of the first element. Pointer to the array &arr will be an address of the array itself in memory, which is also the address of its first element. As a result arr and &arr yield the same values. Try this:
printf("array = %p, &array = %p\n", arr, &arr);
Thought the values are the same, types are different. arr is a variable, whether &arr is a pointer to the variable.
ptr reflects the same picture. Its value ptr = &arr makes it a pointer to an array. It contains the address of the array. *ptr returns the array itself, which in 'c' interpretation is the address of the first element of the array. As a result values for ptr and *ptr are the same as for &arr and arr.
Hope it makes it clearer (not murkier) :-)
Arrays are pointers. Arrays are not pointers, see the comments below
A pointer to an array is a pointer, pointing at a pointer. Try de-referencing twice over, that should yeild a value.
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 = #
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 .
I came across a code whoes output I'm not able to understand.The code is-
int main()
{
int a[] = {1, 2, 3, 4, 5, 6};
int *ptr = (int*)(&a+1);
printf("%d ", *(ptr-1) );
return 0;
}
The output of above code is coming out 6, but i think that it should be 1. Please explain why it is 6.
In your question "&a" is address of the whole array a[]. If we add 1 to &a, we get “base address of a[] + sizeof(a)”. And this value is typecasted to int *. So ptr points to the memory just after 6 . ptr is typecasted to "int *" and value of *(ptr-1) is printed. Since ptr points memory after 6,so ptr – 1 points to 6.
&a is an address of array a. Adding 1 to it will increment it to one past the array (adding 24-bytes). Cast operator (int*) cast &a+1 to pointer to int type. ptr-1 will decrement ptr by 4 bytes only and therefore it is the address of last element of array a. Dereferencing ptr - 1 will give the last element which is 6.
Yes, because a is an array having a type int[6]. Therefore, &a gives you the type int (*)[6]. It is not same as pointer to int, it is a pointer to int array.
So, &a + 1 increments the pointer by one of the the array size, pointing past the last element of the array.
Then, taking the address in ptr and doing a -1, decreases the address by a sizeof(*ptr) which is sizeof(int), which gives you the address of last element on the array.
Finally, de-referencing that address, you get the value of the last element , 6. Success.
Because (int*)(&a + 1) uses the whole array as the base type and adds 1 whole size of an array to the address , i.e. adding 24 bytes.
And when you do ptr-1 since ptr type is int it will subtract only 4 bytes.
Its very important to remember the type of the pointer while doing pointer arithmetic.
I just read some question about pointer. Here is the code:
int a[5]={1, 2, 3, 4, 5};
int *p = (int*)(&a + 1);//second line
cout<<(*p)<<endl;
My compiler output is 0. What is *p? Is it the pointer to array a? and what is &a+1 means?
This is what your declaration statement means:
p
|
v
a[0] a[1] a[2] a[3] a[4] | a[5]
---------(Length)------->
But you're trying to get this (I assume):
p
|
v
a[0] a[1] a[2] a[3] a[4] |
---------(Length)------->
You need to remove the second set of parenthesis from your declaration statement to get a[1]:
int * p = (int *)(&a + 1);
// change to this:
int * p = (int *) &a + 1;
The reason you're getting the wrong value has to do with the sizeof operator, operator precedence, and pointer arithmetic. Let me explain those before I explain the error.
Sizeof Operator
The sizeof operator evaluates the size (in bytes) of a datatype. Immediate example:
sizeof (char) // always returns 1
sizeof (int) // usually returns 4 or 8
sizeof (int *) // usually returns 4 or 8
And note this interesting example:
int a[5];
sizeof (a) // returns sizeof (int) * 5
Operator Precedence
Operator precedence is the order in which a series of operators are evaluated. Anything in parenthesis will be evaluated first. After parenthesis are evaluated, it's up to the operator precedence to determine what order the expression will be solved.
Here's the relevant operators and they're order in the precedence table:
Operator Description Associativity
() Parenthesis Left-to-right
(cast) Cast Right-to-left
& Address of Right-to-left
+, - Plus, Minus Right-to-left
Pointer Arithmetic
Pointer arithmetic is mostly about adding, subtracting and multiplying pointers with integers (or other pointers). What you need to know (for the scope of this question) is this:
int * p;
p = p + 1;
Even though it says + 1, it is actually adding sizeof (int) to the pointer.
This was a design choice by the writers of the C standard because it is much more common
that programmers want to add sizeof (int) to the pointer (which brings them to the next integer in an array) than to add 1 (which brings the pointer in between the first and second element in the array).
More generally put:
datatype p;
p = p + 1;
// actually means
p = p + sizeof (datatype);
Here's a relevant example:
int a[5];
a = a + 1;
// actually means
a = a + sizeof (a);
// remember that sizeof (a) is going to be sizeof (int) * 5?
Declaration Statement
Back to your declaration statement:
int * p = (int *)(&a + 1);
You may already see what's wrong with it: a + 1 really means a + sizeof (a), which brings you out of scope of the array. This may be 0 (often it is) or it may be some other random value.
What you might not have noticed is that this:
int * p = (int *) &a + 1;
Actually gives you the second element in the array. This has to do with operator precedence. If you look at the operator precedence table that I put in a link, casts have a higher precedence than & and + operators. So if a is cast as a (int *) instead of a[5] before the rest of the expression is evaluated, then it becomes equivalent to this:
int * a;
a = a + 1; /* and this would
give you the second element
in the array */
So simply put, if you want to access the second element in your array, change:
int * p = (int *)(&a + 1);
// to this:
int * p = (int *) &a + 1;
&a is the address of the array.
&a + 1 is also an address, but what is this 1? It's a pointer that points sizeof a bytes from a. So it's like writing int *p = &a[5];, then you're casting it to int *.
Now why 0? Because a[5] happens to be 0 - Note that it's out of bounds and could be anything else (Undefined behavior).
Note that arrays are zero-based, meaning that the indexes are from 0. So actually a[4] is the last element, a[5] is out of bounds.
The operator & is used to take the address of a variable. Thus, &a is of type pointer to array of 5 ints: int (*)[5].
Pointer arithmetic means that when you have a pointer p, then p+1 will point to the next element, which is sizeof(*p) bytes away. This means that &a+1 points to 5*sizeof(int) blocks away, namely, the block after the last element in the array.
Casting &a+1 to int * means that now you want this new pointer to be interpreted as a pointer to int instead of pointer to array of 5 ints. You're saying that, from now on, this pointer references something that is sizeof(int) bytes long, so if you increment it, it will move forward sizeof(int) units.
Therefore, *p is accessing a[5], which is an out of bounds position (one beyond the last), so the program has undefined behavior. It printed 0, but it could have crashed or printed something else. Anything can happen when undefined behavior occurs.
int *p = (int*)(&a+1);
what is *p? :
In your code, *p is a pointer to an unknown element of type int.
Lets reason it out:
&a is a valid pointer expression. An integer can be added to a pointer expression.
Result of &a : points to the whole array a[5]. Its type is int (*)[5]
Result of sizeof *(&a) is 5, which is the size of the array.
Result of &a +1 is pointer expression which holds the address of the 1st int beyond the one &a currently points to.
Hence, 1 object past the &a is what *p points to. Hence it is unknown element of type int. So, accessing unknown element is undefined behaviour. This also answers why your output is zero.
Side Note:
If you really wanted to access the second element in the array, you should add 1 to pointer which points to the first element of array. a points to the first element in the array and size is sizeof(int*).
Result of a+1 is the address of the second element in the array.
Result of *(a+1) is the value of the second element in the array. 2