Array of pointers to an array of fixed size

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

    A common misconception among C beginners is that they just assume pointers and arrays are equivalent. That's completely wrong.

    Confusion comes to beginners when they see the code like

    int a1[] = {1,2,3,4,5};
    int *p1 = a1;            // Beginners intuition: If 'p1' is a pointer and 'a1' can be assigned
                             // to it then arrays are pointers and pointers are arrays.
    
    p1[1] = 0;               // Oh! I was right
    a1[3] = 0;               // Bruce Wayne is the Batman! Yeah.
    

    Now, it is verified by the beginners that arrays are pointers and pointers are arrays so they do such experiments:

    int a2[][5] = {{0}};
    int **p2 = a2;
    

    And then a warning pops up about incompatible pointer assignment then they think: "Oh my God! Why has this array become Harvey Dent?".

    Some even goes to one step ahead

    int a3[][5][10] = {{{0}}};
    int ***p3 = a3;             // "?"
    

    and then Riddler comes to their nightmare of array-pointer equivalence.

    Always remember that arrays are not pointers and vice-versa. An array is a data type and a pointer is another data type (which is not array type). This has been addressed several years ago in the C-FAQ:

    Saying that arrays and pointers are "equivalent" means neither that they are identical nor even interchangeable. What it means is that array and pointer arithmetic is defined such that a pointer can be conveniently used to access an array or to simulate an array. In other words, as Wayne Throop has put it, it's "pointer arithmetic and array indexing [that] are equivalent in C, pointers and arrays are different.")

    Now always remember few important rules for array to avoid this kind of confusion:

    • Arrays are not pointers. Pointers are not arrays.
    • Arrays are converted to pointer to their first element when used in an expression except when an operand of sizeof and & operator.
    • It's the pointer arithmetic and array indexing that are same.
    • Pointers and arrays are different.
    • Did I say "pointers are not arrays and vice-versa".

    Now you have the rules, you can conclude that in

    int a1[] = {1,2,3,4,5};
    int *p1 = a1;
    

    a1 is an array and in the declaration int *p1 = a1; it converted to pointer to its first element. Its elements are of type int then pointer to its first element would be of type int * which is compatible to p1.

    In

    int a2[][5] = {{0}};
    int **p2 = a2;
    

    a2 is an array and in int **p2 = a2; it decays to pointer to its first element. Its elements are of type int[5] (a 2D array is an array of 1D arrays), so a pointer to its first element would be of type int(*)[5] (pointer to array) which is incompatible with type int **. It should be

    int (*p2)[5] = a2;
    

    Similarly for

    int a3[][5][10] = {{{0}}};
    int ***p3 = a3;
    

    elements of a3 is of type int [5][10] and pointer to its first element would be of type int (*)[5][10], but p3 is of int *** type, so to make them compatible, it should be

    int (*p3)[5][10] = a3;
    

    Now coming to your snippet

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

    &A and &B are of type int(*)[5][5]. C is of type int***, it's not an array. Since you want to make C to hold the address of both the arrays A and B, you need to declare C as an array of two int(*)[5][5] type elements. This should be done as

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

    However, if I dynamically allocate A and B it works just fine. Why is this?

    In that case you must have declared A and B as int **. In this case both are pointers, not arrays. C is of type int ***, so it can hold an address of int** type data. Note that in this case the declaration int*** C = {&A, &B}; should be

      int*** C = &A;
    

    In case of int*** C = {&A, &B};, the behavior of program would be either undefined or implementation defined.

    C11: 5.1.1.3 (P1):

    A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined

    Read this post for further explanation.

提交回复
热议问题