Behavior of 2D arrays - c++

I have created a 2D array, and tried to print certain values as shown below:
int a[2][2] = { {1, 2},
{3, 4}};
printf("%d %d\n", *(a+1)[0], ((int *)a+1)[0]);
The output is:
3 2
I understand why 3 is the first output (a+1 points to the second row, and we print its 0th element.
My question is regarding the second output, i.e., 2. My guess is that due to typecasting a as int *, the 2D array is treated like a 1D array, and thus a+1 acts as pointer to the 2nd element, and so we get the output as 2.
Are my assumptions correct or is there some other logic behind this?
Also, originally what is the type of a when treated as pointer int (*)[2] or int **?

When you wrote expression
(int *)a
then logically the original array can be considered as a one-dimensional array the following way
int a[4] = { 1, 2, 3, 4 };
So expression a points to the first element equal to 1 of this imaginary array. Expression ( a + 1 ) points to the second element of the imaginary array equal to 2 and expression ( a + 1 )[0] returns reference to this element that is you get 2.

Are my assumptions correct or is there some other logic behind this?
Yes.
*(a+1)[0] is equivalent to a[1][0].
((int *)a+1)[0] is equivalent to a[0][1].
Explanation:
a decays to pointer to first element of 2D array, i.e to the first row. *a dereferences that row which is an array of 2 int. Therefore *a can be treated as an array name of first row which further decay to pointer to its first element, i.e 1. *a + 1 will give the pointer to second element. Dereferencing *a + 1 will give 1. So:
((int *)a+1)[0] == *( ((int *)a+1 )+ 0)
== *( ((int *)a + 0) + 1)
== a[0][1]
Note that a, *a, &a, &a[0] and &a[0][0] all have the same address value although they are of different types. After decay, a is of type int (*)[2]. Casting it to int * just makes the address value to type int * and the arithmetic (int *)a+1 gives the address of second element.
Also, originally what is the type of a when treated as pointer (int (*)[2] or int **?
It becomes of type pointer to array of 2 int, i.e int (*)[2]

A 2D-array is essentially a single-dimensional array with some additional compiler's knowledge.
When you cast a to int*, you remove this knowledge, and it's treated like a normal single-dimensional array (which in your case looks in memory like 1 2 3 4).

The key thing to recognize here is that the a there holds the value of the address where the first row is located at. Since the whole array starts from the same location as that, the whole array also has the same address value; same for the very first element.
In C terms:
&a == &a[0];
&a == &a[0][0];
&a[0] == &a[0][0];
// all of these hold true, evaluate into 1
// cast them if you want, looks ugly, but whatever...
&a == (int (*)[2][2]) &a[0];
&a == (int (*)[2][2]) &a[0][0];
&a[0] == (int (*)[2]) &a[0][0];
For this reason, when you cast the a to int *, it simply becomes 1-to-1 equivalent to &a[0][0] both by the means of type and the value. If you were to apply those operations to &a[0][0]:
(&a[0][0] + 1)[0];
(a[0] + 1)[0];
*(a[0] + 1);
a[0][1];
As for the type of a when treated as a pointer, although I am not certain, should be int (*)[2].

Related

C++, static array, pointer, length

Can somebody explain to me why this code works?!!
I know A holds &A[0] and it is not a real pointer as if you cout<<&A you would get &A[0], but this result looks very strange to me.
int main()
{
double A[] = {2.4, 1.2, 4.6, 3.04, 5.7};
int len = *(&A+1) - A; // Why is this 5?
cout << "The array has " << len << " elements." << endl;
return 0;
}
And why this code doesn't work? And how can you make it work?
void test(double B[])
{
int len = *(&B+1) - B;
cout << len << endl;
}
int main()
{
double A[] = {2.4, 1.2, 4.6, 3.04, 5.7};
test(A);
system("pause");
return 0;
}
The expression is parsed like this:
(*((&A) + 1)) - A
The probably vexing part is that for some (but not all!) parts of this expression, the array decays to a pointer to the first element. So, let's unwrap this:
First thing is taking the address of the array, which gives you a pointer to an array of five elements.
Then, the pointer is incremented (+ 1), which gives the address immediately following the array.
Third, the pointer is dereferenced, which yields a reference to an array of five elements.
Last, the array is subtracted. It is only here that the two operands actually decay to a pointer to their first elements. The two are the length of the array apart, which gives the number of elements as distance.
&A takes the address of A itself. The type of A is double[5].
When you take the address of A itself and increment that pointer by 1, you are incrementing it by sizeof(double[5]) bytes. So now you have a pointer to the address following the A array.
When you dereference that pointer, you have a reference to the next double[5] array following A, which is effectively also a double* pointer to the address of A[5].
You are then subtracting the address of A[0] (an array decays into a pointer to its first element), and standard pointer arithmetic gives you 5 elements:
&A[5] - &A[0] = 5

How does int (*p)[10] work? [duplicate]

This question already has answers here:
How do I use arrays in C++?
(5 answers)
Closed 6 years ago.
C++
int arr[5] = {1, 2, 3, 4, 5};
int (*p)[5] = &arr;
I know p is a pointer which points to an array with 5 elements, but when I try to print the address:
cout << p << " " << *p << " " << &arr << endl;
It gives me:
0x7fff50c91930 0x7fff50c91930 0x7fff50c91930
Question:
How could p equals *p? And now that p equals to &arr, why *p != arr[0]? What exactly does the value p and *p hold?
It would be more clear to imagine that p points to the whole memory block of 5 int. So if there is a ( p + 1 ) it would point to the next memory block.
This then help answer your questions.
How could p equals *p?
p is pointer to array[5] that is initialized to point to arr[5]
*p is the value of the first array element - which is the address of arr[5]. And because the name of the array is the address of the first element. So when you print p and *p they are the same.
And now that p equals to &arr, why *p != arr[0]?
*p is the address of the first array element - which means the address of the whole arr[5] memory block. On the other hand, arr[0] is the first element of the array that p points to, so it's a real value (1) not an address.
What exactly does the value p and *p hold?
As your first question, both of them hold the address of the whole arr[5] memory block.
first of all
'int' this is int type
'int*' this is int pointer type
so
int arr[5] = {1, 2, 3, 4, 5};//declare and initialize array of five integers
int* p[5] ;//declare array of five integer pointers
pointers store only a reference. when we de-reference it by using * it gives the actual value stored at that reference.
int* is a type and only * is a operator(de-reference operator)
int (*p)[5] = &arr;// by doing this you are declaring array of five integer pointers and each pointer is initialing with starting reference of arr.
to get the values of arr by using integer pointer you can use
p[0][0]//1
p[0][1]//2
and so on
and same goes for pointers p[1], p[2] and so on
The name of an array usually evaluates to the address of the first element of the array, but there are two exceptions:
When the array name is an operand of sizeof.
When the array name is an operand of an unary & (address of).
In these 2 cases, the name refers to the array object itself.
The name of the array evaluates to the address of the array .
So arr evaluates to &arr.
But the types will be different.
Try this -
auto ar1 = arr;
auto ar2 = &arr;
auto ar3 = p;
auto ar4 = *p;
ar1 will be of type int*.
ar2 will be of type int(*)[5]
Here you can see that ar4 and ar1 are the same type and ar2 and ar3 are the same type.

Why does a pointer behave like this in c++ [duplicate]

This question already has answers here:
Why p and *p giving the same address when p points to an array?
(3 answers)
Closed 8 years ago.
I found this program in a contest question paper:
#include <iostream>
void main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int*)(&a + 1);
printf("%d %d ",*(a + 1), *(ptr - 1));
}
The output is 2 5
now when I change the 5th line to int *ptr=(int*)(&a); and printf("%d %d ",*(a + 1), *(ptr));
The output becomes 2 1
In the first case the ptr got the last address of the array+1 and in the second case the ptr got the same address of the array(address of a).
My doubt is why does this assignment show different kind of behavior when the a is incremented and assigned to ptr and when a is assigned to ptr without incrementing?
When you take the address of the array, you get a pointer to an array of 5 ints (that is, int(*)[5]). When you increment that pointer, it moves by the size of an array of 5 ints. So it points to the next array in a sequence of arrays (if you actually had a sequence of arrays). Then when you convert that pointer to int*, it becomes a pointer to the first int of the second (non-existent) array, which is one element after the last element of the first array. So that's what is happening with your first example.
With your second example, you are not incrementing the pointer to the array, so when you convert it to int*, it becomes a pointer to the first int in the array.
&a is a pointer to an integer array of size 5, while ptr is an int*. Thus, &a + 1 increment by the size of an int[5], while pointer arithmetic on an int* changes the value of the pointer by multiples of sizeof(int). Thus, &a + 1 is pointing to the address which is 5*sizeof(int) from the address of a. Casting this to an int* ptr and doing ptr-1 gives you the address of a[4].
&a + 1;
Here, simple a refers to the base address of array i.e address of first element. When you say a+1 compiler will see +1 applied to pointer to an int. So, it would increment by offset which would make it jump to next integer.
However, when you say &a, it means address of that array element ( which is of type int [5]). So, adding one to it means that next offset would be to next array of that type i.e indirectly to one-past end of array. Taking address of one-past-array element is no problem until you don't dereference it.

