Array of pointers to an array of fixed size

后端 未结 9 1761
心在旅途
心在旅途 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:40

    You are being confused by the equivalence of arrays and pointers.

    When you declare an array like A[5][5], because you have declared both dimensions, C will allocate memory for 25 objects contiguously. That is, memory will be allocated like this:

    A00, A01, ... A04, A10, A11, ..., A14, A20, ..., A24, ...
    

    The resulting object, A, is a pointer to the start of this block of memory. It is of type int *, not int **.

    If you want a vector of pointers to arrays, you want to declare your variables as:

    int   *A[5], *B[5];
    

    That would give you:

    A0, A1, A2, A3, A4
    

    all of type int*, which you would have to fill using malloc() or whatever.

    Alternatively, you could declare C as int **C.

    0 讨论(0)
  • 2020-12-14 06:40

    Either you should declare the third array like

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

    that is as an array of pointers to two-dimensional arrays.

    For example

    #include <stdio.h>
    
    #define N   5
    
    void output( int ( *a )[N][N] )
    {
        for ( size_t i = 0; i < N; i++ )
        {
            for ( size_t j = 0; j < N; j++ ) printf( "%2d ", ( *a )[i][j] );
            printf( "\n" );
        }
    }
    
    int main( void )
    {
        int A[N][N] =
        {
            {  1,  2,  3,  4,  5 },
            {  6,  7,  8,  9, 10 },
            { 11, 12, 13, 14, 15 },
            { 16, 17, 18, 19, 20 },
            { 21, 22, 23, 24, 25 }
        };
        int B[N][N] =
        {
            { 25, 24, 23, 22, 21 },
            { 20, 19, 18, 17, 16 },
            { 15, 14, 13, 12, 11 },
            { 10,  9,  8,  7,  6 },
            {  5,  4,  3,  2,  1 }
        };
    
    /*
        typedef int ( *T )[N][N];
        T C[] = { &A, &B };
    */
    
        int ( *C[] )[N][N] = { &A, &B };
    
        output( C[0] );
        printf( "\n" );
    
        output( C[1] );
        printf( "\n" );
    }        
    

    The program output is

     1  2  3  4  5 
     6  7  8  9 10 
    11 12 13 14 15 
    16 17 18 19 20 
    21 22 23 24 25 
    
    25 24 23 22 21 
    20 19 18 17 16 
    15 14 13 12 11 
    10  9  8  7  6 
     5  4  3  2  1 
    

    or like

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

    that is as an array of pointers to the first elements of two-dimensional arrays.

    For example

    #include <stdio.h>
    
    #define N   5
    
    void output( int ( *a )[N] )
    {
        for ( size_t i = 0; i < N; i++ )
        {
            for ( size_t j = 0; j < N; j++ ) printf( "%2d ", a[i][j] );
            printf( "\n" );
        }
    }
    
    int main( void )
    {
        int A[N][N] =
        {
            {  1,  2,  3,  4,  5 },
            {  6,  7,  8,  9, 10 },
            { 11, 12, 13, 14, 15 },
            { 16, 17, 18, 19, 20 },
            { 21, 22, 23, 24, 25 }
        };
        int B[N][N] =
        {
            { 25, 24, 23, 22, 21 },
            { 20, 19, 18, 17, 16 },
            { 15, 14, 13, 12, 11 },
            { 10,  9,  8,  7,  6 },
            {  5,  4,  3,  2,  1 }
        };
    
    /*
        typedef int ( *T )[N];
        T C[] = { A, B };
    */
    
        int ( *C[] )[N] = { A, B };
    
        output( C[0] );
        printf( "\n" );
    
        output( C[1] );
        printf( "\n" );
    }        
    

    The program output is the same as above

     1  2  3  4  5 
     6  7  8  9 10 
    11 12 13 14 15 
    16 17 18 19 20 
    21 22 23 24 25 
    
    25 24 23 22 21 
    20 19 18 17 16 
    15 14 13 12 11 
    10  9  8  7  6 
     5  4  3  2  1 
    

    depending on how you are going to use the third array.

    Using typedefs (shown in the demonstrative program as commented) ssimplifies the arrays' definitions.

    As for this declaration

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

    then in the left side there is declared a pointer of type int *** that is a scalar object while in the right side there is a list of initializers that have different type int ( * )[N][N].

    So the compiler issues a message.

    0 讨论(0)
  • 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.

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