Why doesn't (&array)[i] take the address of the ith element? - c++

Consider the following code
int tab2[2];
tab2[0]=5;
tab2[1]=3;
std::cout << tab2[1] << std::endl;
std::cout << (&tab2)[1] << std::endl;
As I have read in other topics, an array can decay to pointer at its first element. Then why doesn't the [] doesn't work the same for tab2 and &tab2 in the above code? What is different?

It's already "converted" as a pointer. You can use the [] notation with arrays or pointers...
(&tab2) means you get the address of your array... In a pointer perspective, it's a pointer to a pointer ( ** ).
So you are trying to convert a variable (which is an array) as a pointer. Ok, but then you try to access the [1] element, which of course does not exist, as your pointer points to your array's address... Such a notation would expect a second array.

This expression:
(&tab2)[1]
Gets you a pointer to an array of 2 ints. Then uses array syntax on that pointer-to-an-array to get you the 1st 2 element int array after tab2.
So you have in memory
tab2
0 1 // index into tab2
5 3 // values
You get a pointer to the array
0 1
&tab2 -> 5 3
Then you go 1 array of 2 ints past tab2
0 1 2 3
&tab2 -> 5 3 ? ?
/|\
(&tab2)[1]

When you use (&tab2), you are retrieving the address of your array. Your statement itself answers your question.
Had you used (*(&tab2)), you would have got what you were expecting as output - 3.

What you've done by adding address-of (&) to tab2 is given yourself the memory address of the tab2 pointer, or a pointer to a pointer (int**). So logically, yes, indexing it makes sense. However, &tab2 is not the same as tab2. &tab2 points to the pointer itsefl, while tab2 points to the array. By indexing &tab2 with 1, you've told it to look at the next element in sequence, which doesn't exist (or it does exist, but belongs to another variable). Had you indexed it with 0, this would have been fine as you would be looking at the "root" of the memory sequence.
Indexing just tab2 is fine as well obviously, because it points to an array.

Related

Unable to understand what is happening in a two-dimensional array pointer

I am a newbie to pointers and am facing some problems while trying to understand them.
Now I looked up this problem over here. I was not 100% satisfied with the solution. So I did some checking on my own to see what happens.
I wanted a pointer to a two-dimensional array so I tried:
int arr[2][3] = {{12,23,4},{323,43,3}};
int (*ptr)[3] = arr; // A pointer to the first element of array.
// The first element of array is an array of three ints.
I ran the following code:
std::cout<<ptr<<std::endl;
std::cout<<*ptr<<std::endl;
Now the results I got were a bit confusing for me:
0x61fdc0
0x61fdc0
Both times the same output is shown. How can the address of the pointer and value after the referencing be the same? Is this behavior similar to double pointers? An explanation like this will be very helpful.
Arrays can decay to pointers. Actually you used that fact when you wrote:
int (*ptr)[3] = arr;
ptr is "a pointer to the first element of array". The 2D array arr did decay to a pointer to its first element when you used it to initialize ptr.
When you dereference ptr you get the first element (of arr), a one-dimensional array, and when you print it via
std::cout << *ptr << std::endl;
you get its address printed, because the array decays to a pointer to its first element.
As the answer you link explains, the address of an array and the address of its first element are identical:
The following are equivalent ways to point to the first of the two
items.
int (*p)[3] = a; // as before
int (*p)[3] = &(a[0]);

H­ow d­oes List::in­sert w­ork with a­rr­a­ys­

I am on youtube looking over tutorials. One had a block of code using the list library as such:
int arr1[5]{ 1,2,3,4,5 };
list<int> list1;
list1.insert(list1.begin(), arr1, arr1 + 5);
My question is, how can one use an array like this? Last I checked, arr1 is an array not a pointer that you use to loop through elements. How does the insert function work?
When an array is used by name, it's name references to first element of the array. For an array arr whenever you say arr[x], [] is defined in terms of pointers. It means start at a pointer referencing arr and move x steps ahead. A size of each step is the sizeof datatype your array is made up of. Thus,arr[x] can also be written as *(arr + x), dereferencing the pointer after x steps.
Now speaking of your list insertion, it means copy all the elements between pointers arr and arr + 5 to the list.
arr1 can be used as a pointer to the beginning of the array, because it gets converted automatically.

