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

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]);

Related

Array of pointers to an array of pointers to int

If i have array of pointer to an array of pointer to int
int **arrs = new int *[n];
and assign each element to new array of pointer to int
for i<n
arrs[i] = new int[size]
Now, when i try to get size of these arrays, give me wrong value
int size = sizeof(arrs[0])/sizeof(int);
It gives me wrong value.
So how can i get the right value ?
You can't. arrs[0] is a pointer, so sizeof(arrs[0]) gives the size of that pointer.
It comes as a surprise to some that there is no way to get the size of an array from only a pointer to that array. You have to store the size somewhere else.
In C++ the simplest and best solution is to use std::vector. Why reinvent the wheel? std::vector has everything you would want from a dynamic array, and should be the first choice in this situation.

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.

What is the fastest way to obtain an index from a pointer of an array element in C++?

Suppose you have a pointer to an int from an array. Is this the best way to find out which item of the array the pointer points to?
int nmbr = pointer - &array[0];
cout<<"Item number "<<nmbr+1;
If the pointer pointed to the 6th item, would this always print "Item number 6"? Is this error-prone? Is there a faster way to do it? Iterating over the array won't work because of possible duplicate values, but does this always work? In this situation we assume the array starts from item 0 to item x. Is there a situation in which an array's items aren't stored in a continuous line (if the array was initialized as int array[x];)?
Assuming pointer is known to point at an element of array, the
std::ptrdiff_t nmbr = pointer - array;
will do it. If pointer does not point at an element of the array, the behaviour is undefined. std::ptrdiff_t is declared in the standard header <cstddef>, and is an implementation-defined signed integral type. Using int is not a good idea, particularly for large arrays, since std::ptrdiff_t may be able to represent a larger range of values than an int (and, if the value is larger than an int can represent, converting the result to int also gives undefined behaviour).
The +1s in your code are incorrect, since array indexing in C++ is zero based.
All arrays, in the sense of something declared as
some_type array[some_positive_value];
have contiguous elements. Note that C++ does not support C's VLAs (variable length arrays) i.e. some_positive_value must be known at compile time.
As mentioned by XTF, yes it is guaranteed to work. There is however, no need for taking the address of the 0'th element, just use array as it is.
For a more generic solution, that will also work on other containers you could consider the following examples:
#include <iostream>
#include <iterator>
#include <array>
int main()
{
{
int array[10];
int * p = &array[5]; // Somehow get a pointer to the sixth element
std::cout << std::distance(std::begin(array), p) << std::endl;
}
{
std::array<int, 10> array;
int * p = &array[5]; // Somehow get a pointer to the sixth element
std::cout << std::distance(std::begin(array), p) << std::endl;
}
}
Both +1's look wrong..
But yes, this is the fastest and simplest way. It's guaranteed to work.

Pointer to 2D Array(why does it work)

I have the following function ( I want to print all elements from a given row)
void print_row(int j, int row_dimension, int *p)
{
p = p + (j * row_dimension);
for(int i = 0; i< row_dimension; i++)
cout<<*(p+i)<< " ";
}
Creating an array
int j[3][3]={{1,2,3},
{4,5,6},
{7,8,9} };
What I do not understand is why can I call the function in the following way :
print_row(i, 3, *j);
Why can I give as a parameter "*j" ? Shouldn't an address be passed? Why can I use the indirection operator?
int j[3][3] =
{{1,2,3},
{4,5,6},
{7,8,9}}; // 2d array
auto t1 = j; // int (*t1)[3]
auto t2 = *j; // int *t2
So what is happening is that *j produces j[0], which is an int[3] which then decays to an int*.
j is in fact an array of arrays. As such, *j is an array of three integers, and when used as a rvalue, it decays to a pointer to its first element, said differently, it decays to &j[0][0].
Then in printrow you compute the starting address of the first element of each subarray - that's the less nice part, I'll come back later to it. Then you correctly use the *(p+i) equivalent of p[i] to access each element of the subarray.
The remaining part of the answer is my interpretation of a strict reading of C standard
I said that computing the starting address of each subarray was the less nice part. It works because we all know that a 2D array of size NxM has the same representation in memory as a linear array of size N*M and we alias those representations. But if we respect strictly the standard, as an int pointer, &p[i][j] points to the first element of an array of three elements. As such, when you add the size of a row, you point past the end of the array which leads to undefined behaviour if you later dereference this address. Of course it works with all common compilers, but on an old question of mine, #HansPassant gave me a reference on experimental compilers able to enforce controls on arrays sizes. Those compilers could detect the access past the end of the array and raise a run time error... but it would break a lot of existing code!
To be strictly standard conformant, you should use a pointer to arrays of 3 integers. It requires the use of Variable Length Arrays, which is an optional feature but is fully standard conformant for system supporting it. Alternatively, you can go down to the byte representation of the 2D array, get its initial address, and from there compute as byte addresses the starting point of each subarray. It is a lot of boiling plate address computations but it fully respect the ##!%$ strict aliasing rule...
TL/DR: this code works with all common compilers, and will probably work with a lot of future versions of them, but it is not correct in a strict interpretation of the standard.
Your code works because *j is a pointer which has the same value as j or j[0]. Such behavior caused by mechanics of how two-dimensional arrays are handled by the compiler.
When you declare 2D array:
int j[3][3]={{1,2,3},
{4,5,6},
{7,8,9}};
compiler actually puts all values sequentially in memory, so the following declaration will have the same footprint:
int j[9]={1,2,3,4,5,6,7,8,9};
So in your case pointers j, *j and j[0] just point to the same place in memory.
Memory isn't multidimensional, so even if its a 2D array, it's data will be placed in a sequential manner, so if you get a pointer to that array -- that is implicitly a pointer to the first element of it -- and start reading the elements sequentially, you will iterate through all elements of this 2D array, reading element from the subsequent rows just after the last element of the previous one.

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.