c/c++ pointer to an array vs pointer to a pointer - c++

I thought array and pointer are basically the same thing, until I run this program:
int main() {
int* a = new int(19);
int b[1];
b[0] = 19;
printf("*a: %d\n a: %p\n &a:%p\n", *a, a, &a);
printf("*b: %d\n b: %p\n &b:%p\n", *b, b, &b);
delete a;
}
output is:
*a: 19
a: 0x7f94524000e0
&a:0x7fff51b71ab8
*b: 19
b: 0x7fff51b71ab4
&b:0x7fff51b71ab4
can someone please explain why the output of &b is the same as b?
Thanks!
-Erben

Well, b is an array. Under the slightest excuse it will decay into a pointer to the first element of b. Note, however, that the expression b and &b are not equivalent: b decays into a pointer the first element, i.e., it is of type int* while &b is a pointer to the array, i.e., it is of type int(*)[1].

Arrays and pointers are not the same. A pointer can behave like an array (e.g. accessing by index).
&b is a pointer to the whole array and b is a pointer to the first element. They may point to a same address in memory but they are totally different things.
+-------------------------------+
|+-----+-----+-----+-----+-----+|
|| | | | | ||
&b---->|| 0 | 1 | 2 | ... | N ||
|| | | | | ||
|+-----+-----+-----+-----+-----+|
+---^---------------------------+
|
b

a is a variable. You are allocating memory using new and assigning the result to this pointer. You might decide to store something else in a later in your program.
b is different. It's not a variable in the sense that it cannot store different addresses. It's an array, having a fixed start location.
Thus, b and &b are same. But the contents of a and the actual address of a are different.

Related

Why does this pointer show the last element?

Please explain to me how the b pointer shows the last element.
Every time, it prints out the last element, no matter how long the array is. If you use *b alone in cout, it shows a number out of array.
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
int a[] = {1,2,3,4,5,6,7,8,9,10,11};
int *b =(int*) (&a+1);
cout << *(b-1) << endl;
return 0;
}
This expression
&a+1
has the type int ( * )[11] and points to the memory after the last element of the array a.
In this declaration
int *b =(int*) (&a+1);
you interpreted the expression as having the pointer type int * that points to after the last element of the array a. Instead you could write
int *b = a + 11;
So the expression
b - 1
points to the last element of the array a.
Thus you may imagine the expression *( b - 1 ) the following way
*( a + 11 - 1 ) => *( a + 10 ) => a[10]
Per pointer arithmetic rules, incrementing/decrementing a pointer by N elements will adjust the value of the pointer by N * sizeof(T) bytes, where T is the dereferenced type of the pointer.
&a is a pointer to the array itself, which has a type of int[11], so you have a pointer of type int(*)[11] to the beginning of the array. Lets call this A1 in the diagram below.
Adding +1 to that pointer will advance it by sizeof(int[11]) (aka sizeof(int)*11) bytes, thus producing a new int(*)[11] pointer to the memory address immediately following the entire array. Let's call this A2 in the diagram.
You are then type-casting that new pointer, so now you have a pointer of type int* to the end of the array. This is the memory address you are assigning to your int *b pointer variable. Lets call this B1 in the diagram below.
Subtracting -1 from that pointer will reduce it by sizeof(int) bytes, thus producing a new int* pointer to the memory address of the last int element in the array. Lets call this B2 in the diagram below.
So, when you dereference b to print the int that it is pointing at, you are printing the value of the last int in the array. If you don't decrement b, it is pointing past the end of the array, and you have undefined behavior. You might just print out random garbage, or you might crash your app. Anything could happen.
---------------------------------------------------------------------
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---------------------------------------------------------------------
^ ^ ^
| | |
|_A1 --------------------------------------------------------|----->|_A2
+1 | |
|_B2 <-|_B1
-1

Address of the Pointer pointing to the first element

