πŸ”’ 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>
int main() {
    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);
    return 0;
}
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>
int main() {
    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 */
    return 0;
}
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>
int main() {
    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 */
    return 0;
}
Level 2 🟑 Functions β€” Returning Pointers & Pointers to Functions
D4
int *p(void)
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  */
}

int main() {
    int *result = p();    /* call function, get int* */
    printf("%d %d %d\n", result[0], result[1], result[2]);
    free(result);
    return 0;
}
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>

int sayHello(void) { printf("Hello!\n"); return 1; }
int sayBye(void)   { printf("Bye!\n");   return 0; }

int main() {
    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!   */
    return 0;
}
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
int p(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 */
int p(char *a) {
    int count = 0;
    while(*a++) count++;   /* count chars until NULL */
    return count;
}

int main() {
    printf("Length: %d\n", p("Ananta")); /* 6 */
    return 0;
}
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.
d8_ptr_to_fn_charptr.c
C
#include <stdio.h>
#include <string.h>

int myLen(char *s) { return (int)strlen(s); }
int myVow(char *s) {  /* count vowels */
    int n=0;
    while(*s){ if(strchr("aeiouAEIOU",*s)) n++; s++; }
    return n;
}

int main() {
    int (*p)(char *a);  /* pointer to fn(char*)β†’int */

    p = myLen;
    printf("Length : %d\n", p("Ananta")); /* 6  */

    p = myVow;
    printf("Vowels : %d\n", p("Ananta")); /* 3  */
    return 0;
}
Level 4 πŸ”΄ Array Parameters β€” char *a[] and char (*a)[]
D9
int p(char *a[])
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.
int p(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 */
int p(char *a[]) {
    int i = 0;
    while(a[i] != NULL) {
        printf("[%d] %s\n", i, a[i]);
        i++;
    }
    return i;
}

int main() {
    char *words[] = { "Apple", "Mango", "Banana", NULL };
    int count = p(words);
    printf("Count: %d\n", count);  /* 3 */
    return 0;
}
D10
int p(char (*a)[])
Function taking pointer to a character array β€” pointer to string
fn(ptr-to-char[]) β†’ int
int p(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>

int op0(void){ return 0; }
int op1(void){ return 1; }
int op2(void){ return 4; }

int main() {
    /* 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 */
    return 0;
}
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.