Increment operator on pointer of array errors?

I'm trying something very simple, well supposed to be simple but it somehow is messing with me...
I am trying to understand the effect of ++ on arrays when treated as pointers and pointers when treated as arrays.
So,
int main()
{
int a[4] = { 1, 4, 7, 9 };
*a = 3;
*(a+1) = 4;
*++a = 4; //compiler error
}
1: So at *(a+1)=4 we set a[1]=4; //Happy
But when *++a = 4;, I'd expect pointer a to be incremented one since ++ is precedent to * and then * kicks in and we make it equal to 4. But this code just does not work... Why is that?
Another problem:
int main()
{
int* p = (int *)malloc(8);
*p = 5;
printf("%d", p[0]);
*++p = 9; //now this works!
printf("%d", p[1]); //garbage
printf("%d", p[0]); //prints 9
}
2: Now *++p = 9; works fine but it's not really behaving like an array. How are two different? This is just incrementing p, and making it equal to 9. If I print p[0], it now prints 9 and I see that though can't access it via p[0] anymore, *(p-1) shows 5 is still there. So indexing a pointer with [0], where exactly does it point to? What has changed?
Thanks a lot all experts!
The array names is not modifiable lvalue so operation ++ is not applied hence ++a that try to modify a is compilation time error (where a is array name).
Note *(a + 1) and *a++ are not same, a + 1 is a valid instruction as it just add 1 but doesn't modify a itself, Whereas ++a (that is equvilent to a = a + 1) try to modify a hence error.
Note 'array names' are not pointer. Pointers are variable but array names are not. Of-course when you assign array name to a pointer then in most expressions array names decays into address of first element. e.g.
int *p = a;
Note p points to first element of array (a[0]).
Read some exceptions where array name not decaying into a pointer to first element?
An expression a[i] is equivalent to *(a + i), where a can be either a pointer or an array name. Hence in your second example p[i] is valid expression.
Additionally, *++p is valid because because p is a pointer (a variable) in second code example.
int a[4] = { 1, 4, 7, 9 };
int *pa=a;
There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable, sopa=a and pa++ are legal. But an array name is not a
variable; constructions like a=pa and a++ are illegal
int* p = (int *)malloc(8);
Don't cast result of malloc()
Use index with pointer
p[1]=9; // p[1]==*(p+1)