In http://www.fredosaurus.com/notes-cpp/arrayptr/array-diagrams.html website, it states that
Pointers hold the memory address of other data and are represented by a black disk with an arrow pointing to the data it references.
For example,
int a[5]; // Allocates memory for 5 ints.
. . .
a[0] = 1;
for (int i=1; i<5; i++) {
a[i] = a[i-1] * 2;
}
would result in.
My question is how can I print the address of the pointer pointing to the array?
I know that &a or &a[0] gives us the address of the first element. But how can I access the pointer pointing the array?
An array and a pointer are not the same thing. What the memory really looks like is this:
a
-------
| 1 | a[0]
-------
| 2 | a[1]
-------
| 4 | a[2]
-------
| 8 | a[3]
-------
| 16 | a[4]
-------
So if you were to print a and &a, you would see that they print the same value.
If the array is on the stack as it would be in your example code then the image below is a more accurate representation of how the memory would be laid out. I've also added an additional pointer to hopefully add some clarification.
int a[5];
a[0] = 1;
for (int i=1; i<5; i++)
a[i] = a[i-1] * 2;
int* b = a;
It may be easier to think of the [] notation of defining an array as a little syntactic sugar. When calling functions and passing in a the function will be called with the address of a[0] being passed in.
When passing b to a function it's the value that will be passed in, which is the address of a.
You can have lots of pointers pointing to a[0].
Just as for a pointer to the array, create a pointer variable pointing to a[0] and then take a pointer to it. You will have one pointer to one pointer pointing to the array.
I know that &a or &a[0] gives us the address of the first element.
Technically. &a is in fact the address of the array itself. It just has the same value as address of the first element. But note that the type of the expression is different. &a is a int (*)[5] (pointer to an array of 5 integers), while &a[0] is a int* (pointer to an integer).
My question is how can I print the address of the pointer pointing to the array?
First step is to have a pointer. You don't have any pointer variables in your example. An array is not a pointer. The sentence "The actual array variable, a in this example, is a pointer to the memory for all of its elements." of the page is very misleading, as an array is not a pointer object. The drawn diagram is not correct for the program.
Here is a program that is correct according to the diagram:
int array[5]; // Allocates memory for 5 ints.
int* a = array; // a pointer to the first element of the array
a[0] = 1;
for (int i=1; i<5; i++) {
a[i] = a[i-1] * 2;
}
Here we actually have a pointer. Now you can print the address of the pointer:
std::cout << &a;

Why do a[] and *a behave differently?

