Mutiple indirection :
int a = 3; int *b = &a; int **c = &b; int ***d = &c;
Here are how the values of these pointers equate to each other:
*d == c;// Dereferencing an (int ***) once gets you an (int **) (3 - 1 = 2)
**d == *c == b;// Dereferencing an (int ***) twice, or an (int **) once, gets you an (int *) (3 - 2 = 1; 2 - 1 = 1)
***d == **c == *b == a == 3; //Dereferencing an (int ***) thrice, or an (int **) twice, or an (int *) once, gets you an int (3 - 3 = 0; 2 - 2 = 0; 1 - 1 = 0)
the & operator can be thought of as adding asterisks (increasing pointer level, as I call it), and the *, ->, and [] operators as removing asterisks (decreasing pointer level).
Function Pointer:
char *strcpy(char *dst, const char *src);
char *(*strcpy_ptr)(char *dst, const char *src);
strcpy_ptr = strcpy;
strcpy_ptr = &strcpy;
just like in a regular function declaration, the parameter names are optional:
char *(*strcpy_ptr_noparams)(char *, const char *) = strcpy_ptr;
The type of the pointer to strcpy is char *(*)(char *, const char *); you may notice that this is the declaration from above, minus the variable name. You would use this in a cast. For example:
strcpy_ptr = (char *(*)(char *dst, const char *src))my_strcpy;
As you might expect, a pointer to a pointer to a function has two asterisks inside of the parentheses:
char *(**strcpy_ptr_ptr)(char *, const char *) = &strcpy_ptr;
We can have an array of function-pointers:
char *(*strcpies[3])(char *, const char *) = { strcpy, strcpy, strcpy };
char *(*strcpies[])(char *, const char *) = { strcpy, strcpy, strcpy };
strcpies[0](dst, src);
A function declaration :
char *strcpy(char *dst, const char *src);
A function pointer variable :
char *(*strcpy_ptr)(char *dst, const char *src);
---->the type returned by this function is char *(*)(char *, const char *)
Because function pointer syntax is so mind-bending, most developers use typedefs to abstract them:
typedef char *(*strcpy_funcptr)(char *, const char *);
strcpy_funcptr strcpy_ptr = strcpy;
strcpy_funcptr get_strcpy_ptr(void);