From comp.lang.c: >> What is the meaning of the following declaration? >> >> static char (*b)[6]; > An old-fashioned trick for reading C declarations is to read the implementation out in words, from the inside out: there is a word called b which points to an array of 6 characters, and is static. Reading it left-to-right usually causes confusion: a static char star b of 6 ... uh... er... Huh? =============================================================================== int (*getmenu())(); The trick to doing declarations like these is to notice that the syntax for the declaration of a variable is identical to the syntax for the use of that variable. For example, to call a function: func(); To call a function using a pointer to a function, replace func with *pfunc (parentheses are req'd because the trailing () binds more tightly): (*pfunc)(); To call a function using a pointer to a function that is returned by another function getmenu, replace pfunc with getmenu(): (*getmenu())(); and there is the declaration! =============================================================================== int (*(f ())) (); reading inside out: f is a function which returns a pointer to a function which returns int =============================================================================== In article <2314@calmasd.GE.COM>, pal@calmasd.UUCP writes: > I have just seen both the "right-left" rule and the "left-right" rule > in two recent net articles for interpreting type declarations like > foo **bar[5][6]; > int *farkle()[]; > Will the real rule please stand up. > Thanks. > > -- > pal@calmasd.GE.COM or ...!sdcsvax!calmasd!pal The real rule is as follows: Use [a subset of] the precedence table to decide when to go left and right. Parenthesis can be used to alter the parsing of declarations, just as they can be used to alter the parsing of expressions. If you look at K&R, page 49, you will see that () and [] have higher precedence than *, that () and [] associate left to right, and that * associates right to left. To illustrate with your examples above: > foo **bar[5][6]; bar is: an array of five /* [] before *, [] left to right. */ arrays of six /* [] before *, [] left to right. */ pointers to /* I'm reading the inside * first, */ pointers to /* because * associates right to left. */ type foo. bar is an array of five arrays of six pointers to pointers to foo. Try doing that with either the right-left or the left-right rule. > int *farkle()[]; /* illegal */ farkle is: a function /* () and [] before *, () and [] L->R. */ returning an array of unknown size of pointers to integers farkle is a function returning an array of unknown size of pointers to integers That is illegal, as a function cannot return an array. Our C compiler says something like "illegal function return type". If you really wanted farkle to be a function returning a pointer to an array of integers, you can use parenthesis to change the order: int (*farkle())[]; /* still illegal */ farkle is now: a function returning a pointer /* parenthesis for grouping */ to an array of unknown size of integers. farkle is a function returning a pointer to an array of unknown size, made up of integers. You cannot have a pointer to something of unknown size, so that is illegal. You might use either a pointer to an array of known size, or a pointer to the first integer in an array of unknown size. If you know the difference between a pointer to an array and a pointer to the first element in an array, skip the following digression: DIGRESSION: pointers to arrays In C, the name of an array is treated as a pointer to the first element in that array. That is different from a pointer to an array. For example, int int_array[6]; int_array is an array of 6 integers. If we use it by itself: func(int_array); /* call to function */ it is treated as a pointer to the first of those six, so void func(ip) /* declaration of func */ int *ip; { ... } is correct. ip will point to the first of the six integers in int_array, and we can increment it to access the other five. We can also use [] with pointers, to ip[index] can also be used to access the elements to int_array. C compilers will also allow void func(i_array) int i_array[]; { ... } in which case i_array is **still a pointer**, and we can still use the [] notation to access the elements of int_array. INTERESTING PART OF DIGRESSION: Now what about int int_2d_array[5][6]; int_2d_array is an array of five arrays of six integers (that is, a two dimensional (five by six) array of integers). If we use int_2d_array by itself, as in func2(int_2d_array); /* call to function */ it is treated as a pointer to the first of those five arrays of six integers, so void func(iap) /* declaration of func */ int (*iap)[6]; /*** POINTER TO ARRAY ***/ { ... } is correct. iap is a pointer to an array of six integers. given the call above, it will point to the first of the five arrays of six integers that make up int_2d_array; We can use (*iap)[index] to access the six elements of the first of the five arrays in int_2d_array. If we increment iap, it will point to the second of the five arrays that make up int_2d_array. We can still use [] with pointers, to iap[index1][index2] also be used to access all the elements to int_2d_array. C compilers will also allow void func(i_2array) int i_2array[][6]; { ... } in which case i_2array is **still a pointer**, and we can still use i_2array[i][j] to access int_2d_array. The following is not consistent with the function call above: void func(i_2ptr) int **i_2ptr; { ... } int_2d_array is passed as a pointer to an array, not a pointer to a pointer. END OF DIGRESSION So, we can declare farkle any of the following ways (intermedeiate steps are left to the reader): int (*farkle())[6]; farkle is a function returning a pointer to an array of 6 integers. int *farkle(); farkle is a function returning a pointer to an integer (that integer may be the first in an array of integers). or even: int (*farkle[6])(); farkle is an array of six pointers to functions that return int. int (*(*farkle)[6])(); farkle is a pointer to an array of 6 pointers to functions that return int. To determine what's illegal: 1) a function can return a pointer, a pointer to an array, or a pointer to a function, but not an entire array or function. int *func_ret_ptr(); int (*func_ret_ptr_to_array())[6]; int (*func_ret_ptr_to_func())(); int illegal_func_ret_array()[6]; int illegal_func_ret_func()(); 2) an array can be made up of pointers, arrays, or pointers to functions, but not entire functions. int *array_of_ptrs[46]; int array_of_arrays[2][3]; int (*array_of_ptrs_to_func[5])(); int illegal_array_of_func[6](); 3) a pointer must point to something of known size, and an array must be made up of known sized elements: int two_dimensional[4][5]; int two_d_unknown[][5]; /* legal as func argunment */ int illegal_two_d[4][]; int completely_illegal[][]; int (*ptr_to_array)[6]; int *array_of_ptrs[]; /* legal as func argunment */ int (*illegal_ptr_to_unknown)[]; THE LAST (and perhaps most important) WORD: If the complicated declarations confuse you, do one or two at a time, and use typedef: typedef int (*ptr_to_int_func)(); typedef ptr_to_int_func six_ptrs_to_int_func[6]; typedef ptr_to_six_ptrs_to_int_func *six_ptrs_to_int_func; ptr_to_six_ptrs_to_int_func farkle; I hope this helps. Remember, neither the right-left nor the left-right rule will work on all cases (for example, int **bar[5][6]). Apologies to any who use the right-left rule if it is more than just "look alternately right and left from the variable name", but I've heard it stated that way many times, and that just doesn't work. -- David Wonnacott "They said Van Gogh was crazy, didn't they?" whuxm!davew or rz3bb!davew AT&T Corporate Education The above opinions are not necessarily those of AT&T, or of anyone else anywhere