I thought a[] and *a are the same thing because they work like pointers. Yet I encountered something unexpected in the following code:
#include <iostream>
using namespace std;
class F {
public:
bool a[];
F();
};
F::F() {
*a = new bool[5];
a[2] = true;
}
int main() {
F obj;
if(obj.a[2])
cout << '?';
return 0;
}
This code prints ?, but I don't understand how it works. When:
*a = new bool[5];
is changed into:
a = new bool[5];
compiler reports:
F:\main.cpp|11|error: incompatible types in assignment of 'bool*' to 'bool [0]'|
I found this behaviour weird, so I was playing around with this code. When I changed the type of a from bool to int compiler always reports an error
F:\main.cpp|11|error: invalid conversion from 'int*' to 'int' [-fpermissive]|
Why does this work the way it does?
I thought a[] and *a are the same thing because they work like pointers.
Let's talk about this piece of declaration:
int a[4] = { 1, 2, 3, 5 };
int *b = NULL;
This is how they land in memory in the executable:
+----+----+----+----+
a: | 1 | 2 | 3 | 5 | <-- 4 integers
+----+----+----+----+
+----------+
b: | NULL | <-- 1 pointer that points to nowhere
+----------+
As you can see, they are not the same thing.
What happens after b = new int[4];?
The new memory layout of b is something like this:
+----------+
b: | 0xacf3de | <-- 1 pointer that points to a block of 4 integers
+----------+
Somewhere else in memory (at address 0xacf3de)...
+----+----+----+----+
0xacf3de: | ? | ? | ? | ? | <-- 4 integers
+----+----+----+----+
But wait, somebody told me that arrays work like pointers...
No, that's not true. The arrays do not work like pointers.
An array name (a, f.e.) can be used as a shortcut for its address in memory (which is, in fact, the address of its first element). The following notations are equivalent:
a
&a
&a[0]
The value of all of them is the address in memory where the first element of a (the 1 in the example above) is stored.
a[0] is an int, &a[0] is an int *. This is the complete form. The other two are shortcuts that the language provides in order to make the code easier to read and understand.
The things are different for pointers.
b is the value stored in the b variable (NULL or 0xacf3de in the example above. It is a value of type int * -- the address in memory where an int is stored. &b is the address in memory where (the value of) b is stored. Its type is int ** -- a pointer to a pointer to an int; or "the address in memory where is stored the address of an int".
But wait, they can be replaced one for another in some contexts
Up to some point, yes, a pointer and an array are interchangeable. As you can see above, there is a common data type involved: int *. It is the type of b (which stores the address of an int) and also the type of &a[0] (which is also the address of an int).
This means that where b can be used, a (a short of &a[0]) can be used instead, and vice-versa.
Also, where *b can be used, *a can be used instead. It is the short for *&a[0] and it means "the value (*) stored at the address (&) of a[0]" and it is, in fact, the same as a[0].
But, where &b can be used, &a cannot be used instead; remember that &a is the same as &a[0] and its type is int * (but the type of &b is int **).
The line:
*a = new bool[5];
is equivalent to:
a[0] = new bool[5];
You are not initialiazing your array, but allocating an array of bool which is then implicitly converted into bool to be assigned to a[0]: the value should be true since the pointer returned by new should be different from 0. This implicit conversion does not apply with ints: that is why you are getting an error when changing the type of a.
Now, considering this line:
a = new bool[5];
Here you are trying to assign your dynamically allocated array to a, in other words assigning a pointer to an array bool* to a static array bool[0]: as the compiler says, the types are incompatible. A static array a[] can be used as a pointer, e.g. in the following code:
int foo(bool* a) { /* ... */ }
bool my_array[5];
foo(my_array);
But pointers can not be converted into static arrays as you are trying to do.
Type of value returned from new Type[x] is Type * i.e pointer of that type
examle:
So Right syntax is
bool a;
*a = new bool[x];
so it is wrong to do like is
a=new bool[x] wrong syntax as it is invalid to assign pointer to a normal varibale
see for more details

Why do the following have the same value: the pointer to an array, the dereferenced pointer to the array?

For instance,
int array[5] = {1}: // array of 5 integers
int (*ptr)[5] = &array; // pointer to an array of 5 integers
The following have the same value:
*ptr;
ptr;
If I were to call printf("%p, %p", *ptr, ptr); both outputs would be exactly the same. Why is this?
In this statement
int (*ptr)[5] = &array;
pointer ptr is initialized by the address of the array. The address of the array is the address of its first element that is of the first row.
Expression
*ptr;
gives you reference to this first element that is to the one-dimensional array - the first row or more precisely to the original array..
In turn in expressions arrays are converted to pointers to their first elements and *ptr that is equivalent to expression array is converted to rvalue of type pointer that points to the first element of array *ptr.:)
That is expression *ptr will have type int *
The address of the first row and the address of the first element of the first row is the same.
Now you have two pointers, ptr and *ptr the first one has type int ( * )[5] while the second one has type int * but the both have the same value.
If you look at the memory layout of a 1D array such as
int array[5];
it will make sense.
array
|
V
+---+---+---+---+---+---+
| | | | | | |
+---+---+---+---+---+---+
array[0]
|
V
+---+---+---+---+---+---+
| | | | | | |
+---+---+---+---+---+---+
Address of array
|
V
+---+---+---+---+---+---+
| | | | | | |
+---+---+---+---+---+---+
Address of array[0]
|
V
+---+---+---+---+---+---+
| | | | | | |
+---+---+---+---+---+---+
i.e. &array == &array[0] == array decayed to a pointer
With a pointer declared as:
int (*ptr)[5] = &array;
ptr == &array
*ptr == array decayed to a pointer == &array[0] == &array
That's why you see the same value printed when you use:
printf("%p, %p", *ptr, ptr);
Since printf is a variadic function, the ellipsis conversion sequences are applied to the arguments. In particular, arrays are decayed to a pointer of the underlying type : IOW, it is implicitly converted to a pointer to the first element of the array. Thus, when you call printf("%p, %p", *ptr, ptr);, *ptr, which is of type int[5] is converted to an int* with value &array[0].

