4
struct grid {
    int width, height;
    void *cells[];
};
typedef struct grid grid;

int main(){
    enum { width = 2, height = 10 };
    grid *g = malloc(sizeof(grid) + width * height * sizeof(void *));
    void *(*cells)[10] = &g->cells;
}

My professor taught us about this cool way to allocate a flexible array and then assign a pointer that points to an entire array of pointers

void *(*cells)[10] = &g->cells; <-- This line

So i tried this method

 char *array[10];
 char *(*pointer)[2] = &array;

And it just gave me a compiler error

warning: incompatible pointer types initializing
      'char *(*)[2]' with an expression of type 'char *(*)[10]'
       [-Wincompatible-pointer-types]
       char *(*pointer)[2] = &array;

If anyone could explain to me the functionality of a "pointer to an entire array" that would be useful. Thank you

4
  • 1
    when you say "gave me a compiler error" in a question, you should always include the error. Commented Dec 14, 2015 at 20:38
  • @Adam Thanks for reminding Commented Dec 14, 2015 at 20:43
  • The array length is part of the type. char *(*pointer)[2] is a pointer to 2-element arrays of char *. Maybe char *(*pointer[2])[10] to get a 2-element array of pointers to 10-element arrays of char *? Commented Dec 14, 2015 at 20:50
  • If your professor said that, he was wrong. He might declare cells field as char cells[0];, not as an incomplete type definition, which is probably the cause of compiler complainting, as the compiler cannot know sizeof struct grid as there is an incomplete type defined there. Commented Dec 16, 2015 at 9:55

2 Answers 2

4

Lets take your correct declaration first:

void *(*cells)[10] = &g->cells;

To understand this, recognize first that cells is the identifier being declared, and from there follow precedence rules:

  1. (*cells) says that cells is a pointer, and the rest of the declaration describes the pointed-to thing. The parentheses are simply to enforce precedence, just like in an arithmetic expression.
  2. The [10] applies next, because brackets have higher precendence than unary *. This says, then, that (*cells) is an array with 10 elements.
  3. That leaves the void * out front, which gives the type of each element.

And if we look at &g->cells, it is a pointer to an array of an unspecified number of void *.

Now consider your code:

char *array[10];
char *(*pointer)[2] = &array;

Following similar procedure, we get that pointer is declared as a pointer to an array of 2 char *. So far, so good. Now, what are you trying to assign to it? Why, it's a pointer to an array of 10 char *. That's a pointer to a different, incompatible type.

In the first case, the initializer's type is a pointer to an "incomplete type" that is compatible with the type to which the pointer points. (It is incomplete because the array length is unspecified; it is compatible because in all other respects it matches the other type.) The pointed-to thing could be an array of the length implicitly asserted by the assignment, and C will treat the pointer as if it were.

In the second case, C can see that the two pointers definitely point to objects of different size, and that therefore the assignment is definitely incorrect. You would need a cast or a change to the type of pointer to make it accept the initialization.

Sign up to request clarification or add additional context in comments.

Comments

3

&array is the address of an array containing 10 pointers to char

pointer is a pointer to an array containing 2 pointers to char

2 != 10 , hence the warning.

There's a handy website that helps to understand difficult c decelerations.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.