C Notes
Understand what pointers are in C, why they are essential, how memory addresses work, and the fundamentals of pointer concepts with visual memory diagrams.
Pointers are often considered the most powerful — and most feared — feature of C programming. They give you direct access to memory, enable efficient data manipulation, and form the backbone of dynamic memory allocation, data structures, and system-level programming. Once you truly understand pointers, you'll see why C is the language of choice for operating systems, embedded systems, and performance-critical software.
What is a Pointer?
A pointer is a variable that stores the memory address of another variable. Instead of holding a data value directly (like 42 or 3.14), a pointer holds the location where that value lives in memory.
Think of it this way: if a variable is like a house, a pointer is like the address written on an envelope that tells you where the house is.
| int x = 42 | int *p = &x | |
|---|---|---|
| Addr: 1000 | Addr: 2000 |
Why Do We Need Pointers?
Pointers aren't just an academic exercise — they solve real problems that other approaches cannot:
| Use Case | Without Pointers | With Pointers |
|---|---|---|
| Modify variables in functions | Cannot (pass by value) | Can (pass by reference) |
| Dynamic memory allocation | Fixed-size arrays only | malloc/realloc for flexible sizes |
| Data structures | Limited | Linked lists, trees, graphs |
| String handling | Inflexible | Efficient manipulation |
| System programming | Impossible | Direct hardware access |
| Array efficiency | Copies data | Works with addresses |
Understanding Memory Addresses
Every variable in your program occupies one or more bytes in memory. Each byte has a unique address (like a house number on a street). You can see these addresses using the address-of operator &:
#include <stdio.h>
int main() {
int age = 25;
float gpa = 3.75;
char grade = 'A';
printf("Variable | Value | Address | Size\n");
printf("---------|-------|--------------|-----\n");
printf("age | %d | %p | %lu bytes\n", age, (void*)&age, sizeof(age));
printf("gpa | %.2f | %p | %lu bytes\n", gpa, (void*)&gpa, sizeof(gpa));
printf("grade | %c | %p | %lu bytes\n", grade, (void*)&grade, sizeof(grade));
return 0;
}Variable | Value | Address | Size ---------|-------|----------------|----- age | 25 | 0x7ffd4a3c8b4c | 4 bytes gpa | 3.75 | 0x7ffd4a3c8b48 | 4 bytes grade | A | 0x7ffd4a3c8b47 | 1 bytes
Memory Visualization
The Two Key Operators
Pointers rely on two fundamental operators:
1. Address-of Operator (&)
Gets the memory address of a variable:
int x = 42;
printf("Address of x: %p\n", (void*)&x); // e.g., 0x7ffd12342. Dereference Operator (*)
Accesses the value at the address stored in a pointer:
int x = 42;
int *p = &x; // p stores address of x
printf("Value at p: %d\n", *p); // 42 — follows the pointer to get the valueYour First Pointer Program
#include <stdio.h>
int main() {
int num = 100;
int *ptr = # // ptr now holds the address of num
printf("Value of num: %d\n", num);
printf("Address of num: %p\n", (void*)&num);
printf("Value of ptr (address it stores): %p\n", (void*)ptr);
printf("Value pointed to by ptr: %d\n", *ptr);
// Modify num through the pointer
*ptr = 200;
printf("\nAfter *ptr = 200:\n");
printf("Value of num: %d\n", num); // Changed!
return 0;
}Value of num: 100 Address of num: 0x7ffd5e8a1b2c Value of ptr (address it stores): 0x7ffd5e8a1b2c Value pointed to by ptr: 100 After *ptr = 200: Value of num: 200
Visual Explanation
| │ 0x1B2C ──┼──────── | │ 100 │ |
| │(addr | │ │(addr: │ |
| │ 0x1B2C ──┼──────── | │ 200 │ ← Modified through pointer! |
Size of Pointers
Regardless of the data type they point to, all pointers on a given system have the same size (determined by the architecture):
#include <stdio.h>
int main() {
printf("Size of int*: %lu bytes\n", sizeof(int*));
printf("Size of char*: %lu bytes\n", sizeof(char*));
printf("Size of float*: %lu bytes\n", sizeof(float*));
printf("Size of double*: %lu bytes\n", sizeof(double*));
printf("Size of void*: %lu bytes\n", sizeof(void*));
return 0;
}Size of int*: 8 bytes Size of char*: 8 bytes Size of float*: 8 bytes Size of double*: 8 bytes Size of void*: 8 bytes
On a 64-bit system, all pointers are 8 bytes. On a 32-bit system, all pointers are 4 bytes.
NULL Pointer
A pointer that doesn't point to any valid memory location should be set to NULL:
#include <stdio.h>
int main() {
int *ptr = NULL; // Safe initialization
if (ptr == NULL) {
printf("Pointer is NULL — not pointing to anything\n");
}
// NEVER dereference a NULL pointer!
// *ptr = 42; // CRASH: Segmentation fault
return 0;
}Pointer is NULL — not pointing to anything
Best Practice: Always initialize pointers to NULL if you don't have a valid address yet. This makes it easy to check if a pointer is safe to use.
Common Pointer Mistakes
| Mistake | What Happens |
|---|---|
| Using uninitialized pointer | Accesses random memory → crash or corruption |
| Dereferencing NULL | Segmentation fault |
| Dangling pointer (freed memory) | Undefined behavior |
| Wrong pointer type | Misinterpreting data |
Forgetting * in declaration | Creates regular variable, not pointer |
Pointer Analogy Summary
Interview Questions
Q1: What is the difference between a pointer and a variable?
A regular variable stores a data value (like an integer or float). A pointer stores a memory address — the location of another variable. The pointer allows indirect access to the value through dereferencing.
Q2: What happens when you dereference a NULL pointer?
It causes a segmentation fault (SIGSEGV) on most systems — the program crashes because NULL (address 0) is not a valid accessible memory location. Always check for NULL before dereferencing.
Q3: Why are all pointers the same size regardless of their type?
Because a pointer stores a memory address, and the address size depends only on the system architecture (32-bit = 4 bytes, 64-bit = 8 bytes). The type information tells the compiler how many bytes to read/write when dereferencing, but doesn't affect the pointer's own size.
Q4: What is a wild pointer?
A wild pointer is an uninitialized pointer that holds a garbage address. Dereferencing it leads to undefined behavior. Always initialize pointers to NULL or a valid address.
Summary
- A pointer stores the memory address of another variable
- The
&operator gets an address; the*operator dereferences (follows) an address - All pointers have the same size on a given architecture (4 bytes on 32-bit, 8 bytes on 64-bit)
- Always initialize pointers to NULL or a valid address to avoid wild pointers
- Pointers enable pass-by-reference, dynamic memory, and efficient data structures
- Never dereference a NULL pointer or an uninitialized pointer
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Introduction to Pointers in C Programming.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this C Programming topic.
Search Terms
c-programming, c programming, programming, pointers, introduction, introduction to pointers in c programming
Related C Programming Topics