Pointers to pointer

Hello guys can someone explain why while declaring pointers to pointer we need to use ** why cant we use only single * to point a pointer to another pointer or is it just a syntax related issue E.g
int main()
{
int a=5,*b,*c;
b=&a;
c=&b //Why cant this simply doesn't make c point to memory location of b with the above pointer declaration why is there a need to declare c as **c
}
With the following codes:
int a=5,*b,**c;
b=&a;
c=&b;
We have:
+---+
a | 5 | <-- value
+---+
|100| <-- address
+---+
+---+
*b |100| <-- value
+---+
|200| <-- address
+---+
+---+
**c |200| <-- value
+---+
|300| <-- address
+---+
When you store a's address in b, b's value is a's address. But b has it's own address (200).
c can store b's address as it's value. But c has it's own address too (300).
printf("%x", &c); will give you: 300
Deferencing *c will get you down "1 level" and give you 100 (get value of address 200)
Deferencing **c will get you down 1 more level and give you 5 (get value of address 100)
If you try to use *c instead of **c to hold *b, how are you able to deference all the way down to reach value 5?
Testing the codes on a compiler:
printf("Address of a: %x\n", &a);
printf("Address of b: %x\n", &b);
printf("Address of c: %x\n", &c);
printf("Value of a: %d\n", a);
printf("Value of b: %x\n", b);
printf("Value of c: %x\n", c);
Output:
Address of a: 28ff44
Address of b: 28ff40
Address of c: 28ff3c
Value of a: 5
Value of b: 28ff44
Value of c: 28ff40
In this case
int main()
{
int a=5,*b,*c;
b=&a;
c=&b;
}
Here b points to a and c points to b. It is what you have commented in the commented.
c still points to the memory location of b.
The catch is : When you de-reference b i.e *b = a = 5.
But When you de-reference c i.e *c = b = &a. So When you dereference c the output would be address of a instead of the value of the variable a
PS : you will face this warning when compiling the code warning: assignment from incompatible pointer type
Every level of indirection needs a level of dereferencing. So for:
T*** x = ...;
you would need:
***x
to get to T&.
If you had a pointer to pointer and you saved it in:
T* x = ...;
T* y = &x;
it would mean that *ptr leads to T&, while it really leads to another T*.
You have your answer in your question only.
pointer to variable , use of *
pointers to pointer of a variable , use **
Details:
** is not a new operator. it's a combination of * and *. In case 2. as per your terminology, you can think of
only single * to point a pointer to another pointer
as in
int * to an inother int * ==> int **
EDIT:
as per your code
int main()
{
int a=5,*b,*c;
b=&a;
c=&b;
}
b is a pointer to int. You can store the address of int there, and a is an int. Perfect.
c is a pointer to int. You can store the address of int there, and b is a pointer to int. Not accepted.
To make point 2 work, you need to declare c as a pointer to int *, right? The notation for the same is int **.
Here's another way to think of pointers-to-pointers: imagine how it works in memory. Here's a little snippet that shows what I mean:
int TheInteger = 123;
int *p = &TheInteger;
int **pp = &p;
printf("The value at memory location &pp (0x%x) is 0x%x (pp). This value (which we assigned as &p (0x%x) is 0x%x (p). This value, in turn, we assign as &TheInegeter (0x%x) points to the 'instance' of TheInteger, which is %d", &pp, pp, &p, p, &TheInteger, TheInteger);
The output of this would be:
The value at memory location &pp (0x657e588) is 0x657e594 (pp). This value (which we assigned as &p (0x657e594) is 0x657e5a0 (p). This value, in turn, we assign as &TheInegeter (0x657e5a0) points to the 'instance' of TheInteger, which is 123
Now, to go back to your original question, you cannot declare a variable as being a pointer when the value you're setting it to is a pointer-to-a-pointer. In other words, in your example, you set 'b' as a pointer to a -- so, you can't tell the compiler that 'c' is just a pointer and then try to set it to a value that the compiler knows is a pointer-to-a-pointer.