Get the size of the array by reference

I created a vector of pointers to an array
vector<PxVec3*> gConvexMeshVertexesArrays;
I added a link to the array with elements
static PxVec3 convexVerts[] = {
PxVec3(-0.000000, 1.295039, -5.117647),
PxVec3(-9.881939, 10.235294, 5.235294),
PxVec3(-10.117647, 10.235294, 5.235294)
}
Then I try to get the size of this array
cout << "in = " << sizeof(convexVerts) / sizeof(PxVec3) << endl; //ok
gConvexMeshVertexesArrays.push_back(convexVerts);
cout << "in2 = " << sizeof(*(gConvexMeshVertexesArrays.back())) / sizeof(PxVec3) << endl; //wrong!
How can I make the second option work correctly? After all, back() returns a reference to the pointer and the size of the array I can't get from the reference.
Thanks.
There is no way to know the size of some memory a pointer may be pointing to because pointers have no information about what data they are pointing to (except the declared type, that is).
If you want a (pointer, size) pair, take a look at std::span in C++20 and similar types provided in some libraries.
The well-known sizeof(array) / sizeof(element) expression works for arrays (and it does so at compile-time) because arrays statically know their entire size (plus they are contiguous, etc.).
I created a vector of pointers to an array
vector<PxVec3*> gConvexMeshVertexesArrays;
You've created a vector of pointers to PxVec3, which I assume is not an array. Those pointed PxVec3 objects may be elements of an array though.
cout << "in2 = " << sizeof(*(gConvexMeshVertexesArrays.back())) / sizeof(PxVec3) << endl; //wrong!
How can I make the second option work correctly?
This would work, if you actually did have a vector of pointers to an array:
std::vector<PxVec3(*)[3]> gConvexMeshVertexesArrays;
This way, indirecting through the pointer to array, you get an lvalue reference to the array itself, and you can get the size of that array the same way as you'd get it from the array directly as you are attempting here.
If you instead have a pointer to an element of an array, as you do in the example, then there is no general way to get the size of the array that contains the element from that pointer.
In some particular cases, there may be a way to calculate the size however. For example, you could decide that certain value represents the end of the array, in which case you can iterate the successive sibling of the pointed object until you reach the terminator. This is conventionally done with character strings where the null terminator character represents end of a string.
In case you want to store a pointer to an element of an array, and want to know the size and cannot choose a value as terminator, then you would typically store the size along with the pointer.
gConvexMeshVertexesArrays.push_back(convexVerts);
I successfully add a pointer to an array to the vector and then try to get the size of that array.
No, you don't. You push a pointer to the first element of an array into the vector. Then you get the size of the array element (whether you intended that or not), which you divide by the size of the element, which always results in 1.

Pointer to an Element of a Vector

If I have a pointer that is pointing to an element in a vector, say element 2, and then that element gets swapped with element 4 of the same vector. Is the pointer now pointing to element 2, element 4, or neither? Example:
vector a is equal to [1,2,3,4,5]
create pointer that points to the element 2, which is equal to 3 in this case
swap elements 2 and 4
vector a is now [1,2,5,4,3]
where is the vector pointing to?
You mean, "where is the pointer pointing to?". If that's the case, it'll point to the same location in memory as before which is now occupied by the value 5.
Also, by swapping I assume you meant swapping the values between two locations.
Why?
Simply because your pointer points to a memory location. What's stored there doesn't matter --- it could be a value, or it could be garbage. When you dereference it (to see what the value is) it will return the value stored at that location.
Since you've swapped the values, the value at that location is 5 not 3 hence, the pointer is still pointing to the same location and is unchanged but the value at the location has changed.
Sample Code:
// Create the vector
int a[] = {1,2,3,4,5};
int* ptr = &a[2];
// Display original status
std::cout<<"Original Value: "<<*ptr<<std::endl;
std::cout<<"Address: "<<ptr<<std::endl;
// Swap values
std::swap(a[2],a[4]);
// Check
std::cout<<"New Value: "<<*ptr<<std::endl;
std::cout<<"Address: "<<ptr<<std::endl;
Note:
I've used an array of integers in the example but if by vector you meant std::vector, the same will hold assuming no reallocation has taken place (check out this SO answer).

