Array of pointers to an array of fixed size

后端 未结 9 1799
心在旅途
心在旅途 2020-12-14 06:04

I tried to assign two fixed-size arrays to an array of pointers to them, but the compiler warns me and I don\'t understand why.

int A[5][5];
int B[5][5];
int         


        
9条回答
  •  心在旅途
    2020-12-14 06:42

    There is a lot wrong with the line

    int*** C = {&A, &B};
    

    You're declaring a single pointer C, but you're telling it to point to multiple objects; that won't work. What you need to do is declare C as an array of pointers to those arrays.

    The types of both &A and &B are int (*)[5][5], or "pointer to 5-element array of 5-element array of int"; thus, the type of C needs to be "array of pointer to 5-element array of 5-element array of int", or

    int (*C[2])[5][5] = { &A, &B };
    

    which reads as

          C           -- C is a
          C[2]        -- 2-element array of
         *C[2]        -- pointers to
        (*C[2])[5]    -- 5-element arrays of
        (*C[2])[5][5] -- 5-element arrays of
    int (*C[2])[5][5] -- int
    

    Yuck. That's pretty damned ugly. It gets even uglier if you want to access an element of either A or B through C:

    int x = (*C[0])[i][j]; // x = A[i][j]
    int y = (*C[1])[i][j]; // y = B[i][j]
    

    We have to explicitly dereference C[i] before we can index into the array it points to, and since the subscript operator [] has higher precedence than the unary * operator, we need to group *C[0] in parens.

    We can clean this up a little bit. Except when it is the operand of the sizeof or unary & operators (or is a string literal being used to initialize another array in a declaration), an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.

    The expressions A and B have type int [5][5], or "5-element array of 5-element array of int". By the rule above, both expressions "decay" to expressions of type "pointer to 5-element array of int", or int (*)[5]. If we initialize the array with A and B instead of &A and &B, then we need an array of pointers to 5-element arrays of int, or

    int (*C[2])[5] = { A, B };
    

    Okay, that's still pretty eye-stabby, but that's as clean as this is going to get without typedefs.

    So how do we access elements of A and B through C?

    Remember that the array subscript operation a[i] is defined as *(a + i); that is, given a base address a, offset i elements (not bytes)1 from that address and dereference the result. This means that

    *a == *(a + 0) == a[0]
    

    Thus,

    *C[i] == *(C[i] + 0) == C[i][0]
    

    Putting this all together:

    C[0] == A                      // int [5][5], decays to int (*)[5]
    C[1] == B                      // int [5][5], decays to int (*)[5]
    
    *C[0] == C[0][0] == A[0]       // int [5], decays to int *
    *C[1] == C[1][0] == B[0]       // int [5], decays to int *
    
    C[0][i] == A[i]                // int [5], decays to int *
    C[1][i] == B[i]                // int [5], decays to int *
    
    C[0][i][j] == A[i][j]          // int
    C[1][i][j] == B[i][j]          // int
    

    We can index C as though it were a 3D array of int, which is a bit cleaner than (*C[i)[j][k].

    This table may also be useful:

    Expression        Type                "Decays" to       Value
    ----------        ----                -----------       -----
             A        int [5][5]           int (*)[5]       Address of A[0]
            &A        int (*)[5][5]                         Address of A
            *A        int [5]              int *            Value of A[0] (address of A[0][0])
          A[i]        int [5]              int *            Value of A[i] (address of A[i][0])
         &A[i]        int (*)[5]                            Address of A[i]
         *A[i]        int                                   Value of A[i][0]   
       A[i][j]        int                                   Value of A[i][j]   
    

    Note that A, &A, A[0], &A[0], and &A[0][0] all yield the same value (the address of an array and the address of the first element of the array are always the same), but the types are different, as shown in the table above.


    1. Pointer arithmetic takes the size of the pointed-to type into account; if p contains the address of an int object, then p+1 yields the address of the next int object, which may be 2 to 4 bytes away.

提交回复
热议问题