Here is the code I found on Leetcode. However I cannot make sense of the following two lines, especially *(&a + 1). And the results show a copy of the array a. Could anyone give some explanation to this? Thanks!
int a[5] = {0, 1, 2, 3, 4};
vector<int> v4(a, *(&a + 1));
The examples that you normally face when constructing a vector from an array usually looks like the following:
int a[5] = {...};
vector<int> v4(a, a + 5 );
// or vector<int>(a, a+sizeof(a)/int); // automatically calculate num elems inside a
The example above simply shows you want to construct a vector using all the elements inside array "a". "a" in this example is just the address to the starting element of the array, then you add 5 to get the address of the last element. A more intuitive way to write this would be:
vector<int> v4(begin(a), end(a));
Unless of course you don't want all the elements of a in v4
Now the example you have given us is the shorthand of the first example where you don't need to explicitly state the size of the array.
I'm assuming you are just confused with the second argument of the vector constructor.
The second argument just returns the address of the last element of array "a". But how?
Well let's break it down:
&a returns the address to the "a[]". Essentially a pointer to the array "a". Now if you add one to this address, you will get a pointer to the address "a[0]" + sizeof a[] which will point to the last element of address a. Compare this to the first example above. You had to add 5, why is this not the case here? Well you are working with different units. &a points to the starting address of a[] rather than the address of the first element of the array. So you are essentially moving the address in units of a[5] rather than units of int.
Then finally you have the dereference operator "*" to dereference the pointer and get the address of array[] for the last element.
a is type a[] and &a is type *a[] so the dereference is needed to make it the same type otherwise you get a compiler error.
TLDR: You are getting the address for the last element using different methods. The +1 operator behaves relative to the type you are dealing with. a + 1 is the same as starting address of "a" + sizeof 1 integer. &a + 1 is the same as starting address of a[] + size of a[].
You're getting confused by array decay. a is the array "as a whole". It decays into a pointer pointing to the first element in MOST contexts, but the operand of unary-& is one of the few that it does not. So &a gives you the address of the array as a whole, not the address of the first element. These are the same place, but have different types (int (*)[5] vs int *) and that different type means that pointer arithmetic is different.
Related
I wanted some further understanding, and possibly clarification, on a few things that confuse me about arrays and pointers in c++. One of the main things that confuse me is how when you refer to the name of an array, it could be referring to the array, or as a pointer to the first element, as well as a few other things. in order to better display where my trouble understanding is coming from, I'll display a few lines of code, as well as the conclusion that I've made from each one.
let's say that I have
int vals[] = {1,50,3,28,32,500};
int* valptr = vals;
Because vals is a pointer to the first value of the array, then that means that valptr, should equal vals as a whole, since I'm just setting a pointer equal to a pointer, like 1=1.
cout<<vals<<endl;
cout<<&vals<<endl;
cout<<*(&vals)<<endl;
cout<<valptr<<endl;
the code above all prints out the same value, leading me to conclude two things, one that valptr and vals are equal, and can be treated in the same way, as well as the fact that, for some reason, adding & and * to vals doesn't seem to refer to anything different, meaning that using them in this way, is useless, since they all refer to the same value.
cout<<valptr[1]<<endl;//outputs 50
cout<<vals[1]<<endl;//outputs 50
cout<<*vals<<endl;//outputs 1
cout<<*valptr<<endl;//outputs 1
the code above furthers the mindset to me that valptr and vals are the same, seeing as whenever I do something to vals, and do the same thing to valptr, they both yield the same result
cout<<*(&valptr +1)-valptr<<endl;
cout<<endl;
cout<< *(&vals + 1) -vals<<endl;
Now that we have established what I know, or the misconceptions that I may have, now we move on to the two main problems that I have, which we'll go over now.
The first confusion I have is with cout<< *(&vals + 1) -vals<<endl; I know that this outputs the size of the array, and the general concept on how it works, but I'm confused on several parts.
As shown earlier, if
cout<<vals<<endl;
cout<<&vals<<endl;
cout<<*(&vals)<<endl;
all print out the same value, the why do I need the * and & in cout<< *(&vals + 1) -vals<<endl; I know that if I do vals+1 it just refers to the address of the next element on the array, meaning that *(vals+1)returns 50.
This brings me to my first question: Why does the & in *(&vals+1) refer to the next address out the array? why is it not the same output as (vals+1)in the way that *(&vals)and (vals)have the same output?
Now to my second question. We know thatcout<< *(&vals + 1) -vals<<endl; is a valid statement, successfully printing the size of the array. However, as I stated earlier, in every other instance, valptr could be substituted for vals interchangeably. However, in the instance of writingcout<<*(&valptr +1)-valptr<<endl; I get 0 returned, instead of the expected value of 6. How can something that was proven to be interchangeable before, no longer be interchangeable in this instance?
I appreciate any help that anyone reading this can give me
Arrays and pointers are two different types in C++ that have enough similarities between them to create confusion if they are not understood properly. The fact that pointers are one of the most difficult concepts for beginners to grasp doesn't help either.
So I fell a quick crash course is needed.
Crash course
Arrays, easy
int a[3] = {2, 3, 4};
This creates an array named a that contains 3 elements.
Arrays have defined the array subscript operator:
a[i]
evaluates to the i'th element of the array.
Pointers, easy
int val = 24;
int* p = &val;
p is a pointer pointing to the address of the object val.
Pointers have the indirection (dereference) operator defined:
*p
evaluates to the value of the object pointed by p.
Pointers, acting like arrays
Pointers give you the address of an object in memory. It can be a "standalone object" like in the example above, or it can be an object that is part of an array. Neither the pointer type nor the pointer value can tell you which one it is. Just the programmer. That's why
Pointers also have the array subscript operator defined:
p[i]
evaluates to the ith element to the "right" of the object pointed by p. This assumes that the object pointer by p is part of an array (except in p[0] where it doesn't need to be part of an array).
Note that p[0] is equivalent to (the exact same as) *p.
Arrays, acting like pointers
In most contexts array names decay to a pointer to the first element in the array. That is why many beginners think that arrays and pointers are the same thing. In fact they are not. They are different types.
Back to your questions
Because vals is a pointer to the first value of the array
No, it's not.
... then that means that valptr, should equal vals as a whole, since I'm just setting a pointer equal to a pointer, like 1=1.
Because the premise is false the rest of the sentence is also false.
valptr and vals are equal
No they are not.
can be treated in the same way
Most of the times yes, because of the array to pointer decay. However that is not always the case. E.g. as an expression for sizeof and operand of & (address of) operator.
Why does the & in *(&vals+1) refer to the next address out the array?
&vals this is one of the few situation when vals doesn't decay to a pointer. &vals is the address of the array and is of type int (*)[6] (pointer to array of 6 ints). That's why &vals + 1 is the address of an hypothetical another array just to the right of the array vals.
How can something that was proven to be interchangeable before, no longer be interchangeable in this instance?
Simply that's the language. In most cases the name of the array decays to a pointer to the first element of the array. Except in a few situations that I've mentioned.
More crash course
A pointer to the array is not the same thing as a pointer to the first element of the array. Taking the address of the array is one of the few instances where the array name doesn't decay to a pointer to its first element.
So &a is a pointer to the array, not a pointer to the first element of the array. Both the array and the first element of the array start at the same address so the values of the two (&a and &a[0]) are the same, but their types are different and that matters when you apply the dereference or array subscript operator to them:
Expression
Expression type
Dereference / array subscript expresison
Dereference / array subscript type
a
int[3]
*a / a[i]
int
&a
int (*) [3] (pointer to array)
*&a / &a[i]
int[3]
&a[0]
int *
*&a[0] / (&a[0])[i]
int
I am new to C++ and to programming in general. I got confused when I learnt the concepts of pointer and array.
Takes int*p = arr; int arr[]={5,1}; as an example. I learnt that arr is also a pointer.
p(a pointer) arr[0]
the thing it stores: [first element address: 601] [5]
its memory : 501 601
address(just make
some fake address)
However, arr(the pointer)
[first element address: 601]
601
Normally, a pointer should have a different address from the array. However, the arr, as the pointer to the first element, has the same address as the first element. So I feel confused. And I wonder whether it is because the memory box of arr[0] is split into two parts: one part for arr[0], and one part for the pointer arr, so that they have the same address in memory.
I learnt that arr is also a pointer.
Then you were taught something wrong, which is probably the reason for your confusion.
If you have int arr[] = {5, 1}; then arr is an array, not a pointer. An array can implicitly be converted to a pointer to its first element. But the array itself is still an array. For example, make an int arr[512]; and check what sizeof(arr) is going to be. If arr were a pointer, then that should be the same as sizeof(int*). But it isn't because arrays are not pointers. They are arrays…
If you write
int arr[] = {5, 1, 3};
int* p = arr;
what you end up with is something like this:
arr
+---+---+---+
0xA0: | 5 | 1 | 3 |
+---+---+---+
p
+-------+
0xB0: | 0xA0 |
+-------+
Somewhere in memory, let's say at address 0xA0, there will be an object that is an array of three int. The identifier arr is just a name that denotes this array object in you code. The array object contains three int objects placed one after the other. The individual ints (elements of the array) are subobjects of the complete array object. Note that the address of the complete array object is the same as the address of the subobject that is the first array element. Nevertheless, there is a difference between the array object arr, which is of type int[3] and encompasses the whole array, and the first element, which is of type int.
Also in memory, let's say at address 0xB0, there will be another object of type int*. The identifier p is just a name that denotes this pointer object in your code. p is a completely separate object from arr. It exists at a completely different address. p was initialized to point to the result of the expression arr. The expression arr denotes our array. Pointers and arrays are completely different things. In what way does it make sense to assign an array to a pointer!? What is going on?
To understand why int* p = arr; works and what it does, let's back up a little and think about how we would actually access an element of arr. If we know the address at which array elements start, we can simply compute the address of any element by just adding the element size times the element index. This is precisely how pointer arithmetic works in C++ (which is not a coincidence): given a pointer p to the first element of an array, we can get a pointer to the i-th element by just adding them together: p + i. In fact, the subscripting operator [] for element access such as p[i] is literally defined as just shorthand notation for *(p + i).
Thus, while arrays and pointers are completely different things, arrays only really become useful once pointers enter the picture. Using an array generally requires accessing its elements. Accessing the elements of an array generally requires pointers. Since you generally need a pointer to the first element to really use an array for anything, arrays can implicitly be converted to a pointer to their first element in C and C++.
When you write p = arr what you're really writing is p = &arr[0]. Because, while you cannot assign an array to a pointer, an array of int can implicitly be converted to an int* that points to the first element of the array. And that int* can be assigned to a pointer. And that's why p in our example above will contain the address of the first element of the array (which happens to be the same as the address of the array).
However, since arrays are arrays, not pointers (they just can be converted to a pointer to the first element if necessary), taking the address of an array like &arr will result in a pointer to the array object itself (which, as we have seen, has the same address as the first element). The type of &arr will be int(*)[3] (pointer to array of three int). Unlike &p, which will actually be a pointer to a pointer to int…
Note: When you write arr[2], what you're really writing is *((&arr[0]) + 2) because the [] operator works on pointers. And arrays are not pointers but can implicitly be converted into a pointer to their first element…
I would suggest that pointers are not a beginner topic in C++, they are mostly just a carry over from C. If you can, you should avoid them and use the STL Containers.
In your code sample, the type of arr is int[2]. You should think of that in memory as looking something like this:
arr --+
|
v
+---+---+
| 5 | 1 |
+---+---+
The value contained in arr is the location of the first element (the 5). arr is essentially a pointer to that 5. The only difference being that the type (int[2]) has also remembered how many elements there are.
The assignment statement p = arr works because p's type is int* which int[] can decay to.
Suppose we have that the following 2-dimensional array:
int multi[3][3];
As I understand it, we can then say that multi is a "pointer to a pointer", or -- at the very least -- we can do something like the followiong:
int **p_p_int = multi;
Question: Why don't we say that multi is a "pointer to a pointer to a pointer to pointer", since multi points towards the address of its first element, which itself points to a pointer, which points towards the address of multi[0][0], which itself points to the value of multi[0][0].
This seems to be 4 objects that point (here I'm counting addresses as pointers).
Now you might say "but addresses aren't pointers, even though pointers can equal addresses", in which case it also seems weird to say that a 2-dimensional array is a "pointer to a pointer", since it's actually a pointer to an address to a pointer to an address (to a value).
I feel like I have mananaged to confuse myself quite a bit here :)
A 1d array converts to a pointer rather than being one — e.g. you can reassign a pointer, you cannot reassign an array.
A literal 2d array isn't stored in the way described below.
However a 2d array can be achieved by a pointer to a pointer if:
int **array2d is a pointer. It points to an array. That array contains pointers.
Because array2d points to an array of pointers, array2d[n] is also a pointer. But it's a pointer to an array of integers.
So that's two pointers, total.
In pseudo code, the steps to look up the item at (m, n) are:
add m to array2d to index that array. Read pointer, p from calculated address;
add n to p to index that array. Read integer from calculated address.
The job of a pointer is to point towards something. Just because something is both a pointer and points to something else doesn't make it a pointer to a pointer, unless that something else is a pointer.
So let's break this down:
multi points towards the address of its first element,
That makes it a pointer
which itself points to a pointer,
That makes it a pointer to a pointer.
which points towards the address of multi[0][0],
No. It contains the address of multi[0][0], it doesn't point to it.
which itself points to the value of multi[0][0]
Well, of course. It's a pointer, pointers point to values, that's their job. That doesn't make them pointers to pointers, it makes them pointers to values.
This seems to be 4 objects that point (here I'm counting addresses as pointers).
Sure, but two of those pointings are the very same pointing just counted twice. You say X is a pointer that contains a value that points to something as if that was two separate pointings. The job of a pointer is to have a value that points to something, that's what makes it a pointer in the first place. It's two ways of saying the same thing, "X is a pointer" = "X contains a value (of a type) that points to something".
Saying that multi is a pointer to a pointer is just wrong. It is a 2D array.
multi can not be converted to a ** - only to *
A pointer to pointer would obviously point to a pointer. multi is not doing that. You'll find an integer at that location - not a pointer - simply because multi is not an array of pointers. multi[n] may also be converted to a * but the converted value is not taken from a place where it was stored - it is just calculated from multi.
Don't think of a 2D array like:
int a[3];
int b[3];
int c[3];
int* x[3] = {a, b, c};
cause that is simply not how 2D arrays work.
All pointer values you get from a 2D array are calculated values - not stored values.
I think that there are two unrelated stuff here that you are mixing up:
the name of any array of the type T[][][]...n...[] decayes into T*[][][]...n-1...[] for example:
int arr [7] decayes into int* arr
std::fstream arr[2][2] decays into std::fstream* arr[2]
by decaying, we mean that a function which can get T can also accept T' which T' is the decayed type of T
you can dynamically create psuedo 2 dimentional arrays by using pointer to pointer and dynamic allcoation
int** psuedeo2DimArray = new int*[10];
for (auto i=0U;i<10;i++){
psuedeo2DimArray[i] = new int[10];
}
In all cases, the type of multi is int[2][2] and nothing else.
When implementing a two dimensional array like this:
int a[3][3];
these hold: A=&A[0], at the same time A[0]=&A[0][0]. So, A=&(&A[0][0]), what basically says that A is the address of the address of the first element of the array, which is not quite true. What is my mistake here? Does A really decay to a pointer to a pointer?
Your mistake is that you have an incorrect understanding of the relationship between arrays and pointers. An array is not a pointer. It is an array. However, an array is implicitly convertible to a pointer to its own first element. So, while this expression does evaluate to true:
A == &A[0]
It is not correct to say that A is &A[0]. The conversion does not happen in all expressions. For example:
&A
This does not take the address of the address of the first element of A (that doesn't even make sense). It takes the actual address of A, who's type is int[3][3]. So the type of &A is int(*)[3][3], read as "pointer to array of 3 arrays of 3 ints".
The primary difference between &A and &A[0] is that if you add 1 to &A, you will get an address that is 3 * 3 * sizeof(int) bytes away, while if you add 1 to &A[0], you will get a pointer that is only 3 * sizeof(int) bytes away.
With all this in mind, you should be able to see where your mistake is. A[0] is not &A[0][0], but it is implicitly convertible to it. However, like all conversions, this results in a temporary, which you cannot take the address of. So the expression &(&A[0][0]) doesn't even make sense.
Because of reactions on my previous answer I did some research to learn more on whatever was wrong in my explanation.
Found a rather elaborate explanation of the topic here :
http://eli.thegreenplace.net/2009/10/21/are-pointers-and-arrays-equivalent-in-c
I'll try to summarize :
if you have following :
char array_place[100] = "don't panic";
char* ptr_place = "don't panic";
the way that this is represented in memory is entirely different.
whereas ptr_place is a real pointer, array_place is just a label.
char a = array_place[7];
char b = ptr_place[7];
The semantics of arrays in C dictate that the array name is the address of the first element of the array, which is not the same as saying that it is a pointer. Hence in the assignment to a, the 8th character of the array is taken by offsetting the value of array_place by 7, and moving the contents pointed to by the resulting address into the al register, and later into a.
The semantics of pointers are quite different. A pointer is just a regular variable that happens to hold the address of another variable inside. Therefore, to actually compute the offset of the 8th character of the string, the CPU will first copy the value of the pointer into a register and only then increment it. This takes another instruction [1].
This point is frequently ignored by programmers who don't actually hack on compilers. A variable in C is just a convenient, alphanumeric pseudonym of a memory location. Were we writing assembly code, we would just create a label in some memory location and then access this label instead of always hard-coding the memory value - and this is what the compiler does.
Well, actually the address is not hard-coded in an absolute way because of loading and relocation issues, but for the sake of this discussion we don't have to get into these details.
A label is something the compiler assigns at compile time. From here the great difference between arrays and pointers. This also explains why sizeof(array_place) gives the full size of the array where as the size of a pointer will give the size of a pointer.
I must say, I was not aware of these subtle differences myself, and I have been coding for quite a long time in C and C++ and with arrays too.
Nevertheless if the name of the array element is the address of the first element of the array. You can create a pointer and initialise it what that value
char* p = array_place
p will point to the memory location where the characters are.
to conclude :
There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable, so p=array_place and p++ are legal. But an array name is not a variable; constructions like array_place=p and array_place++ are illegal. That I did know ;-)
Hi I'm new to C and learning about pointers. I'm writing a simple recursive function to test it where it takes parameters int *a and int size. In my main method, I send print_array the address of the first character of my array using the & beforehand.
This doesn't seem to work, I get given an "incompatible pointer types" error at compilation. I understand that I can remove the & and the program works fine. I have a question:
Why can't I pass in the memory address of my_array from main with a &? Shouldn't I be able to just give the function the memory address of first element of array and it can deal with the rest?
Thanks, hope this question wasn't too noob.
#include <stdio.h>
#include <stdlib.h>
void print_array(int *a, int size){
if (size>0){
printf("%d\n", a[0]);
print_array(a+1, size-1);
}
}
int main(void){
int my_array[20];
int i;
for (i=0; i < 20; i++){
my_array[i] = rand() % 20;
}
/*the contents of the array*/
printf("The contents of the array\n");
for (i=0; i < 20; i++){
printf("%d\n", my_array[i]);
}
printf("The recursive method print\n");
print_array(&my_array, 20);
return EXIT_SUCCESS;
}
Yes, you can give the function the address of the first element, and let it deal with the rest. You could do that as either:
print_array(my_array, 20);
...or:
print_array(&my_array[0], 20);
Unfortunately, while &my_array is legal code, it produces a pointer to the entire array, rather than a pointer to the first element of the array. Those have the same address, but different types, which is what's causing the error.
The type of a pointer determines (among other things) how arithmetic on that pointer will work. In your case, print_array prints the first int in the array, then adds one to the pointer. Since it's a pointer to int, that addition actually adds the size of an int to the address in the pointer.
If you used a pointer to the entire array, then adding one would instead add the size of the entire array to the address. For example, let's assume 4-byte ints and that my_array has a base address of 1000. In this case, my_array+1 will yield 1004, so it holds the address of the second int in the array (just as you undoubtedly wanted). By contrast, &my_array will take the address of the entire array, with the type "pointer to array of 20 ints". When you add one to it, that will add 1 * the size of the pointed-to type to the address, so you'll get 1080 (i.e., the entire array is 20 * 4 = 80 bytes). This is obviously not what you wanted--instead of x+1 pointing to the second item in the array, it now points past the end of the array, and attempting to dereference the pointer will give undefined behavior.
So, just switch to one of the forms above (my_array or &my_array[0]). As a more general point, realize that the name of an array evaluates as a pointer to the first element of the array under most circumstances--the notable exceptions being when you use the name of the array as a the operand of either the sizeof operator or the address-of operator (as you did here). In these two cases, the name of the array still refers to the entire array instead of a pointer to the first element.
Your function needs a pointer to an int, specifically the address of the first (0th) element of the array.
By calling print_array(&my_array, 20);, you're trying to pass the address of the entire array, a value of type int(*)[20], which is different than int*. It points to the same memory location, but it's of a different type.
To pass the address of the first element, you can write:
print_array(&my_array[0], 20);
or, equivalently:
print_array(my_array, 20);
The latter works because, in most but not all contexts, the name of an array is implicitly converted to a pointer to its first element.
The relationship between arrays and pointers in C and C++ can be confusing. Recommended reading: Section 6 of the comp.lang.c FAQ
Because arrays automatically decay to pointers, the following was extracted from the n1570 draft
6.3.2 Other operands
6.3.2.1 Lvalues, arrays, and function designators
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. If the array object has
register storage class, the behavior is undefined.