Mixing variable pointers in a 2D array

I have a major doubt in 2D arrays (C language). Consider declaring a 2D array as follows

int array[3][5]; 

Now, when I do the following, the output of both th below printf is the same:

 printf("%u\n", array); printf("%u\n", *(array)); 

Now when you are trying to do the following:

 printf("%u\n", array+1); printf("%u\n", *(array)+1); 

The outputs are different. I get that the second printf refers to the array [0] [1], and the first refers to the array [1] [0]. How it works? array - pointer to what?

Thanks in advance

+5
source share
5 answers

Arrays are not pointers. Ignore any answer, book, or textbook that tries to tell you otherwise.

An array type expression in most contexts is converted (at compile time) to a pointer to the first element of the array. The exceptions are:

  • Operand sizeof ( sizeof arr gives the size of the array, not the size of the pointer)
  • The operand of unary & ( &arr gives the address of the array, and not its first element - the same memory location, of a different type). This is especially important for your example.
  • The string literal in the initializer used to initialize the array object ( char s[6] = "hello"; does not copy the address of the string literal, it copies its value)

A 2-dimensional array is nothing more than an array of arrays. There are other data structures that can be used with the same syntax x[y][z] , but they are not true two-dimensional arrays. You have.

The index operator [] is defined in terms of pointer arithmetic. x[y] means *(x+y) .

The behavior of your code follows from these rules.

Read the comp.lang.c FAQ section 6. This is the best explanation of this material that I have seen.

And do not use "%u" to print pointer values; convert to void* and use "%p" .

 printf("%p\n", (void*)array); printf("%p\n", (void*)*(array)); 
+1
source

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; // a is an lvalue of type int and value 1 a = a+3; // here the `a` is converted to an rvalue of type int and value 1, then after the addition there an assignment, on the lhs there an lvalue `a` and an rvalue `4` 

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!

+5
source

2D arrays in C are confusing.
array and * array are the same pointers but not the same.
array is of type int [3] [5] (which is an array of size 5, arrays int [3]).
* array - the first line of the array, which is of type int [3].
array + 1 means an array plus one element. The array element is int [3], so it is 12 bytes in advance.
* array + 1 means * array plus one element. The * element of the array is int, so it has 4 bytes in advance.

+2
source

You can understand it like this:

the array points to 3 rows with 5 columns each

when you make an array + 1, the line changes, so you go to the 1st line. You should try to access using * (array + 1).

when you do * (array), you specify the 0th row and * (array) +1 moves forward in the column, so the element is an array [0] [1]

0
source

The increment of units in the pointers corresponds to the size of the data type.

0
source

Source: https://habr.com/ru/post/1012701/


All Articles