Why is function(char * array[]) a valid function definition but not (char (*array)[] in C?

前端 未结 4 790
闹比i
闹比i 2020-12-09 23:12

I think that it is because the former is an array of pointers to char and the latter is a pointer to an array of chars, and we need to properly specify the size of

相关标签:
4条回答
  • 2020-12-09 23:46

    Because,

    (1) function(char * p_array[])
    

    is equivalent to char **p_array; i.e. a double pointer which is valid.

    (2) function(char (*p_array)[])
    

    You are right, that p_array is pointer to char array. But that needs to be of fixed size in the case when it appears as function argument. You need to provide the size and that will also become valid.

    0 讨论(0)
  • 2020-12-09 23:52

    Both are valid in C but not C++. You would ordinarily be correct:

    char *x[]; // array of pointers to char
    char (*y)[]; // pointer to array of char
    

    However, the arrays decay to pointers if they appear as function parameters. So they become:

    char **x; // Changes to pointer to array of pointer to char
    char (*y)[]; // No decay, since it's NOT an array, it's a pointer to an array
    

    In an array type in C, one of the sizes is permitted to be unspecified. This must be the leftmost one (whoops, I said rightmost at first). So,

    int valid_array[][5]; // Ok
    int invalid_array[5][]; // Wrong
    

    (You can chain them... but we seldom have reason to do so...)

    int (*convoluted_array[][5])[][10];
    

    There is a catch, and the catch is that an array type with [] in it is an incomplete type. You can pass around a pointer to an incomplete type but certain operations will not work, as they need a complete type. For example, this will not work:

    void func(int (*x)[])
    {
        x[2][5] = 900; // Error
    }
    

    This is an error because in order to find the address of x[2], the compiler needs to know how big x[0] and x[1] are. But x[0] and x[1] have type int [] -- an incomplete type with no information about how big it is. This becomes clearer if you imagine what the "un-decayed" version of the type would be, which is int x[][] -- obviously invalid C. If you want to pass a two-dimensional array around in C, you have a few options:

    • Pass a one-dimensional array with a size parameter.

      void func(int n, int x[])
      {
          x[2*n + 5] = 900;
      }
      
    • Use an array of pointers to rows. This is somewhat clunky if you have genuine 2D data.

      void func(int *x[])
      {
          x[2][5] = 900;
      }
      
    • Use a fixed size.

      void func(int x[][5])
      {
          x[2][5] = 900;
      }
      
    • Use a variable length array (C99 only, so it probably doesn't work with Microsoft compilers).

      // There's some funny syntax if you want 'x' before 'width'
      void func(int n, int x[][n])
      {
          x[2][5] = 900;
      }
      

    This is a frequent problem area even for C veterans. Many languages lack intrinsic "out-of-the-box" support for real, variable size, multidimensional arrays (C++, Java, Python) although a few languages do have it (Common Lisp, Haskell, Fortran). You'll see a lot of code that uses arrays of arrays or that calculates array offsets manually.

    0 讨论(0)
  • 2020-12-09 23:53

    Those two declarations are very different. In a function parameter declaration, a declarator of [] directly applied to the parameter name is completely equivalent to a *, so your first declaration is exactly the same in all respects as this:

    function(char **p_array);
    

    However, this does not apply recursively to parameter types. Your second parameter has type char (*)[], which is a pointer to an array of unknown size - it is a pointer to an incomplete type. You can happily declare variables with this type - the following is a valid variable declaration:

    char (*p_array)[];
    

    Just like a pointer to any other incomplete type, you cannot perform any pointer arithmetic on this variable (or your function parameter) - that's where you error arises. Note that the [] operator is specified as a[i] being identical to *(a+i), so that operator cannot be applied to your pointer. You can, of course, happily use it as a pointer, so this is valid:

    void function(char (*p_array)[])
    {
        printf("p_array = %p\n", (void *)p_array);
    }
    

    This type is also compatible with a pointer to any other fixed-size array of char, so you can also do this:

    void function(char (*p_array)[])
    {
        char (*p_a_10)[10] = p_array;
    
        puts(*p_a_10);
    }
    

    ...and even this:

    void function(char (*p_array)[])
    {
        puts(*p_array);
    }
    

    (though there is precious little point in doing so: you might as well just declare the parameter with type char *).

    Note that although *p_array is allowed, p_array[0] is not.

    0 讨论(0)
  • 2020-12-09 23:57

    NOTE:
    The below answer was added when the Q was tagged C++, and it answers from a C++ perspective. With tagged changed to only C, both the mentioned samples are valid in C.

    Yes, Your reasoning is correct.
    If you try compiling the error given by compiler is:

    parameter ‘p_array’ includes pointer to array of unknown bound ‘char []’
    

    In C++ array sizes need to be fixed at compile time. C++ standard forbids Variable Lenght Array's(VLA) as well. Some compilers support that as an extension but that is non standard conforming.

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