Creating arrays on the heap and addressing them with pointers

I'm having trouble understanding the following bit of code that I was hoping would create an array on the heap and fill it with the characters 9 down to 0 (I know I could just index the array like a normal stack array with [] notation to do this but I'm doing it this way to try to understand pointers in more depth):
int *ptrHeapArray = new int[10];
for(int f=9; f>=0 ;f--)
{
*ptrHeapArray = f;
ptrHeapArray++;
}
for(int f=0; f<10; f++)
cout << ptrHeapArray[f] << "\n";
It prints out compleletly unexpected values.
As I understand the above, the 'new' command creates an array on the heap and sends me back a pointer to the address where the array is. Since the pointer I assign (ptrHeapArray) is of int size I assumed I could use pointer post incrementing to navigate through the array. However the results indicate that my assumptions are wrong.
This got me to thinking that perhaps the pointer passed back by the 'new' keyword is just a pointer to the whole array and can't be used to step through the array for some reason.
So I tried creating another pointer to the pointer returned by the 'new' keyword and used that to do my array population:
int *ptrHeapArray = new int[10]; //array to hold FRANK data in 32 bit chunks
int *ptrToHeapArrayPointer = ptrHeapArray;
for(int f=9; f>=0 ;f--)
{
*ptrToHeapArrayPointer = f;
ptrToHeapArrayPointer++;
}
for(int f=0; f<10; f++)
cout << ptrHeapArray[f] << "\n";
This worked fine.
Can anyone explain to me why I had to do this and couldn't just have used the pointer passed backed to me by the 'new' keyword?
Thanks
The line
ptrHeapArray++;
in your first for loop increments the pointer, such that it doesn't point to the beginning of the array anymore.
The line
int *ptrHeapArray = new int[10];
allocates the memory for 10 integers and points ptrHeapArray to the beginning of that memory. In your for loop you then move this pointer. When ptrHeapArray points to the third of the integers:
[0] [1] [2] [3] [4]
^ ^ ^
orig. | |
| +-- ptrHeapArray[2]
|
+-- ptrHeapArray now points here
then ptrHeapArray[2] would give you the integer at the position orignally numbered with 4.
You are modifying the pointer in code. After the first loop in the first snippet, the pointer will point to the end of the array rather than the beginning. To make things clearer, this would work too (not suggested but demonstrates the behavior):
int *ptrHeapArray = new int[10];
for(int f=9; f>=0 ;f--)
{
*ptrHeapArray = f;
ptrHeapArray++;
}
ptrHeapArray -= 10; // reset the pointer to its original location
for(int f=0; f<10; f++)
cout << ptrHeapArray[f] << "\n";
Your ptrToHeapArrayPointer is misnamed, it is just a standard int ptr that you've pointed to the same place as ptrHeapArray. If you renamed it to currentPositionPtr your code might make more sense to you.
When you do ptrHeapArray++ it inscrements ptrHeapArray. When you come to print out the data ptrHeapArray no longer points to the start of the array.
The problem is that in your first example ptrHeapArray is initially set to the beginning of the array. As you iterate through your loop you are incrementing the pointer, and by the end of the for loop you are pointing to the last element in the array. When you go through the for loop to display all of your values, you are indexing to values past the end of the array since ptrHeapArray is pointing to the last element in the array you allocated.
It is also important to remember, that you should probably make sure not to loose the original pointer you got back from using the new operator so that you can properly free up the memory that was allocated on the heap.
In the first loop you incremented your pointer ptrHeapArray until the end of array. So after executing the first for loop your pointer is pointing to end of the array and not at the beggining. Hence, when you are trying to print the contents of the array, you are accessing invalid memory allocations and the behavior will be unexpected. In the second case, you are taking a copy of your starting address before assigning values to the array. So when you try to print the contents using the copy, it will be pointing to the beginning of the array.