Rule: http://ieng9.ucsd.edu/~cs30x/rt_lt.rule.html
In short, you should start with the identifier, and then parse everything from the identifier to the right (it can be () - a function or an array [] ), and then parse everything from the identifier to the left. Brackets change this order - you must first parse everything in the innermost brackets, etc., It works as with arithmetic calculations.
In other words, there is a priority order (which can be changed in parentheses), from higher to lower:
1) () is a function and [] is an array from left to right;
2) * - pointer, type, type modifier, from right to left.
Your example
int (*ptr)(char (*ch)[])
We start with the id
int (*ptr)(char (*ch)[]);
The ptr identifier is in parentheses, so first we parse everything in the parent
(*ptr)
There is nothing to the right, so we analyze on the left
(*ptr)
We ended up in parentheses, now we parse to the right of the parentheses
int (*ptr)(char (*ch)[]);
So far, we have ignored function arguments and parsed to the left of parentheses
int (*ptr)(char (*ch)[]);
In the same way, we analyze the function argument (I inserted some spaces for better alignment)
char (* ch )[ ]
Finally, we have:
ptr is a pointer to a function that returns an int and takes a pointer to an array of characters as an argument