Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.
Read Complex C Declarations
Decode pointer to array, array of pointers, function returning a pointer and pointer to function with one reliable method. Essential skill for embedded C programming and interviews.
Few things in C look as intimidating as a long declaration full of stars and parentheses, yet the function pointer declaration in C follows a simple, mechanical rule. This lecture of our free C programming course gives you a method to read any declaration, compares the look-alike forms that trip up beginners, proves the differences with a program that prints real sizes, and shows how typedef tames the worst cases. If you work through this free C tutorial carefully, reading register tables, driver headers and interview questions in embedded C programming will feel much easier.
What You Will Learn
- The reading method that works for every C declaration
- The difference between an array of pointers and a pointer to an array
- The difference between a function returning a pointer and a pointer to a function
- How to read and write a function pointer declaration in C, including arrays of them
- How typedef turns an unreadable declaration into a clear one
- A program that proves each declaration’s size and behaviour
Prerequisites
The earlier lectures of this chapter on pointers, pointer to pointer, pointers with arrays and function pointers are all required background.
Why Declarations Look Confusing
Even a function pointer declaration in C is built from the inside out, like every other declaration. You write a name, then wrap it with operators: brackets for arrays, parentheses for functions and a star for pointers. The three operators have different priorities. Brackets and parentheses bind tighter than the star, which is why a pair of brackets around the star changes the meaning completely. Once you know that, a declaration is no longer a puzzle; it is a sentence you read in a fixed order.
The Reading Method: Start at the Name
- Find the identifier. This is the thing being declared.
- Look to the right. Brackets mean array of, parentheses mean function returning.
- If you hit a closing parenthesis, go back left of the name. A star means pointer to.
- When the parenthesised part is finished, step outside it and continue right, then left.
- Finish with the base type at the far left.
Five Declarations Every Student Must Know
| Declaration | Meaning | Memory the variable itself needs |
|---|---|---|
int *p; | p is a pointer to int | One pointer |
int **p; | p is a pointer to a pointer to int | One pointer |
int *p[20]; | p is an array of 20 pointers to int | Twenty pointers |
int (*p)[20]; | p is a pointer to an array of 20 ints | One pointer |
int *f(void); | f is a function returning a pointer to int | None; it is code, not data |
Pointer to Function Versus Function Returning Pointer
Every function pointer declaration in C hinges on one pair of parentheses. These two differ by only that pair, and mixing them up is among the most common mistakes in C.
| Declaration | Reading |
|---|---|
int *f(void); | f is a function (void) returning pointer to int |
int (*f)(void); | f is a pointer to a function (void) returning int |
int *(*f)(void); | f is a pointer to a function (void) returning pointer to int |
int (*f[2])(void); | f is an array of 2 pointers to functions returning int |
Prove It With a Program
Reading is one thing, but a program settles arguments. The next file declares each form, prints its size, and uses it. The sizes assume a 64-bit machine where a pointer is 8 bytes. Save it as ep_decl.c.
#include <stdio.h>
static int one(void)
{
return 1;
}
static int *pick(void)
{
static int v = 42;
return &v;
}
int main(void)
{
int *a[20]; /* array of 20 pointers to int */
int (*b)[20]; /* pointer to an array of 20 ints */
int arr[20] = { 0 };
int *(*fp)(void) = pick; /* pointer to function returning int * */
int (*gp)(void) = one; /* pointer to function returning int */
int (*tbl[2])(void) = { one, one }; /* array of 2 function ptrs */
b = &arr;
(*b)[3] = 9;
printf("sizeof a = %zu\n", sizeof a);
printf("sizeof b = %zu\n", sizeof b);
printf("sizeof fp = %zu\n", sizeof fp);
printf("sizeof tbl = %zu\n", sizeof tbl);
printf("arr[3] = %d\n", arr[3]);
printf("*fp() = %d\n", *fp());
printf("gp() = %d\n", gp());
printf("tbl[1]() = %d\n", tbl[1]());
return 0;
}
Build and Run
gcc -Wall -Wextra -std=c11 -pedantic -o ep_decl ep_decl.c
./ep_decl
Expected output:
sizeof a = 160
sizeof b = 8
sizeof fp = 8
sizeof tbl = 16
arr[3] = 9
*fp() = 42
gp() = 1
tbl[1]() = 1
What the Output Tells You
sizeof ais 160 because the array holds 20 pointers of 8 bytes each. The variable is a whole array.sizeof bis 8 because it is a single pointer that happens to point to an array of 20 ints.sizeof fpis 8: a pointer to a function is one address, no matter what the function returns.sizeof tblis 16: two function pointers.(*b)[3] = 9dereferences the pointer to reach the array, then subscripts it. The parentheses are required, because without them the subscript would apply to the pointer first.*fp()calls the function and then dereferences the pointer it returned, giving 42.
Taming Declarations With typedef
A typedef makes any function pointer declaration in C readable. Instead of decoding int *(*fp)(void) every time, name the pieces:
typedef int *(*getter_fn)(void); /* pointer to function returning int * */
getter_fn fp = pick; /* now an ordinary-looking declaration */
This is how production code handles it. The standard library itself, and most microcontroller vendor headers, rely on typedefs for callback types.
Tip: use a decoder while you learn
Programs like cdecl translate declarations to plain English and back. Use one to check yourself, but practise the reading method until you no longer need it, because interviewers will ask you to do it on paper.
Common Function Pointer Declaration in C Mistakes
| Mistake | Consequence | Fix |
|---|---|---|
Dropping the parentheses in int (*b)[20] | Declares an array of pointers instead | Wrap the star and the name |
Writing *b[3] when you mean (*b)[3] | Indexes the pointer, not the array it points to | Parenthesise the dereference |
Confusing int *f(void) and int (*f)(void) | Function versus pointer to function | Check where the star sits |
| Returning the address of a local variable from a function returning a pointer | Dangling pointer | Return a static, heap or caller-supplied object, as pick does |
| Writing one-line declarations with many levels | Unreadable code | Use typedef for each level |
Best Practices for Function Pointer Declaration in C
- Never write more than two levels of declarator without a typedef.
- Name function pointer typedefs with a suffix such as
_fnor_cb. - Compile with
-pedantic -Wall -Wextrato catch type mismatches. - When in doubt, print
sizeofand test with a small program.
Performance and Security Considerations
Declarations carry no run-time cost; the cost is in the code that uses them. For security, a returned pointer must refer to storage that outlives the call, and tables of function pointers should stay const.
Summary and Key Takeaways
- Start at the name, go right, then left, and leave each parenthesised group when finished.
- Brackets and parentheses bind tighter than the star.
int *p[20]is an array of pointers;int (*p)[20]is a pointer to an array.int *f(void)is a function;int (*f)(void)is a pointer to a function.- Typedef is the cure for an unreadable function pointer declaration in C.
Conclusion
With a consistent reading method, no function pointer declaration in C should intimidate you again. You also met the exact pairs that interviewers love to ask about. The final lecture of this chapter combines everything into a small embedded-style lab, an interrupt vector table, followed by a quiz and interview questions.
Frequently Asked Questions
What is the difference between int *p[20] and int (*p)[20]?
The first is an array of 20 pointers to int. The second is a single pointer to an array of 20 ints. The parentheses change which operator applies first.
How do I declare a pointer to a function returning a pointer?
Write int *(*fp)(void);. Read it as: fp is a pointer to a function with no arguments that returns a pointer to int.
How do I read a complex C declaration?
Find the name, go right for arrays and functions, go left for pointers, and leave each set of parentheses when you finish it.
Why does typedef help with function pointers?
It gives the whole type one short name, so variables, parameters and return types look like ordinary declarations.
Can a function return a function pointer?
Yes, but the raw syntax is ugly. Use a typedef for the pointer type and declare the function as returning that type.
Is the size of a function pointer related to the function’s return type?
No. Every function pointer holds one address, so its size is the platform’s pointer size regardless of the signature.
Master Embedded C Programming for Free
Next: an interrupt vector table lab, then a quiz and interview questions on function pointers.
Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.

2 Comments