Docs
Pointers and Arrays
Pointers and Arrays in C
Table of Contents
- ā¢Introduction
- ā¢Array Names as Pointers
- ā¢Pointer Arithmetic
- ā¢Array Access Methods
- ā¢Differences Between Arrays and Pointers
- ā¢Pointers with 2D Arrays
- ā¢Array of Pointers
- ā¢Pointer to Array
- ā¢Common Patterns
- ā¢Best Practices
- ā¢Summary
Introduction
Arrays and pointers are closely related in C. Understanding their relationship is crucial for:
- ā¢Efficient array manipulation
- ā¢Passing arrays to functions
- ā¢Dynamic memory allocation
- ā¢String handling
- ā¢Building complex data structures
Array Names as Pointers
The Fundamental Connection
An array name acts as a constant pointer to the first element.
int arr[5] = {10, 20, 30, 40, 50};
arr ā pointer to arr[0]
&arr[0] ā same address as arr
*arr ā value of arr[0] (10)
Visual Representation
int arr[5] = {10, 20, 30, 40, 50};
Memory Layout:
Address: 1000 1004 1008 1012 1016
āāāāāāāāāāā¬āāāāāāāāāā¬āāāāāāāāāā¬āāāāāāāāāā¬āāāāāāāāāā
ā 10 ā 20 ā 30 ā 40 ā 50 ā
āāāāāāāāāāā“āāāāāāāāāā“āāāāāāāāāā“āāāāāāāāāā“āāāāāāāāāā
arr[0] arr[1] arr[2] arr[3] arr[4]
ā
arr (points here, address 1000)
Demonstration
int arr[5] = {10, 20, 30, 40, 50};
printf("%p\n", arr); // Address of first element
printf("%p\n", &arr[0]); // Same address!
printf("%d\n", *arr); // 10 (value at first element)
printf("%d\n", arr[0]); // 10 (same value)
Pointer Arithmetic
How Pointer Arithmetic Works
When you add/subtract from a pointer, it moves by the size of the type.
int arr[5] = {10, 20, 30, 40, 50};
int *ptr = arr;
ptr + 1 ā Address of arr[1] (moves 4 bytes for int)
ptr + 2 ā Address of arr[2] (moves 8 bytes)
ptr + n ā Address of arr[n]
Mathematical Formula
New Address = Base Address + (n Ć sizeof(type))
For int arr[] and int *ptr = arr:
ptr + 1 = 1000 + (1 Ć 4) = 1004
ptr + 2 = 1000 + (2 Ć 4) = 1008
Operators on Pointers
| Operation | Meaning | Example |
|---|---|---|
ptr + n | Address n elements after | ptr + 3 ā 4th element |
ptr - n | Address n elements before | ptr - 2 ā 2 elements back |
ptr++ | Move to next element | Advance pointer |
ptr-- | Move to previous element | Move back |
ptr2 - ptr1 | Number of elements between | Distance |
Incrementing Pointers
int arr[5] = {10, 20, 30, 40, 50};
int *ptr = arr;
printf("%d\n", *ptr); // 10
ptr++;
printf("%d\n", *ptr); // 20
ptr++;
printf("%d\n", *ptr); // 30
Type-Specific Movement
char *cp = (char*)1000;
int *ip = (int*)1000;
double *dp = (double*)1000;
cp + 1 ā 1001 (moves 1 byte)
ip + 1 ā 1004 (moves 4 bytes)
dp + 1 ā 1008 (moves 8 bytes)
Array Access Methods
Four Equivalent Ways to Access Elements
int arr[5] = {10, 20, 30, 40, 50};
int *ptr = arr;
// All of these access arr[2] (value 30):
arr[2] // Array indexing
*(arr + 2) // Pointer arithmetic on array name
ptr[2] // Indexing with pointer
*(ptr + 2) // Pointer arithmetic on pointer
The Equivalence
// The compiler converts array notation to pointer arithmetic:
arr[i] ā” *(arr + i)
ptr[i] ā” *(ptr + i)
// This even works:
2[arr] ā” *(2 + arr) ā” *(arr + 2) // Valid but confusing!
Loop Examples
int arr[5] = {10, 20, 30, 40, 50};
// Method 1: Array indexing
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
// Method 2: Pointer with indexing
int *ptr = arr;
for (int i = 0; i < 5; i++) {
printf("%d ", ptr[i]);
}
// Method 3: Pointer arithmetic
ptr = arr;
for (int i = 0; i < 5; i++) {
printf("%d ", *(ptr + i));
}
// Method 4: Incrementing pointer
ptr = arr;
for (int i = 0; i < 5; i++) {
printf("%d ", *ptr++);
}
// Method 5: Pointer comparison
for (int *p = arr; p < arr + 5; p++) {
printf("%d ", *p);
}
Differences Between Arrays and Pointers
Despite their similarities, arrays and pointers have important differences.
Key Differences
| Aspect | Array | Pointer |
|---|---|---|
| Size | sizeof(arr) = total bytes | sizeof(ptr) = pointer size |
| Assignment | Cannot reassign | Can reassign |
| Memory | Allocates space for elements | Only stores an address |
| Address | &arr is array address | &ptr is pointer's address |
sizeof Difference
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;
sizeof(arr) ā 20 (5 Ć 4 bytes)
sizeof(ptr) ā 8 (pointer size on 64-bit)
// Calculate array length
int length = sizeof(arr) / sizeof(arr[0]); // 5
Assignment Difference
int arr[5] = {1, 2, 3, 4, 5};
int arr2[5] = {6, 7, 8, 9, 10};
int *ptr = arr;
ptr = arr2; // OK - pointer can be reassigned
arr = arr2; // ERROR! Array name is constant
Address Difference
int arr[5];
int *ptr = arr;
arr ā Address of first element (e.g., 1000)
&arr ā Address of entire array (1000, but different type!)
&arr[0] ā Address of first element (1000)
ptr ā Value stored in ptr (1000)
&ptr ā Address of ptr itself (different, e.g., 2000)
Visual: &arr vs arr
int arr[5];
arr and &arr have same value but different types:
arr ā int* (pointer to int)
&arr ā int (*)[5] (pointer to array of 5 ints)
arr + 1 moves 4 bytes (to next int)
&arr + 1 moves 20 bytes (past entire array!)
Pointers with 2D Arrays
Memory Layout of 2D Arrays
2D arrays are stored in row-major order (rows are contiguous).
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
Memory (contiguous):
āāāāā¬āāāā¬āāāā¬āāāā¬āāāā¬āāāā¬āāāā¬āāāā¬āāāā¬āāāā¬āāāā¬āāāā
ā 1 ā 2 ā 3 ā 4 ā 5 ā 6 ā 7 ā 8 ā 9 ā10 ā11 ā12 ā
āāāāā“āāāā“āāāā“āāāā“āāāā“āāāā“āāāā“āāāā“āāāā“āāāā“āāāā“āāāā
[0][0]....[0][3] [1][0]....[1][3] [2][0]....[2][3]
āāā row 0 āāā āāā row 1 āāā āāā row 2 āāā
Accessing 2D Array with Pointers
int matrix[3][4] = {...};
// matrix is pointer to first row (array of 4 ints)
// matrix[0] is pointer to first element of first row
// These are equivalent:
matrix[i][j]
*(*(matrix + i) + j)
*(matrix[i] + j)
*((int*)matrix + i * 4 + j) // Flat access
Pointer to First Element
int matrix[3][4];
int *ptr = &matrix[0][0]; // or (int*)matrix
// Access any element:
*(ptr + i * 4 + j) // matrix[i][j]
Pointer to Row
int matrix[3][4];
int (*rowPtr)[4] = matrix; // Pointer to array of 4 ints
rowPtr[0] ā First row
rowPtr[1] ā Second row
rowPtr[1][2] ā Element at row 1, column 2
Array of Pointers
An array of pointers stores addresses instead of values.
Declaration
int *ptrArray[5]; // Array of 5 pointers to int
Common Use: String Array
char *names[] = {
"Alice",
"Bob",
"Charlie"
};
// Each element is a pointer to a string
Visual Representation
char *names[] = {"Alice", "Bob", "Charlie"};
Array of Pointers: Strings in Memory:
āāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāā
ā names[0] āāāā¼āāāāāāāāāāā ā "Alice\0" ā
āāāāāāāāāāāāāā⤠āāāāāāāāāāāāāāāāā
ā names[1] āāāā¼āāāāāāāāāāā āāāāāāāāāāāāāāāāā
āāāāāāāāāāāāāā⤠ā "Bob\0" ā
ā names[2] āāāā¼āāāāāāāāāāā āāāāāāāāāāāāāāāāā
āāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāā
ā "Charlie\0" ā
āāāāāāāāāāāāāāāāā
Ragged Arrays
Array of pointers can point to arrays of different lengths.
int row0[] = {1, 2};
int row1[] = {3, 4, 5, 6};
int row2[] = {7, 8, 9};
int *rows[] = {row0, row1, row2};
// row0 has 2 elements
// row1 has 4 elements
// row2 has 3 elements
Pointer to Array
Declaration
int (*ptr)[5]; // Pointer to array of 5 ints
Difference from Array of Pointers
int *ptr[5]; // Array of 5 pointers to int
int (*ptr)[5]; // Pointer to array of 5 ints
// The parentheses matter!
Usage with 2D Arrays
int matrix[3][5];
int (*ptr)[5] = matrix; // Pointer to row (array of 5 ints)
ptr[0] ā First row
ptr[1] ā Second row
ptr[1][2] ā Element at row 1, column 2
Visual Comparison
int *ptr[5]; Array of 5 pointers
āāāāāāā¬āāāāāā¬āāāāāā¬āāāāāā¬āāāāāā
ā ptr ā ptr ā ptr ā ptr ā ptr ā 5 separate pointers
āāāāāāā“āāāāāā“āāāāāā“āāāāāā“āāāāāā
int (*ptr)[5]; Pointer to array of 5
āāāāāāā
ā ptr ā āāā āāāāā¬āāāā¬āāāā¬āāāā¬āāāā
āāāāāāā ā ā ā ā ā ā One array of 5 ints
āāāāā“āāāā“āāāā“āāāā“āāāā
Common Patterns
Pattern 1: Traversing Array with Pointer
void printArray(int *arr, int size) {
int *end = arr + size;
while (arr < end) {
printf("%d ", *arr);
arr++;
}
printf("\n");
}
Pattern 2: Find Element
int* findElement(int *arr, int size, int target) {
int *end = arr + size;
for (int *p = arr; p < end; p++) {
if (*p == target) return p;
}
return NULL;
}
Pattern 3: Reverse Array
void reverseArray(int *arr, int size) {
int *left = arr;
int *right = arr + size - 1;
while (left < right) {
int temp = *left;
*left = *right;
*right = temp;
left++;
right--;
}
}
Pattern 4: Copy Array
void copyArray(int *dest, const int *src, int size) {
const int *end = src + size;
while (src < end) {
*dest++ = *src++;
}
}
Pattern 5: Two-Pointer Technique
// Remove duplicates from sorted array
int removeDuplicates(int *arr, int size) {
if (size == 0) return 0;
int *write = arr + 1;
int *read = arr + 1;
int *end = arr + size;
while (read < end) {
if (*read != *(read - 1)) {
*write++ = *read;
}
read++;
}
return write - arr;
}
Best Practices
1. Prefer Array Notation for Clarity
// Clear
arr[i] = value;
// Less clear (though equivalent)
*(arr + i) = value;
2. Use Pointer Arithmetic for Traversal
// Good for sequential access
for (int *p = arr; p < arr + size; p++) {
process(*p);
}
3. Don't Forget Size Information
// Always pass size when array decays to pointer
void processArray(int *arr, int size);
4. Use const for Read-Only Access
void printArray(const int *arr, int size);
5. Be Careful with Pointer Comparisons
// Only compare pointers to same array
int arr1[5], arr2[5];
int *p1 = arr1;
int *p2 = arr2;
p1 < p2; // UNDEFINED! Different arrays
6. Avoid Out-of-Bounds Access
int arr[5];
int *ptr = arr;
ptr + 5; // OK (one past end, for comparison)
*(ptr + 5); // UNDEFINED! Out of bounds
Summary
Key Relationships
int arr[5] = {10, 20, 30, 40, 50};
int *ptr = arr;
// These are equivalent:
arr[i] ā” *(arr + i)
ptr[i] ā” *(ptr + i)
&arr[i] ā” arr + i ā” ptr + i
Memory Concepts
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Array elements are contiguous in memory ā
ā Pointer arithmetic moves by sizeof(type) bytes ā
ā Array name is a constant pointer to first element ā
ā Array decays to pointer when passed to functions ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Quick Reference
| Expression | Type | Meaning |
|---|---|---|
arr | int* | Address of first element |
&arr | int(*)[N] | Address of entire array |
arr + i | int* | Address of arr[i] |
*arr | int | Value of arr[0] |
arr[i] | int | Value at index i |
*(arr + i) | int | Same as arr[i] |
Next Steps
After mastering pointers and arrays:
- ā¢Study Pointer to Pointer (double pointers)
- ā¢Learn Dynamic Memory Allocation (malloc, free)
- ā¢Explore Function Pointers
- ā¢Practice String manipulation with pointers
"In C, arrays and pointers are different, but they're used so similarly that they often feel like the same thing."