2

I'm working on some code and can't get my head around this cast. As far as I understand we're trying to cast a pointer to unsigned char array to something else. I'm not quite sure what (*c_grid) means and what (*)[dim_x] is there for.

unsigned char (*c_grid)[dim_x] = (unsigned char (*)[dim_x])grid_in;

P.S.: and home comes that after that I can access c_grid elements as c_grid[i][j]?

Denys S.
  • 6,358
  • 12
  • 43
  • 65
  • `c_grid` is a pointer to an array (of size `dim_x`) of `unsigned chars`. That's also what the typecast on the right side does – mch Jul 01 '14 at 14:07

2 Answers2

2

c_grid is a pointer to an array of dim_x elements of type unsigned char. (unsigned char (*)[dim_x]) is casting grid_in to the same type as that of c_grid, i.e, pointer to an array of dim_x elements of type unsigned char.

c_grid is a pointer to array. What that means?

When you declare

int a[10];
int *p = a; 

then you can access rest of the element of the array a by using p[i]. Same rule is applied in case of 2D array.
If grid_in is a 2D array and c_grid is pointer to its first element (each element of grid_in is a 1D array of length dim_x), then when you increment c_grid by 1, it will point to the next row of the 2D array grid_in. So, you can say that c_grid[0] is pointer to first row and c_grid[i] is pointer to ith row.

To access the jth element of ith row c_grid points to, you just need c_grid[i][j]

haccks
  • 104,019
  • 25
  • 176
  • 264
  • 2
    The answers here are not really going to teach you how pointers work in C. You really should read a book or look at an online resource that really explains how they work. This site is really for answering specific questions. – AnthonyLambert Jul 01 '14 at 14:28
  • @haccks, I don't seem to understand how c_grid[i][j] would be computed, because in my understanding (unsigned char (*)[dim_x]) <- that is a 1D array of dim_x elements, which implies linear allocation of elements. And when we try to address ij_th elements we already anticipate some structure which is somehow known (like number of elements in a row/column) which we don't know or do we? – Denys S. Jul 01 '14 at 15:01
  • @DenysS.; Still you have problem with it ? – haccks Jul 01 '14 at 17:29
  • @DenysS.; BTW, you can [see this](http://stackoverflow.com/a/24468853/2455888) for visual explanation of what pointer to an array is ? – haccks Jul 01 '14 at 18:15
0

In C declarators, the * operator associates right-to-left, similarly to the unary operators, and the array declarator associates left-to-right with a higher precedence. That is to say, char ***a[1][1], if we add full parentheses, is the same thing as: char (*(*(*((a[1])[1])))). The postfix [] type construction operators apply first, left to right, and then the unary * operators right to left. This means that a is an "array of arrays of pointers to pointer to pointer to char".

Parentheses can be used to override the association and precedence. For example: char (***a)[1][1]. Now a is a "pointer to pointer to pointer to array of arrays of char". The * operators apply right to left, and then the postfix ones to that parenthesized unit.

Other parenthesizations are possible, like char **(*a)[1][1], where a is now a pointer to an array, or char **(*a[1])[1], where a is an array of pointers.

The syntax determines the "shape" of the type.

A cast expression resembles a declaration, except that the declared name is simply removed. For instance to turn char **(*a[1])[1] into a type expression suitable for a cast, we take out the a: char **(*[1])[1].

The declarator syntax is designed in such a way that when we take out the declared identifier from the declarator, it is still obvious where that name would go if we were to put it back. It can only go in one place.

Given char **(*[1])[1] from which a has been removed, where can we re-insert a?

char *a*(*[1])[1]   // not here
char **a(*[1])[1]   // not here
char **(a*[1])[1]   // not here
char **(*a[1])[1]   // aha! this rings a bell
char **(*[a 1])[1]  // certainly not here
char **(*[1 a])[1]  // nope
char **(*[1]a)[1]   // wrong
char **(*[1])a[1]   // wrong
char **(*[1])[a 1]  // wrong
char **(*[1])[1 a]  // wrong
char **(*[1])[1]a   // wrong

Once you get used to the syntax, it will be obvious. The identifier has to either immediately follow the declaration specifiers (in this case char) or has to immediately follow an open parenthesis ( or a * operator. On the right, it can only be followed by [ or nothing.

So the first substitution immediately looks wrong, since a is followed by *, and the second substitution looks wrong because a is followed by (.

Kaz
  • 55,781
  • 9
  • 100
  • 149
  • thanks for such an extensive answer, it clarified some aspects, but I still don't understand how comes that after casting grid_in we can access c_grid elements in a 2D array manner even though we have never declared it to be such. – Denys S. Jul 01 '14 at 15:08
  • @DenysS This is possible because the underlying memory doesn't have any concept of the C type; it is just a view that we have imposed on it. In C we can subvert the type system to take the storage of an object which as declared one way, and use it as if it were another type. Most instances of this "type punning", however, are not defined by the C language standard ("undefined behavior"). – Kaz Jul 01 '14 at 15:12
  • @DenysS Note that when we dynamically allocate an object with `malloc`, we usually convert the pointer to a type other than `void *`, and effectively give that memory a type. So being able to treat arbitrary memory as having some type is necessary for dynamic allocation. – Kaz Jul 01 '14 at 15:14