Pointers in C
The most powerful feature in C! Pointers store memory addresses. Learn what they are, why they matter, and how to use them safely.
What You Will Learn
- ✓Understand what pointers are (address holders)
- ✓Use & to get address, * to get value
- ✓Declare and initialize pointers
- ✓Understand NULL pointers and why they matter
01What is a Pointer?
A pointer is a variable that stores the memory address of another variable. Instead of holding data directly, it "points to" where the data is stored in memory.
Variable vs Pointer
Regular Variable
Stores the actual value
Pointer Variable
Stores the address of another variable
Why Use Pointers?
- • Efficiency: Pass large data without copying
- • Dynamic Memory: Allocate memory at runtime
- • Data Structures: Build linked lists, trees, graphs
- • Function Parameters: Modify variables from functions
🏠 Real-World Analogy: House Addresses
Think of memory like a street with houses:
Regular Variable = House Contents
Like the furniture inside a house. You store actual things (data) in it.
Pointer = House Address
Like a piece of paper with an address written on it. It doesn't contain furniture, but tells you where to find it!
Just like you can give someone your address (pointer) instead of moving your entire house (copying data), pointers let you share location instead of duplicating data!
02Understanding Memory Addresses
Every variable in your program is stored at a specific location in memory. This location has a unique address (like a house number on a street).
1#include <stdio.h>23int main() {4 int age = 25;5 float price = 99.99;6 char grade = 'A';7 8 // Print the VALUE of variables9 printf("age = %d\n", age);10 printf("price = %.2f\n", price);11 printf("grade = %c\n", grade);12 13 // Print the ADDRESS of variables using & operator14 printf("\nAddress of age: %p\n", (void*)&age);15 printf("Address of price: %p\n", (void*)&price);16 printf("Address of grade: %p\n", (void*)&grade);17 18 return 0;19}Sample Output:
price = 99.99
grade = A
Address of age: 0x7ffd5e8e3a4c
Address of price: 0x7ffd5e8e3a48
Address of grade: 0x7ffd5e8e3a47
The & Operator (Address-of)
&variable returns the memory address of a variable. The address is shown in hexadecimal format (0x...).
03Declaring and Initializing Pointers
1#include <stdio.h>23int main() {4 // Step 1: Create a regular variable5 int num = 42;6 7 // Step 2: Declare a pointer (use * in declaration)8 int *ptr; // ptr can store address of an int9 10 // Step 3: Assign address to pointer (use & to get address)11 ptr = # // ptr now "points to" num12 13 // Combined declaration and initialization14 int value = 100;15 int *p = &value; // Declare and initialize in one line16 17 // Print to verify18 printf("num = %d\n", num); // Value: 4219 printf("&num = %p\n", (void*)&num); // Address of num20 printf("ptr = %p\n", (void*)ptr); // Same address (ptr stores it)21 printf("*ptr = %d\n", *ptr); // Value at that address: 4222 23 return 0;24}🔍 How This Program Works
int num = 42 — Creates a variable storing 42 at some memory address (e.g., 0x1000).
int *ptr — Declares a pointer variable. The * means "pointer to int". Currently contains garbage.
ptr = &num — The & gets num's address (0x1000). Now ptr stores that address.
printf("%p", ptr) — Prints what ptr contains: the address 0x1000 (same as &num).
*ptr — The * dereferences: "go to address in ptr and get the value there" → returns 42.
Pointer Syntax Summary
| Syntax | Meaning | Example |
|---|---|---|
| int *ptr; | Declare pointer to int | Creates pointer variable |
| &num | Get address of num | Returns 0x7ffd... |
| ptr = # | Store address in ptr | ptr points to num |
| *ptr | Get value at address (dereference) | Returns 42 |
04Dereferencing Pointers (*)
Dereferencing means accessing the value stored at the address the pointer holds. Use the * operator.
1#include <stdio.h>23int main() {4 int x = 10;5 int *ptr = &x; // ptr points to x6 7 // Reading via pointer8 printf("Value of x: %d\n", x); // Direct: 109 printf("Value via *ptr: %d\n", *ptr); // Via pointer: 1010 11 // Modifying via pointer12 *ptr = 50; // Changes the value at address (changes x!)13 14 printf("\nAfter *ptr = 50:\n");15 printf("Value of x: %d\n", x); // Now 50!16 printf("Value via *ptr: %d\n", *ptr); // Also 5017 18 // Both x and *ptr refer to the same memory location19 x = 100;20 printf("\nAfter x = 100:\n");21 printf("Value via *ptr: %d\n", *ptr); // 10022 23 return 0;24}Output:
Value via *ptr: 10
After *ptr = 50:
Value of x: 50
Value via *ptr: 50
After x = 100:
Value via *ptr: 100
🔍 How Dereferencing Works
int *ptr = &x — ptr now holds x's memory address. Both x and *ptr refer to the same location.
*ptr (reading) — "Go to the address stored in ptr and read what's there" → returns 10.
*ptr = 50 (writing) — "Go to the address stored in ptr and write 50 there". This changes x!
After *ptr = 50, printing x shows 50 — proof that x and *ptr are the same memory.
Changing x = 100 also makes *ptr return 100. They're always in sync!
The * Has Two Meanings!
- • In declaration:
int *ptr;— defines a pointer - • In expression:
*ptr— dereferences (gets value)
05Pointer Memory Layout
A pointer is itself a variable that takes up memory. On most modern systems, pointers are 8 bytes (64-bit) or 4 bytes (32-bit).
int x = 42; int *ptr = &x;
Variable x
@0x1000
4 bytes
Pointer ptr
@0x2000
8 bytes (64-bit)
ptr stores the address 0x1000, which is where x lives in memory
1#include <stdio.h>23int main() {4 int x = 42;5 int *ptr = &x;6 7 printf("Size of int: %zu bytes\n", sizeof(int)); // 48 printf("Size of int*: %zu bytes\n", sizeof(int*)); // 8 (on 64-bit)9 printf("Size of ptr: %zu bytes\n", sizeof(ptr)); // 810 11 // All pointer types are the same size!12 char *cp;13 double *dp;14 printf("\nSize of char*: %zu bytes\n", sizeof(cp)); // 815 printf("Size of double*: %zu bytes\n", sizeof(dp)); // 816 17 return 0;18}06Pointer Arithmetic
You can add or subtract integers from pointers. The pointer moves by the size of the data type it points to.
1#include <stdio.h>23int main() {4 int arr[5] = {10, 20, 30, 40, 50};5 int *ptr = arr; // Points to first element6 7 printf("ptr points to: %d (address: %p)\n", *ptr, (void*)ptr);8 9 // ptr + 1 moves by sizeof(int) = 4 bytes10 ptr++; // or ptr = ptr + 111 printf("After ptr++: %d (address: %p)\n", *ptr, (void*)ptr);12 13 ptr++;14 printf("After ptr++: %d (address: %p)\n", *ptr, (void*)ptr);15 16 // Can also use pointer arithmetic directly17 printf("\nUsing arr pointer arithmetic:\n");18 printf("*(arr + 0) = %d\n", *(arr + 0)); // 1019 printf("*(arr + 1) = %d\n", *(arr + 1)); // 2020 printf("*(arr + 2) = %d\n", *(arr + 2)); // 3021 22 // arr[i] is equivalent to *(arr + i)23 printf("\narr[3] = %d, *(arr + 3) = %d\n", arr[3], *(arr + 3));24 25 return 0;26}Pointer Arithmetic Visualization
+0
+4
+8
+12
+16
ptr → ptr+1 → ptr+2 → ptr+3 → ptr+4
Each step moves by sizeof(int) = 4 bytes
07Pointers and Arrays
Arrays and pointers are closely related. The array name is actually a pointer to its first element!
1#include <stdio.h>23int main() {4 int arr[5] = {10, 20, 30, 40, 50};5 6 // Array name IS a pointer to first element7 printf("arr = %p\n", (void*)arr);8 printf("&arr[0] = %p\n", (void*)&arr[0]); // Same address!9 10 // These are equivalent ways to access elements:11 printf("\nAccessing arr[2]:\n");12 printf("arr[2] = %d\n", arr[2]); // Subscript notation13 printf("*(arr + 2) = %d\n", *(arr + 2)); // Pointer arithmetic14 15 // Using a separate pointer16 int *ptr = arr; // No & needed - arr is already an address17 18 printf("\nUsing pointer:\n");19 for (int i = 0; i < 5; i++) {20 printf("ptr[%d] = %d, *(ptr + %d) = %d\n", 21 i, ptr[i], i, *(ptr + i));22 }23 24 return 0;25}Key Equivalences
- •
arr[i]≡*(arr + i) - •
&arr[i]≡arr + i - •
arr≡&arr[0]
08NULL Pointer
A NULL pointer is a pointer that doesn't point to any valid memory location. It's used to indicate "no value" or "not pointing to anything".
1#include <stdio.h>2#include <stdlib.h> // For NULL34int main() {5 int *ptr = NULL; // Initialize to NULL6 7 // Always check before dereferencing!8 if (ptr == NULL) {9 printf("ptr is NULL - cannot dereference!\n");10 } else {11 printf("Value: %d\n", *ptr);12 }13 14 // Now point to something valid15 int x = 42;16 ptr = &x;17 18 if (ptr != NULL) {19 printf("ptr is valid, value: %d\n", *ptr);20 }21 22 // Common pattern: set to NULL after freeing23 // free(ptr); // If dynamically allocated24 ptr = NULL; // Prevent dangling pointer25 26 return 0;27}⚠️ Never Dereference NULL!
Dereferencing a NULL pointer causes a segmentation fault (crash). Always check if a pointer is NULL before using *ptr.
09Common Pointer Mistakes
❌ Uninitialized Pointer (Wild Pointer)
int *ptr; // Points to random memory!*ptr = 10; // CRASH - undefined behavior// Always initialize:int *ptr = NULL; // Safe❌ Dangling Pointer
int *ptr;{ int x = 10; ptr = &x;} // x is destroyed here!printf("%d", *ptr); // UNDEFINED - x no longer exists❌ Mismatched Pointer Types
float f = 3.14;int *ptr = &f; // WARNING - type mismatch!// Correct:float *ptr = &f; // Types must match❌ Forgetting & in scanf
int x;scanf("%d", x); // WRONG! Missing &scanf("%d", &x); // Correct - pass address10Summary
What You Learned:
- ✓Pointer: Variable that stores memory address
- ✓& operator: Gets address of a variable
- ✓* operator: Dereferences (gets value at address)
- ✓Pointer size: 8 bytes on 64-bit, 4 bytes on 32-bit
- ✓Pointer arithmetic: ptr+1 moves by sizeof(type)
- ✓NULL: Special value meaning "points to nothing"
11Next Steps
Continue learning about other derived data types: