100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
C

Pointers in C

Learn C pointers with syntax, address-of and dereference operators, pointer arithmetic, and common pitfalls, with examples and output.

Pointers, Structures & UnionsIntermediate14 min readJul 7, 2026
Analogies

1. Introduction

A pointer in C is a variable that stores the memory address of another variable instead of storing a value directly. Pointers are one of the most powerful and distinctive features of C, enabling direct memory access, efficient array traversal, dynamic memory allocation, call-by-reference function semantics, and the construction of data structures such as linked lists and trees. Understanding pointers deeply is essential for mastering systems-level programming and for reasoning about how C programs actually use memory at runtime.

🏏

Cricket analogy: A pointer is like a fielding position card that tells you where a player stands rather than the player themselves, letting a captain like Rohit Sharma redirect fielders efficiently without physically moving each one manually.

2. Syntax

A pointer variable is declared by prefixing the variable name with an asterisk (*), and its type must match the type of the variable it points to: dataType *pointerName;. The address-of operator (&) retrieves the memory address of a variable, and the dereference operator (*) retrieves (or sets) the value stored at the address a pointer holds. For example: int x = 10; int *p = &x; assigns the address of x to p, and *p accesses the integer value stored at that address. Pointer arithmetic (p++, p + n) moves the pointer by multiples of sizeof(dataType), not by raw bytes, which is what makes pointers so convenient for array traversal.

🏏

Cricket analogy: Declaring int *p is like a scorer writing 'pointer to Kohli's stats' on a card; &x is like calling out Kohli's seat number in the dugout, and *p is like reading his actual current score from that seat; p++ then moves the reference to the next batter's slot, not by a fixed number of physical rows.

3. Explanation

Every variable in a running C program occupies a location in memory identified by an address; a pointer simply stores that address as its value. The asterisk (*) plays two different roles in C: in a declaration such as int *p, it marks p as a pointer to int; in an expression such as *p = 5, it dereferences p, meaning 'the value at the address p points to'. This dual meaning often confuses beginners, so it helps to read declarations right-to-left: 'p is a pointer to int'. Operator precedence also matters: in the expression *ptr++, the postfix ++ binds tighter than the dereference *, so the expression first advances ptr to the next element and then dereferences the original address (equivalent to *(ptr++)), whereas (*ptr)++ dereferences first and increments the value pointed to. Pointers also enable call-by-reference: passing &variable to a function lets that function modify the caller's original variable through the pointer, unlike normal call-by-value arguments which only receive copies.

🏏

Cricket analogy: Reading a pointer declaration right-to-left is like reading a scoreboard note 'p, pointer to runs' as 'p is a pointer to runs'; and passing a fielder's actual position (call-by-reference via &variable) lets the captain adjust it directly, unlike shouting instructions to a stand-in copy who can't actually move.

A wild or uninitialized pointer is a pointer that has been declared but not assigned a valid address (e.g., int *p; without initialization). Dereferencing such a pointer, or a pointer that has already been freed or gone out of scope (a dangling pointer), reads or writes to an unpredictable memory location. This is undefined behavior in C: it may appear to 'work' during testing, corrupt unrelated data, or crash the program with a segmentation fault. Always initialize pointers (e.g., to NULL) and check them before dereferencing, and set a pointer to NULL immediately after freeing the memory it referenced.

Tip: Use the format specifier %p with printf to print a pointer's address, and always cast the pointer argument to (void *) for portability: printf("%p\n", (void *)p);. This avoids undefined behavior across compilers where the internal representation of pointer types can differ.

4. Example

c
#include <stdio.h>

void increment(int *n) {
    (*n)++;              /* modifies the caller's variable via the pointer */
}

int main(void) {
    int x = 10;
    int *p = &x;          /* p now holds the address of x */

    printf("Before: x = %d, *p = %d\n", x, *p);

    *p = 25;              /* dereference p to change x indirectly */
    printf("After *p = 25: x = %d\n", x);

    increment(&x);         /* pass address so the function can modify x */
    printf("After increment(&x): x = %d\n", x);

    int arr[3] = {1, 2, 3};
    int *ap = arr;          /* array name decays to pointer to first element */
    for (int i = 0; i < 3; i++) {
        printf("arr[%d] = %d (via *(ap + %d) = %d)\n", i, arr[i], i, *(ap + i));
    }

    return 0;
}

5. Output

text
Before: x = 10, *p = 10
After *p = 25: x = 25
After increment(&x): x = 26
arr[0] = 1 (via *(ap + 0) = 1)
arr[1] = 2 (via *(ap + 1) = 2)
arr[2] = 3 (via *(ap + 2) = 3)

6. Key Takeaways

  • A pointer stores a memory address, not a value; & gets an address and * dereferences it.
  • Pointer arithmetic moves in units of sizeof(dataType), which is what makes array traversal via pointers work naturally.
  • Passing &variable to a function enables call-by-reference, letting the function modify the caller's data.
  • Always initialize pointers and never dereference uninitialized, dangling, or NULL pointers.
  • Array names decay to a pointer to their first element in most expressions, linking arrays and pointers closely in C.

Practice what you learned

Was this page helpful?

Topics covered

#CProgrammingStudyNotes#Programming#PointersInC#Pointers#Syntax#Explanation#Example#StudyNotes#SkillVeris#ExamPrep