I will try to give you a technically correct explanation so that you know what is happening. Not very complicated, but really controversial.
Introduction:
In C, there are “lvalues” that basically represent “assignable” objects that take place somewhere in memory, and “rvalues” that represent, well, “conceptual” values (not required to be placed anywhere in particular) .
For example, if you define int a = 5;
, then a
is an lvalue of type int and a value of 5. It can also be interpreted as (or rather, to convert) the value of r of type int. Such a value of r will still be known that it is 5, but it will no longer contain information about the location of a
in memory.
Some expressions need lvalues (for example, the left side of the = operator because you need to assign an object), and some need rvalues (for example, operator + because you only need integral values when adding or the right side of the operator =). If the expression requires an rvalue, but you pass an lvalue, then it is converted to an rvalue.
In addition, only r values are passed to functions in C (which means that C is strictly by default, and not by call).
Some examples:
int a = 1; a;
The conversion from lvalue to rvalue is usually trivial and inconspicuous (it's like taking number 5 from a shelf labeled a
). Arrays are mostly an exception.
The big thing: There are no array type values in C. There are pointers lvalues and rvalues, integer lvalues and rvalues, lvalues structures and rvalues, etc. But only lvalue arrays. When you try to convert the lvalue value of an array type to an rvalue, you no longer have an array, you have a pointer to the first element of the array. This is the root of the confusion in arrays in C (and C ++).
Explanation:
array
*(array)
array+1
*(array)+1
array
is an lvalue of type int[3][5]
(an array of 3 ints out of 5 ints). When you try to pass it to a function, it gets a pointer of type int (*)[5]
(a pointer to an array of 5 int), because that is what remains after the lvalue-to-rvalue conversion.
*(array)
more complicated. First, an lvalue-to-rvalue is executed, which leads to an rvalue of type int(*)[5]
, then operator*
takes this rvalue value and returns an lvalue of type int[5]
, which you then try to pass to the function. Therefore, it is converted to r again, which leads to int*
.
array+1
causes the array to be converted to an rvalue of type int(*)[5]
and that rvalue is incremented by one, therefore (according to the rules of pointer arithmetic) the pointer moves 1 * sizeof(int[5])
bytes forward.
*(array)+1
: see 2 points earlier, but the last value of type int*
again increased using the arithmetic rules of the pointer to 1 * sizeof(int)
.
No secrets here!