The core idea โ two pointers, walking inward. Place one pointer at the start of the array (
left) and one at the end (right). Swap the values they point at. Move left one step right, move right one step left. Repeat until they meet or cross. The array is reversed in exactly n/2 swaps, using zero extra memory โ no temporary array, no second copy. Just two pointers and a single temp variable for the swap.
two-pointer reversal โ step by step on array [10, 20, 30, 40, 50]
| Concept | How used | Code |
|---|---|---|
| int *left | Points to first element, walks right | int *left = arr |
| int *right | Points to last element, walks left | int *right = arr + n - 1 |
| Swap | Temp variable, deref both pointers | int t = *left; *left = *right; *right = t |
| Advance | Move pointers inward each iteration | left++; right-- |
| Stop condition | Pointers meet or cross | while(left < right) |
p1 โ step 1 ยท basic reverse
S1
๐ reverse() โ The Two-Pointer Swap Core
int *left = arr, int *right = arr+n-1 โ swap while left < right โ in-place, zero extra memory
Core Algorithm
The two-pointer technique is one of the most important patterns in programming. Two pointers start at opposite ends and walk toward each other. At each step they swap what they point at. When they meet or cross, every element has been swapped exactly once โ the array is fully reversed. The loop condition
while(left < right) handles both even-length arrays (pointers meet exactly in the middle) and odd-length arrays (they cross without meeting, leaving the middle element untouched โ correct, since the middle element needs no swap).
- 1Left pointer:
int *left = arrโ starts atarr[0]. Will move forward withleft++. - 2Right pointer:
int *right = arr + n - 1โ starts at last element. Will move backward withright--. - 3Swap:
int tmp = *left; *left = *right; *right = tmpโ classic three-step swap through pointers. - 4Advance inward:
left++; right--โ both move one step closer to each other. - 5Stop:
while(left < right)โ when pointers meet or cross, every swap is done.
#include <stdio.h> /* Print array via pointer walk */ void printArr(const int *arr, int n, const char *label) { printf(" %-10s [ ", label); const int *p = arr; while (p < arr + n) printf("%d ", *p++); printf("]\n"); } /* Core reverse โ two-pointer in-place */ void reverse(int *arr, int n) { int *left = arr; /* start pointer โ arr[0] */ int *right = arr + n - 1; /* end pointer โ arr[n-1] */ while (left < right) { /* stop when pointers meet */ int tmp = *left; /* 1. save left value */ *left = *right; /* 2. copy right โ left */ *right = tmp; /* 3. copy saved โ right */ left++; /* 4. left moves inward โถ */ right--; /* 5. right moves inward โ */ } } int main() { int a[] = {10, 20, 30, 40, 50}; /* odd length */ int b[] = {5, 15, 25, 35}; /* even length */ int c[] = {99}; /* single element */ printf("=== Odd-length array (5 elements) ===\n"); printArr(a, 5, "Before:"); reverse(a, 5); printArr(a, 5, "After :"); printf("\n=== Even-length array (4 elements) ===\n"); printArr(b, 4, "Before:"); reverse(b, 4); printArr(b, 4, "After :"); printf("\n=== Single element ===\n"); printArr(c, 1, "Before:"); reverse(c, 1); printArr(c, 1, "After :"); return 0; }
=== Odd-length array (5 elements) === Before: [ 10 20 30 40 50 ] After : [ 50 40 30 20 10 ] === Even-length array (4 elements) === Before: [ 5 15 25 35 ] After : [ 35 25 15 5 ] === Single element === Before: [ 99 ] After : [ 99 ]
Why
while(left < right) not left <= right? With <=, an odd-length array would try to swap the middle element with itself โ harmless but pointless. With <, the middle element is skipped cleanly. Both produce the correct result, but < is more efficient and the idiomatic C choice.p1 โ step 2 ยท verbose trace + char reverse
S2
๐ Verbose Trace + String Reversal โ Same Algorithm, Different Type
Print every swap step โ then apply identical logic to char arrays
Trace + Char
The two-pointer reversal is type-agnostic โ the same logic works on any array type. By changing
int* to char* and int tmp to char tmp, the identical algorithm reverses a string in-place. We also add a verbose version that prints every swap step โ when you can see each pointer position and swap, the algorithm becomes completely transparent.
- 1Verbose trace: inside the loop,
printfthe index positions and values being swapped before the swap happens. - 2Index from pointer:
left - arrgives the current index ofleftโ pointer subtraction gives the offset. - 3Char reversal: change
int*tochar*. Works on any null-terminated string โ usestrlen(s)for the length. - 4reverseString: reverses a word in-place โ the foundation of the "reverse words in a sentence" algorithm.
#include <stdio.h> #include <string.h> /* Verbose reverse โ prints every swap step */ void reverseVerbose(int *arr, int n) { int *left = arr; int *right = arr + n - 1; int step = 1; printf(" Step Left[idx] Right[idx] Action\n"); printf(" ----------------------------------------\n"); while (left < right) { printf(" %2d arr[%td]=%d arr[%td]=%d swap\n", step, left - arr, *left, right - arr, *right); int tmp = *left; *left = *right; *right = tmp; left++; right--; step++; } printf(" Pointers met โ done.\n"); } /* Char reversal โ identical logic, different type */ void reverseString(char *s) { char *left = s; char *right = s + strlen(s) - 1; while (left < right) { char tmp = *left; *left = *right; *right = tmp; left++; right--; } } int main() { int arr[] = {3, 7, 1, 9, 4, 6}; printf("=== Verbose Trace ===\n"); reverseVerbose(arr, 6); printf(" Result: [ "); for(int i=0;i<6;i++) printf("%d ",arr[i]); printf("]\n"); printf("\n=== String Reversal (char array) ===\n"); char words[][15] = {"Ananta", "pointer", "racecar"}; for(int i=0;i<3;i++){ printf(" %-10s โ ", words[i]); reverseString(words[i]); printf("%s\n", words[i]); } return 0; }
=== Verbose Trace ===
Step Left[idx] Right[idx] Action
----------------------------------------
1 arr[0]=3 arr[5]=6 swap
2 arr[1]=7 arr[4]=4 swap
3 arr[2]=1 arr[3]=9 swap
Pointers met โ done.
Result: [ 6 4 9 1 7 3 ]
=== String Reversal (char array) ===
Ananta โ atnanA
pointer โ retniop
racecar โ racecarPointer subtraction
left - arr gives the index of the element left currently points at. If arr is at address 1000 and int is 4 bytes, then left at address 1008 gives (1008-1000)/4 = 2 โ index 2. C performs this division automatically when you subtract two pointers of the same type.p1 โ step 3 ยท complete reverser
S3
๐ Complete Number Reverser โ All Variants Together
Reverse, partial reverse, check palindrome, reverse sub-range โ all via two-pointer
Full Project 1
Four variants of the same core algorithm show how versatile two-pointer reversal is. Full reverse โ the base case. Partial reverse โ reverse only indices
[from..to] by setting left and right within that sub-range. Palindrome check โ compare without swapping: walk inward, return false if any pair mismatches. Rotate array โ reverse the whole, then reverse first k, then reverse rest โ a beautiful three-reversal trick.
#include <stdio.h> void printArr(const int *a, int n){ printf("[ "); const int *p=a; while(p<a+n) printf("%d ",*p++); printf("]"); } /* 1. Full reverse โ O(n/2) swaps */ void reverse(int *a, int n) { int *L=a, *R=a+n-1; while(L<R){ int t=*L; *L=*R; *R=t; L++; R--; } } /* 2. Partial reverse โ reverse only [from..to] */ void reverseRange(int *a, int from, int to) { int *L=a+from, *R=a+to; while(L<R){ int t=*L; *L=*R; *R=t; L++; R--; } } /* 3. Palindrome check โ two-pointer compare (no swap) */ int isPalindrome(const int *a, int n) { const int *L=a, *R=a+n-1; while(L<R){ if(*L != *R) return 0; /* mismatch โ not palindrome */ L++; R--; } return 1; } /* 4. Rotate left by k โ three-reversal trick Rotate [1,2,3,4,5] left by 2 โ [3,4,5,1,2] Step 1: reverse full โ [5,4,3,2,1] Step 2: reverse [n-k..n-1] โ [5,4,3,1,2] โ wrong order Correct: reverse [0..k-1], reverse [k..n-1], reverse all */ void rotateLeft(int *a, int n, int k) { k = k % n; /* handle k >= n */ reverseRange(a, 0, k-1); /* reverse first k */ reverseRange(a, k, n-1); /* reverse rest */ reverseRange(a, 0, n-1); /* reverse entire */ } int main() { printf("=== 1. Full Reverse ===\n"); int a[] = {10,20,30,40,50}; printf(" Before: "); printArr(a,5); reverse(a,5); printf(" After : "); printArr(a,5); printf("\n"); printf("\n=== 2. Partial Reverse (index 1 to 3) ===\n"); int b[] = {1,2,3,4,5}; printf(" Before: "); printArr(b,5); reverseRange(b,1,3); printf(" After : "); printArr(b,5); printf("\n"); printf("\n=== 3. Palindrome Check ===\n"); int p1[] = {1,2,3,2,1}; int p2[] = {1,2,3,4,5}; printf(" [1,2,3,2,1]: %s\n", isPalindrome(p1,5)?"Palindrome":"Not palindrome"); printf(" [1,2,3,4,5]: %s\n", isPalindrome(p2,5)?"Palindrome":"Not palindrome"); printf("\n=== 4. Rotate Left by 2 ===\n"); int r[] = {1,2,3,4,5}; printf(" Before: "); printArr(r,5); rotateLeft(r,5,2); printf(" After : "); printArr(r,5); printf("\n"); return 0; }
=== 1. Full Reverse === Before: [ 10 20 30 40 50 ] After : [ 50 40 30 20 10 ] === 2. Partial Reverse (index 1 to 3) === Before: [ 1 2 3 4 5 ] After : [ 1 4 3 2 5 ] === 3. Palindrome Check === [1,2,3,2,1]: Palindrome [1,2,3,4,5]: Not palindrome === 4. Rotate Left by 2 === Before: [ 1 2 3 4 5 ] After : [ 3 4 5 1 2 ]
The three-reversal rotation trick is a classic algorithm that rotates an array in O(n) time and O(1) space using only the reversal function you already wrote. Rotating left by k: reverse first k elements, reverse remaining n-k elements, then reverse the entire array. Three calls to the same function โ elegant reuse of one primitive operation.