2D array variable pointer confusion

前端 未结 5 2046
日久生厌
日久生厌 2021-01-06 03:35

I have a basic doubt in 2D arrays (C Language). Consider a declaration of a 2D array as follows

int array[3][5];

Now when I do the followin

相关标签:
5条回答
  • 2021-01-06 04:13

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

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

    • The operand of sizeof (sizeof arr yields the size of the array, not the size of a pointer)
    • The operand of unary & (&arr yields the address of the array, not of its first element -- same memory location, different type). This is particularly relevant to your example.
    • A string literal in an initializer used to initialize an array object (char s[6] = "hello"; doesn't copy the address of the string literal, it copies its value)

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

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

    The behavior of your code follows from these rules.

    Read section 6 of the comp.lang.c FAQ. It's the best explanation of this stuff I've seen.

    And don't use "%u" to print pointer values; convert to void* and use "%p".

    printf("%p\n", (void*)array);
    printf("%p\n", (void*)*(array));
    
    0 讨论(0)
  • 2021-01-06 04:13

    You can understand in this way:

    array points to an 3 rows with 5 columns each

    when you do array+1, row changes so you go to 1st row. You should try accessing with *(array + 1).

    when you do *(array), you point to 0th row and *(array)+1 moves ahead in column so element is array[0][1]

    0 讨论(0)
  • 2021-01-06 04:13

    Unit increment in pointers is in accordance to the size of the data type.

    0 讨论(0)
  • 2021-01-06 04:14

    2D arrays in C are confusing.
    array and *array are both the same pointer, but are not the same type.
    array is of type int[3][5] (which is an array, of size 5, of int[3] arrays).
    *array is the first line of array, which is of type int[3].
    array+1 means array plus one element. An element of array is int[3], so it's 12 bytes forward.
    *array+1 means *array plus one element. An element of *array is int, so it's 4 bytes forward.

    0 讨论(0)
  • 2021-01-06 04:23

    I'll try to give you a technically-correct explanation so you'll know what's going on. Not really complicated, but indeed counter-intuitive.

    Intro:

    In C there are "lvalues" which basically represent "assignable" objects that have a place somewhere in memory, and "rvalues" which 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 value 5. Also it can be interpreted as (or rather, converted to) an rvalue of type int. Such an rvalue would still be known to be equal to 5, but it would no longer contain the information about a's location in memory.

    Some expressions need lvalues (like the left hand-side of operator= because you have to assign to an object), and some need rvalues (like operator+ because you only need the integral values when you add, or the right side of operator=). If an expression needs an rvalue but you pass an lvalue, then it is converted to an rvalue.

    Also, only rvalues are passed to functions in C (which means that C is strictly call-by-value, not call-by-reference).

    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's an assignment, on the lhs there's an lvalue `a` and an rvalue `4`
    

    Conversion from an lvalue to an rvalue is usually trivial and unnoticable (it's like taking the number 5 from a shelf labeled a). Arrays are basically the exception here.

    The big thing: There are no rvalues of array type in C. There are pointer lvalues and rvalues, integer lvalues and rvalues, structure lvalues and rvalues etc... But only lvalue arrays. When you try to convert an lvalue of array type to an rvalue, you no longer have an array, you have a pointer to the array's first member. That is the root of confusion about arrays in C (and C++).

    Explanation:

    • array
    • *(array)
    • array+1
    • *(array)+1

    array is an lvalue of type int[3][5] (array of 3 ints of 5 ints). When you try to pass it to a function, it receives a pointer of type int (*)[5] (pointer to array of 5 ints) because that's what's left after lvalue-to-rvalue conversion.

    *(array) is tricker. First the lvalue-to-rvalue is performed resulting in an rvalue of type int(*)[5], then operator* takes that rvalue and returns an lvalue of type int[5], which then you attempt to pass to the function. Hence again it's converted to an rvalue, resulting in an int*.

    array+1 causes the array to be converted to an rvalue of type int(*)[5] and that rvalue gets incremented by one, so (according to the rules of pointer arithmetics) the pointer moves 1 * sizeof(int[5]) bytes forwards.

    *(array)+1: see 2 points before, but the final rvalue of type int* gets incremented, again by rules of pointer arithmetics, by 1 * sizeof(int).

    No mystery here!

    0 讨论(0)
提交回复
热议问题