C/C++ Array initializer problem

Can someone explain why I can do:
int x[4] = { 0, 1, 2, 3 };
int *p = x;
But cannot do:
int x[2][2] = { 0, 1, 2, 3 };
int **p = x;
Is there a way to be able to assign to **p the x[][]?
TIA
A pointer to int int * can point at an integer within an array of integers, so that's why the first is OK;
int x[4] = { 0, 1, 2, 3 };
int *p = x;
This makes p point to x[0], the first int in x.
A pointer to a pointer-to-int int ** can point at a pointer-to-int within an array of pointers-to-int. However, your second array is not an array of pointers-to-int; it is an array of arrays. There are no pointers-to-int, so there is nothing sensible to point int **p at. You can solve this in two ways. The first is to change the type of p so that it is a pointer-to-array-of-2-ints:
int x[2][2] = { 0, 1, 2, 3 };
int (*p)[2] = x;
Now p points at x[0], the first int [2] in x.
The alternative is to create some pointers-to-int to point at:
int x[2][2] = { 0, 1, 2, 3 };
int *y[2] = { x[0], x[1] };
int **p = y;
Now p points at y[0], which is the first int * in y. y[0] in turn points at x[0][0], and y[1] points at x[1][0].
Using the pointer notation you can do this
*(p + n) will return back a value in the subscript n which is equivalent of
p[n], a "single dimension array"
*( * (p + i) + j) will return back a value in the subscripts i and j which
is equivalent of p[i][j], a "double dimension array"
This will prove that using array subscripts [] decays into pointers as per the rule - see ANSI C Standard, 6.2.2.1 - "An array name in an expression is treated by the compiler as a pointer to the first element of the array", furthermore, ANSI C Standard 6.3.2.1 - "A subscript is always equivalent to an offset from a pointer", and also ANSI C Standard 6.7.1 - "An array name in the declaration of a function parameter is treated as a pointer to the first element in the array"
If you are not sure in understanding how pointers and arrays work, please see my other answer which will explain how it works...
Please ignore anyone who says arrays and pointers are the same - they are not...
No, there's no way to assign the array to an "int **", because a two-dimensional array is an array of arrays, not an array of pointers.
You could for instance do:
int x1[2] = {0, 1};
int x2[2] = {2, 3};
int *x[2] = {x1, x2};
int **p = x;
... and maybe that would be an acceptable equivalent to what you are trying to do (depending on what exactly that is of course!).
Update: If you must keep x as a two-dimensional array, you could also do: int (*p)[2] = x; which gives you a pointer-to-array-of-int.
There is no way to meaningfully initialize you variable p with x. Why? Well, there's no way to answer your question until you explain how you even came to this idea. The type of p is int **. The type of x is int[2][2]. These are two different types. Where did you get the idea that you should be able to assign one to the other?
If you really need to access elements of your x through a pointer of type int **, you have to do it indirectly. You have to create an additional intermediate array that will hold pointers to first elements of consecutive rows of array x:
int *rows[2] = { x[0], x[1] };
and now you can point your p to the beginning of this intermediate array
int **p = rows;
Now when you assess p[i][j] you get x[i][j].
There's no way to do it directly, without an intermediate array.
If you are really using c++ instead of c, you can get this effect by using std::vector (or some other collection type).
typedef std::vector<std::vector<int> > intmatrix;
intmatrix x;
intmatrix::iterator p = x.begin();
or some such.
It's all about Standard Conversion rule ($4.2)
An lvalue or rvalue of type “array ofN
T” or “array of unknown bound of T”
can be converted to an rvalue of type
“pointer to T.” The result is a
pointer to the first element of the
array.
The type of od and td respectively are
char [3]
char [1][3]
This means that od has type 'array of 3 chars' (N = 3, T = char).
So in accordance with the above quote, it can be converted to 'pointer to char'
Therefore char *p = od; is perfectly well-formed
Similarly the type of od is 'array of 1 array of 3 chars' (N = 1, T = array of 3 chars).
So in accordance with the above quote, it can be converted to 'pointer to array of 3 chars'
Therefore char (*p)[3] = td; is perfectly well-formed
Is there a way to be able to assign to
**p the x[][]?
No. Because type of td[x][y] for valid x and y is char. So what you can really do is char *pc = &td[0][0].