C pointers : pointing to an array of fixed size

2019-01-03 00:48发布

This question goes out to the C gurus out there:

In C, it is possible to declare a pointer as follows:

char (* p)[10];

.. which basically states that this pointer points to an array of 10 chars. The neat thing about declaring a pointer like this is that you will get a compile time error if you try to assign a pointer of an array of different size to p. It will also give you a compile time error if you try to assign the value of a simple char pointer to p. I tried this with gcc and it seems to work with ANSI, C89 and C99.

It looks to me like declaring a pointer like this would be very useful - particularly, when passing a pointer to a function. Usually, people would write the prototype of such a function like this:

void foo(char * p, int plen);

If you were expecting a buffer of an specific size, you would simply test the value of plen. However, you cannot be guaranteed that the person who passes p to you will really give you plen valid memory locations in that buffer. You have to trust that the person who called this function is doing the right thing. On the other hand:

void foo(char (*p)[10]);

..would force the caller to give you a buffer of the specified size.

This seems very useful but I have never seen a pointer declared like this in any code I have ever ran across.

My question is: Is there any reason why people do not declare pointers like this? Am I not seeing some obvious pitfall?

标签: c pointers size
9条回答
趁早两清
2楼-- · 2019-01-03 01:36

Maybe I'm missing something, but... since arrays are constant pointers, basically that means that there's no point in passing around pointers to them.

Couldn't you just use void foo(char p[10], int plen); ?

查看更多
兄弟一词,经得起流年.
3楼-- · 2019-01-03 01:37

I also want to use this syntax to enable more type checking.

But I also agree that the syntax and mental model of using pointers is simpler, and easier to remember.

Here are some more obstacles I have come across.

  • Accessing the array requires using (*p)[]:

    void foo(char (*p)[10])
    {
        char c = (*p)[3];
        (*p)[0] = 1;
    }
    

    It is tempting to use a local pointer-to-char instead:

    void foo(char (*p)[10])
    {
        char *cp = (char *)p;
        char c = cp[3];
        cp[0] = 1;
    }
    

    But this would partially defeat the purpose of using the correct type.

  • One has to remember to use the address-of operator when assigning an array's address to a pointer-to-array:

    char a[10];
    char (*p)[10] = &a;
    

    The address-of operator gets the address of the whole array in &a, with the correct type to assign it to p. Without the operator, a is automatically converted to the address of the first element of the array, same as in &a[0], which has a different type.

    Since this automatic conversion is already taking place, I am always puzzled that the & is necessary. It is consistent with the use of & on variables of other types, but I have to remember that an array is special and that I need the & to get the correct type of address, even though the address value is the same.

    One reason for my problem may be that I learned K&R C back in the 80s, which did not allow using the & operator on whole arrays yet (although some compilers ignored that or tolerated the syntax). Which, by the way, may be another reason why pointers-to-arrays have a hard time to get adopted: they only work properly since ANSI C, and the & operator limitation may have been another reason to deem them too awkward.

  • When typedef is not used to create a type for the pointer-to-array (in a common header file), then a global pointer-to-array needs a more complicated extern declaration to share it across files:

    fileA:
    char (*p)[10];
    
    fileB:
    extern char (*p)[10];
    
查看更多
We Are One
4楼-- · 2019-01-03 01:45

I would not recommend this solution

typedef int Vector3d[3];

since it obscures the fact that Vector3D has a type that you must know about. Programmers usually dont expect variables of the same type to have different sizes. Consider :

void foo(Vector3d a) {
   Vector3D b;
}

where sizeof a != sizeof b

查看更多
登录 后发表回答