π’ Reading C Pointer Declarations β Simple to Complex
0%
C Programming Β· Pointers Β· Declaration Syntax
Reading C Pointer Declarations
C pointer declarations look intimidating but follow three simple rules. Once you learn to read them right-to-left from the identifier, every declaration β no matter how complex β becomes readable in seconds. This lesson covers every type from the book.
π
Rule 1 β Start at name
Always begin at the identifier p. Then read outward using the spiral/clockwise rule.
β‘οΈ
Rule 2 β Right before left
[] and () on the right bind tighter than * on the left.
π
Rule 3 β Parentheses first
Parentheses around *p force pointer-ness before array or function.
Level 1 π’ Basic Pointer Declarations
D1
int *p
The most fundamental pointer β p is a pointer to an integer
Pointer to int
How to read it
Start at p. Look right β nothing. Look left β *. So p is a pointer. Look further left β int. So p is a pointer to an int. Done.
int*p;
* β p is a POINTER
int β points to integer
Plain English
p is a pointer to an integer quantity. It stores the address of an int variable.
d1_basic_pointer.c
C
#include <stdio.h>intmain() {
int x = 42;
int *p; /* p is a pointer to int */
p = &x; /* p now holds address of x */printf("value: %d\n", *p); /* dereference β 42 */printf("address: %p\n", (void*)p);
return0;
}
D2
int *p[10]
Array of pointers β [] beats * β p is an array, not a pointer
Array of Pointers
Start at p. Look right β [10] β p is a 10-element array. Look left β * β of pointers. Look left again β int β to integers. The [] on the right wins over * on the left because right-side operators bind first.
int*p[10];
[10] β array of 10 elements
* β each element is a pointer
int β pointer-to-integer
Plain English
p is a 10-element array of pointers to integer quantities. Each of the 10 slots holds the address of a different int.
d2_array_of_ptrs.c
C
#include <stdio.h>intmain() {
int a=1, b=2, c=3;
int *p[10]; /* 10-element array of int pointers */
p[0] = &a;
p[1] = &b;
p[2] = &c;
printf("%d %d %d\n", *p[0], *p[1], *p[2]); /* 1 2 3 */return0;
}
Key difference: int *p[10] vs int (*p)[10] Without parentheses β int *p[10] β p is an array of 10 pointers. With parentheses β int (*p)[10] β p is a pointer to a 10-element int array. Parentheses completely change the meaning.
D3
int (*p)[10]
Pointer to an array β parentheses force p to be the pointer
Pointer to Array
Parentheses around *p lock in pointer-ness first. Start at p. Parentheses say: go left first inside β * β p is a pointer. Now parentheses end. Go right β [10] β to a 10-element array. Go left β int β of integers.
int(*p)[10];
(*p) β p is a POINTER
[10] β to a 10-element array
int β array of integers
Plain English
p is a pointer to a 10-element integer array. This is used to iterate over 2D arrays row by row.
d3_ptr_to_array.c
C
#include <stdio.h>intmain() {
int matrix[3][10] = {{1,2},{3,4},{5,6}};
int (*p)[10] = matrix; /* p points to first ROW */printf("Row 0: %d %d\n", p[0][0], p[0][1]); /* 1 2 */
p++; /* advance by one FULL ROW */printf("Row 1: %d %d\n", p[0][0], p[0][1]); /* 3 4 */return0;
}
Function that returns a pointer β p is a function, not a pointer
Function β *int
Start at p. Look right β (void) β p is a function taking no arguments. Look left β * β returns a pointer. Look further left β int β to an integer. No parentheses around *p, so (void) on the right wins over *.
int*p(void);
(void) β p is a FUNCTION
void β takes no argument
* β returns a POINTER
int β to an integer
Plain English
p is a function that accepts no arguments and returns a pointer to an integer quantity.
d4_fn_returns_ptr.c
C
#include <stdio.h>#include <stdlib.h>int *p(void) { /* function returning int* */int *arr = (int*)malloc(5 * sizeof(int));
for(int i=0;i<5;i++) arr[i] = i * 10;
return arr; /* returns pointer to int */
}
intmain() {
int *result = p(); /* call function, get int* */printf("%d %d %d\n", result[0], result[1], result[2]);
free(result);
return0;
}
D5
int (*p)(void)
Pointer to a function β parentheses force p to be the pointer
Pointer to Function
Parentheses around *p lock in pointer-ness. Start at p. Inside parens go left β * β p is a pointer. Parens end. Go right β (void) β to a function taking no arguments. Go left β int β that returns int. This is how you declare a function pointer β use it to store and call functions dynamically.
int(*p)(void);
(*p) β p is a POINTER
(void) β to a FUNCTION taking no args
int β that returns integer
Plain English
p is a pointer to a function that accepts no arguments and returns an integer quantity.
d5_ptr_to_fn.c
C
#include <stdio.h>intsayHello(void) { printf("Hello!\n"); return1; }
intsayBye(void) { printf("Bye!\n"); return0; }
intmain() {
int (*p)(void); /* pointer to function()βint */
p = sayHello; /* point p at sayHello */
p(); /* call via pointer β Hello! */
p = sayBye; /* re-point at sayBye */
p(); /* call via pointer β Bye! */return0;
}
Function pointers are how C achieves runtime polymorphism β the same pointer variable p can call different functions depending on what it is assigned. This is the foundation of callbacks, dispatch tables, and plugin systems.
Level 3 π Functions with Parameters β char* and char*[]
D6
int p(char *a)
Function taking a char pointer, returning int β the simplest function with a param
fn(char*) β int
intp(char*a);
(char *a) β p is a FUNCTION
char *a β takes pointer to character
int β returns integer
Plain English
p is a function that accepts an argument which is a pointer to a character, and returns an integer quantity. Classic signature β e.g. strlen(char *s).
d6_fn_charptr.c
C
#include <stdio.h>/* p is a function(char *a) β int */intp(char *a) {
int count = 0;
while(*a++) count++; /* count chars until NULL */return count;
}
intmain() {
printf("Length: %d\n", p("Ananta")); /* 6 */return0;
}
D7
int *p(char *a)
Function takes char*, returns int* β function returning a pointer
fn(char*) β int*
int*p(char*a);
(char *a) β p is a FUNCTION
char *a β takes pointer to char
* β returns a POINTER
int β to an integer
Plain English
p is a function that accepts an argument which is a pointer to a character, and returns a pointer to an integer quantity.
D8
int (*p)(char *a)
Pointer to a function that takes char* and returns int
Ptr to fn(char*) β int
Now p is a pointer to a function. The parentheses around *p lock it as pointer first. Then (char *a) describes what function it points to: one that takes a pointer-to-char. And int on the far left is what that function returns.
int(*p)(char*a);
(*p) β p is a POINTER
(char *a) β to a FUNCTION taking char*
int β that returns integer
Plain English
p is a pointer to a function that accepts an argument which is a pointer to a character, and returns an integer quantity.
Function taking array of char pointers β the signature of main()
fn(char*[]) β int
The parameter char *a[] is an array of pointers to characters. a is [] β array, then * β of pointers, then char β to characters. This is exactly the type of argv in main(int argc, char *argv[]) β an array of strings.
intp(char*a[]);
p(...) β p is a FUNCTION
a[] β param is an ARRAY
char * β of pointers to char
int β returns integer
Plain English
p is a function that accepts an argument which is an array of pointers to characters, and returns an integer quantity. This is identical to main(int argc, char *argv[]).
d9_fn_argv_style.c
C
#include <stdio.h>/* p takes array of char pointers β like argv */intp(char *a[]) {
int i = 0;
while(a[i] != NULL) {
printf("[%d] %s\n", i, a[i]);
i++;
}
return i;
}
intmain() {
char *words[] = { "Apple", "Mango", "Banana", NULL };
int count = p(words);
printf("Count: %d\n", count); /* 3 */return0;
}
D10
int p(char (*a)[])
Function taking pointer to a character array β pointer to string
fn(ptr-to-char[]) β int
intp(char(*a)[]);
p(...) β p is a FUNCTION
(*a) β param a is a POINTER
[] β to a character array
int β returns integer
Plain English
p is a function that accepts an argument which is a pointer to a character array, and returns an integer quantity.
Level 5 π₯ Array of Function Pointers β Most Complex Forms
D11
int (*p[10])(void)
10-element array of pointers to functions β a dispatch table
Array of fn ptrs
Start at p. Look right inside parens β [10] β p is a 10-element array. Look left inside parens β * β of pointers. Parens end. Look right β (void) β to functions taking no args. Look left β int β each returning an integer. This is a dispatch table: 10 function pointers in one array.
int(*p[10])(void);
p[10] β array of 10 elements
* β each is a POINTER
(void) β to FUNCTIONS taking no args
int β each returns integer
Plain English
p is a 10-element array of pointers to functions; each function accepts no argument and returns an integer quantity.
d11_array_of_fn_ptrs.c
C β Dispatch Table
#include <stdio.h>intop0(void){ return0; }
intop1(void){ return1; }
intop2(void){ return4; }
intmain() {
/* 10-element array of pointers to fn()βint */int (*p[10])(void);
p[0] = op0; /* p[0] points to op0 */
p[1] = op1; /* p[1] points to op1 */
p[2] = op2; /* p[2] points to op2 */for(int i=0; i<3; i++)
printf("p[%d]() = %d\n", i, p[i]()); /* call each */return0;
}
output
p[0]() = 0
p[1]() = 1
p[2]() = 4
D12
int (*p[10])(char a)
10 function pointers, each taking a char and returning int
Array of fn(char) ptrs
int(*p[10])(char a);
p[10] β array of 10
* β pointers
(char a) β to fn taking a char
int β returning integer
Plain English
p is a 10-element array of pointers to functions; each function accepts an argument which is a character, and returns an integer quantity.
D13
int *(*p[10])(char *a)
The most complex form β array of function pointers, each returning int*
Array of fn(char*)βint* ptrs
Read step by step: p β look right inside parens β [10] β 10-element array β look left inside parens β * β of pointers β parens end β look right β (char *a) β to functions taking pointer-to-char β look left β * β each returns a pointer β look far left β int β to an integer.
int*(*p[10])(char*a);
p[10] β array of 10
* inside () β each is a pointer
(char *a) β to fn taking char*
* outside β each returns a POINTER
int β to an integer
Plain English
p is a 10-element array of pointers to functions; each function accepts an argument which is a pointer to a character, and returns a pointer to an integer quantity. The most complex declaration from the book.
Summary π Quick Reference β All Declarations at a Glance
The Clockwise/Spiral Rule β 3 Steps
Step 1 β Start at the identifier (p). Say "p isβ¦"
Step 2 β Go right first: if you see [n] β "array of n", if you see (β¦) β "function takingβ¦". Hit closing paren or end? Stop going right.
Step 3 β Go left: if you see * β "pointer to". If you see a type name (int, char) β that's what it points to or returns. If there are parens around *p β go left inside the parens first, then continue outward.
Repeat steps 2β3 spiralling outward until you have read the entire declaration.
int *p
p is a pointer to int
int *p[10]
p is array[10] of int pointers
int (*p)[10]
p is pointer to int[10] array
int *p(void)
p is function() returning int*
int (*p)(void)
p is pointer to function()βint
int p(char *a)
p is function(char*)βint
int *p(char *a)
p is function(char*)βint*
int (*p)(char *a)
p is pointer to function(char*)βint
int p(char *a[])
p is function(char*[])βint (like main)
int (*p[10])(void)
p is array[10] of ptrs to fn()βint
int (*p[10])(char a)
p is array[10] of ptrs to fn(char)βint
int *(*p[10])(char *a)
p is array[10] of ptrs to fn(char*)βint*
Parentheses change everything.int *p[10] and int (*p)[10] look almost identical but mean completely different things. The first is an array of pointers; the second is a pointer to an array. When in doubt, add parentheses around *p to force pointer-ness.
checklist
Reading rule: Start at identifier p β go right first ([] and () bind before *) β go left (* = pointer, type = what it points to). Repeat spiralling outward.
D1 β int *p: p is a pointer to int. The simplest case. * on the left of p with nothing on the right.
D2 β int *p[10]: p is an ARRAY of 10 pointers to int. [] on right beats * on left β p is array first.
D3 β int (*p)[10]: p is a POINTER to a 10-element int array. Parens force pointer before []. Opposite of D2.
D4 β int *p(void): p is a FUNCTION taking no args, returning int*. () on right beats * β p is function first.
D5 β int (*p)(void): p is a POINTER to a function()βint. Parens force pointer before (). Function pointer.
D8 β int (*p)(char *a): p is a pointer to a function taking char* and returning int. Function pointer with parameter.
D9 β int p(char *a[]): p is a function taking array of char pointers (= char**). Exactly like main()'s argv.
D11 β int (*p[10])(void): p is a 10-element array of pointers to fn()βint. A dispatch table. Read p[10] first (array), then * (of pointers), then (void) (to functions).
D13 β int *(*p[10])(char *a): p is array[10] of pointers to functions(char*)βint*. Most complex. Two *: one for the pointer-to-function, one for the return type.