Array Reverse in C: Complete Guide with Examples
Array Reverse in C: A Comprehensive Tutorial
Reversing an array means rearranging its elements such that the first element becomes the last, the second becomes the second-last, and so on. Array reversal is a fundamental operation used in string manipulation, palindrome checking, and many algorithmic problems. This tutorial explores multiple approaches to reversing an array in C, with a focus on efficiency and correctness.
This tutorial provides an in-depth exploration of array reversal in C: temporary array approach, two-pointer technique, single-pointer method, practical applications, common pitfalls, and best practices.
Conceptual Introduction & Fundamentals
What is Array Reversal?
Array reversal is the process of inverting the order of elements in an array. For an array arr of size n, the reversed array has arr[n-1] at position 0, arr[n-2] at position 1, and so on.
Example:
text
Original: [1, 4, 3, 2, 6, 5] Reversed: [5, 6, 2, 3, 4, 1]
Why Reverse an Array?
- String reversal: Reverse characters in a string.
- Palindrome checking: Compare array with its reverse.
- Algorithm foundation: Rotations, permutations, and data manipulation.
- Display purposes: Show data in reverse chronological order.
- Matrix operations: Row/column reversal.
Approaches Overview
| Approach | Time Complexity | Space Complexity |
|---|---|---|
| Temporary array | O(n) | O(n) |
| Two pointers | O(n) | O(1) |
| Single pointer | O(n) | O(1) |
| Recursive | O(n) | O(n) stack |
Syntax & Core Mechanics
Approach 1: Temporary Array (Naive)
Creates a temporary array to store the reversed elements.
c
#include <stdio.h> #include <stdlib.h> void reverseArrayTemp(int arr[], int n) { /* Allocate temporary array */ int *temp = malloc(n * sizeof(int)); if (temp == NULL) { fprintf(stderr, "Memory allocation failed.\n"); return; } /* Copy elements in reverse order */ for (int i = 0; i < n; i++) { temp[i] = arr[n - i - 1]; } /* Copy back to original array */ for (int i = 0; i < n; i++) { arr[i] = temp[i]; } free(temp); } int main(void) { int arr[] = {1, 4, 3, 2, 6, 5}; int n = sizeof(arr) / sizeof(arr[0]); reverseArrayTemp(arr, n); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } printf("\n"); return 0; } Expected output:
text
5 6 2 3 4 1
Time: O(n), Space: O(n)
Approach 2: Two Pointers (Efficient)
Uses two pointers moving towards the center, swapping elements in place.
c
#include <stdio.h> void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } void reverseArrayTwoPointers(int arr[], int n) { int left = 0; int right = n - 1; while (left < right) { swap(&arr[left], &arr[right]); left++; right--; } } int main(void) { int arr[] = {1, 4, 3, 2, 6, 5}; int n = sizeof(arr) / sizeof(arr[0]); reverseArrayTwoPointers(arr, n); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } printf("\n"); return 0; } Expected output:
text
5 6 2 3 4 1
Time: O(n), Space: O(1)
Approach 3: Single Pointer (In-Place)
Iterates over the first half and swaps with the corresponding element from the end.
c
#include <stdio.h> void reverseArraySinglePointer(int arr[], int n) { for (int i = 0; i < n / 2; i++) { int temp = arr[i]; arr[i] = arr[n - i - 1]; arr[n - i - 1] = temp; } } int main(void) { int arr[] = {1, 4, 3, 2, 6, 5}; int n = sizeof(arr) / sizeof(arr[0]); reverseArraySinglePointer(arr, n); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } printf("\n"); return 0; } Expected output:
text
5 6 2 3 4 1
Time: O(n), Space: O(1)
Approach 4: Recursive
c
#include <stdio.h> void reverseRecursive(int arr[], int left, int right) { if (left >= right) { return; /* Base case */ } /* Swap */ int temp = arr[left]; arr[left] = arr[right]; arr[right] = temp; /* Recurse */ reverseRecursive(arr, left + 1, right - 1); } void reverseArray(int arr[], int n) { reverseRecursive(arr, 0, n - 1); } int main(void) { int arr[] = {1, 4, 3, 2, 6, 5}; int n = sizeof(arr) / sizeof(arr[0]); reverseArray(arr, n); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } printf("\n"); return 0; } Expected output:
text
5 6 2 3 4 1
Time: O(n), Space: O(n) stack
Full Practical Code Example with Explanation
This program demonstrates all array reversal approaches with timing and verification.
Program: Array Reversal Comparison
c
/** * array_reverse.c * Demonstrates multiple approaches to reverse an array. * Includes performance comparison and edge case handling. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <time.h> #define MAX_LINE_LEN 100 #define MAX_SIZE 100000 /* Function prototypes */ void reverseTempArray(int arr[], int n); void reverseTwoPointers(int arr[], int n); void reverseSinglePointer(int arr[], int n); void reverseRecursive(int arr[], int left, int right); void reverseRecursiveWrapper(int arr[], int n); void printArray(const int arr[], int n); int readInteger(const char *prompt, int *outValue); int arraysEqual(const int a[], const int b[], int n); void copyArray(const int src[], int dst[], int n); void demonstrateApproaches(void); void performanceComparison(void); int main(void) { int choice; char buffer[MAX_LINE_LEN]; printf("=== Array Reversal Demo ===\n"); while (1) { printf("\n--- Menu ---\n"); printf("1. Demonstrate All Approaches\n"); printf("2. Custom Array Reversal\n"); printf("3. Performance Comparison\n"); printf("4. Exit\n"); printf("Enter choice: "); fflush(stdout); if (fgets(buffer, sizeof(buffer), stdin) == NULL) { fprintf(stderr, "Error reading choice.\n"); return EXIT_FAILURE; } choice = atoi(buffer); switch (choice) { case 1: demonstrateApproaches(); break; case 2: { int arr[MAX_SIZE]; int n; int method; if (readInteger("Enter array size (1-100000): ", &n) != 0) { fprintf(stderr, "Invalid size.\n"); break; } if (n < 1 || n > MAX_SIZE) { printf("Size must be 1-%d.\n", MAX_SIZE); break; } printf("Enter %d elements:\n", n); for (int i = 0; i < n; i++) { char prompt[50]; snprintf(prompt, sizeof(prompt), " Element %d: ", i); if (readInteger(prompt, &arr[i]) != 0) { fprintf(stderr, "Invalid input.\n"); n = i; break; } } printf("\nOriginal array: "); printArray(arr, n); printf("\nSelect reversal method:\n"); printf("1. Temporary Array\n"); printf("2. Two Pointers\n"); printf("3. Single Pointer\n"); printf("4. Recursive\n"); printf("Enter method: "); fflush(stdout); if (fgets(buffer, sizeof(buffer), stdin) == NULL) break; method = atoi(buffer); switch (method) { case 1: reverseTempArray(arr, n); break; case 2: reverseTwoPointers(arr, n); break; case 3: reverseSinglePointer(arr, n); break; case 4: reverseRecursiveWrapper(arr, n); break; default: printf("Invalid method.\n"); continue; } printf("Reversed array: "); printArray(arr, n); break; } case 3: performanceComparison(); break; case 4: printf("Exiting.\n"); return EXIT_SUCCESS; default: printf("Invalid choice. Please try again.\n"); break; } } return EXIT_SUCCESS; } /* Approach 1: Temporary array */ void reverseTempArray(int arr[], int n) { if (n <= 1) return; int *temp = malloc(n * sizeof(int)); if (temp == NULL) { fprintf(stderr, "Memory allocation failed.\n"); return; } for (int i = 0; i < n; i++) { temp[i] = arr[n - i - 1]; } for (int i = 0; i < n; i++) { arr[i] = temp[i]; } free(temp); } /* Approach 2: Two pointers */ void reverseTwoPointers(int arr[], int n) { int left = 0; int right = n - 1; while (left < right) { int temp = arr[left]; arr[left] = arr[right]; arr[right] = temp; left++; right--; } } /* Approach 3: Single pointer */ void reverseSinglePointer(int arr[], int n) { for (int i = 0; i < n / 2; i++) { int temp = arr[i]; arr[i] = arr[n - i - 1]; arr[n - i - 1] = temp; } } /* Approach 4: Recursive */ void reverseRecursive(int arr[], int left, int right) { if (left >= right) return; int temp = arr[left]; arr[left] = arr[right]; arr[right] = temp; reverseRecursive(arr, left + 1, right - 1); } void reverseRecursiveWrapper(int arr[], int n) { if (n <= 1) return; reverseRecursive(arr, 0, n - 1); } /* Prints array */ void printArray(const int arr[], int n) { printf("["); for (int i = 0; i < n; i++) { printf("%d", arr[i]); if (i < n - 1) printf(", "); } printf("]\n"); } /* Compares two arrays */ int arraysEqual(const int a[], const int b[], int n) { for (int i = 0; i < n; i++) { if (a[i] != b[i]) return 0; } return 1; } /* Copies an array */ void copyArray(const int src[], int dst[], int n) { memcpy(dst, src, n * sizeof(int)); } /* Demonstrates all approaches with verification */ void demonstrateApproaches(void) { printf("\n=== All Reversal Approaches ===\n"); int original[] = {1, 4, 3, 2, 6, 5}; int n = sizeof(original) / sizeof(original[0]); int expected[] = {5, 6, 2, 3, 4, 1}; int arr[MAX_SIZE]; printf("Original: "); printArray(original, n); /* Method 1: Temporary array */ copyArray(original, arr, n); reverseTempArray(arr, n); printf("Temp Array: "); printArray(arr, n); printf(" Verification: %s\n", arraysEqual(arr, expected, n) ? "PASS" : "FAIL"); /* Method 2: Two pointers */ copyArray(original, arr, n); reverseTwoPointers(arr, n); printf("Two Pointers: "); printArray(arr, n); printf(" Verification: %s\n", arraysEqual(arr, expected, n) ? "PASS" : "FAIL"); /* Method 3: Single pointer */ copyArray(original, arr, n); reverseSinglePointer(arr, n); printf("Single Pointer:"); printArray(arr, n); printf(" Verification: %s\n", arraysEqual(arr, expected, n) ? "PASS" : "FAIL"); /* Method 4: Recursive */ copyArray(original, arr, n); reverseRecursiveWrapper(arr, n); printf("Recursive: "); printArray(arr, n); printf(" Verification: %s\n", arraysEqual(arr, expected, n) ? "PASS" : "FAIL"); } /* Performance comparison */ void performanceComparison(void) { printf("\n=== Performance Comparison ===\n"); int size = 100000; int *original = malloc(size * sizeof(int)); int *arr = malloc(size * sizeof(int)); if (original == NULL || arr == NULL) { fprintf(stderr, "Memory allocation failed.\n"); free(original); free(arr); return; } /* Initialize with random-ish data */ for (int i = 0; i < size; i++) { original[i] = i * 7 % 1000; } clock_t start, end; double timeTaken; /* Method 1: Temporary array */ copyArray(original, arr, size); start = clock(); reverseTempArray(arr, size); end = clock(); timeTaken = ((double)(end - start)) / CLOCKS_PER_SEC * 1000.0; printf("Temporary Array: %.3f ms\n", timeTaken); /* Method 2: Two pointers */ copyArray(original, arr, size); start = clock(); reverseTwoPointers(arr, size); end = clock(); timeTaken = ((double)(end - start)) / CLOCKS_PER_SEC * 1000.0; printf("Two Pointers: %.3f ms\n", timeTaken); /* Method 3: Single pointer */ copyArray(original, arr, size); start = clock(); reverseSinglePointer(arr, size); end = clock(); timeTaken = ((double)(end - start)) / CLOCKS_PER_SEC * 1000.0; printf("Single Pointer: %.3f ms\n", timeTaken); /* Method 4: Recursive */ copyArray(original, arr, size); start = clock(); reverseRecursiveWrapper(arr, size); end = clock(); timeTaken = ((double)(end - start)) / CLOCKS_PER_SEC * 1000.0; printf("Recursive: %.3f ms\n", timeTaken); free(original); free(arr); } /* Reads an integer safely */ int readInteger(const char *prompt, int *outValue) { char buffer[MAX_LINE_LEN]; char *endPtr; long val; printf("%s", prompt); fflush(stdout); if (fgets(buffer, sizeof(buffer), stdin) == NULL) { return -1; } errno = 0; val = strtol(buffer, &endPtr, 10); if (endPtr == buffer || (*endPtr != '\n' && *endPtr != '\0')) { return -1; } if (errno == ERANGE || val < -2147483647 - 1 || val > 2147483647) { return -1; } *outValue = (int)val; return 0; } Explanation of Approaches
- Temporary Array: Simple but uses O(n) extra space.
- Two Pointers: In-place, O(1) space, most intuitive.
- Single Pointer: In-place, O(1) space, concise.
- Recursive: Elegant but uses O(n) stack space.
Expected Output (sample run)
text
=== Array Reversal Demo === --- Menu --- 1. Demonstrate All Approaches 2. Custom Array Reversal 3. Performance Comparison 4. Exit Enter choice: 1 === All Reversal Approaches === Original: [1, 4, 3, 2, 6, 5] Temp Array: [5, 6, 2, 3, 4, 1] Verification: PASS Two Pointers: [5, 6, 2, 3, 4, 1] Verification: PASS Single Pointer:[5, 6, 2, 3, 4, 1] Verification: PASS Recursive: [5, 6, 2, 3, 4, 1] Verification: PASS --- Menu --- ... Enter choice: 3 === Performance Comparison === Temporary Array: 0.412 ms Two Pointers: 0.285 ms Single Pointer: 0.278 ms Recursive: 0.521 ms
Common Pitfalls, Edge Cases & Memory Considerations
1. Off-by-One Errors
Incorrect loop bounds cause missed or double swaps.
c
for (int i = 0; i <= n / 2; i++) { // BUG: swaps middle element twice for odd n /* ... */ } Solution: Use i < n / 2.
2. Integer Division for Odd Lengths
For odd-length arrays, the middle element stays in place.
c
/* n = 5: i goes 0, 1 (swaps pairs) */ /* Middle element at index 2 remains */
Solution: This is correct behavior; no special handling needed.
3. Empty Array
Reversing an empty array should do nothing.
c
int arr[] = {}; reverseArray(arr, 0); // No-op Solution: Add if (n <= 1) return; at the start.
4. Single Element
A single-element array is already reversed.
c
int arr[] = {5}; reverseArray(arr, 1); // No change 5. Memory Leaks with Temporary Array
Forgetting to free the temporary array.
c
int *temp = malloc(n * sizeof(int)); /* ... */ /* Missing free(temp); */
Solution: Always free dynamically allocated memory.
6. Stack Overflow with Recursion
Deep recursion for large arrays causes stack overflow.
c
reverseRecursive(arr, 0, 999999); // Stack overflow
Solution: Use iterative approach for large arrays.
7. Const Arrays
Attempting to reverse a const array is a compile error.
c
void reverse(const int arr[], int n) { arr[0] = arr[n-1]; // Error: read-only } Solution: Remove const if modification is intended.
8. Null Pointer
Passing NULL to reversal function crashes.
c
reverseArray(NULL, 5); // BUG
Solution: Check for NULL before processing.
9. Large Arrays on Stack
Large automatic arrays can overflow the stack.
c
void func(void) { int bigArray[1000000]; reverseArray(bigArray, 1000000); } Solution: Use static or malloc for large arrays.
10. Memory Considerations
- Temporary array approach uses O(n) extra space.
- Two-pointer and single-pointer approaches use O(1) space.
- Recursive uses O(n) stack space.
- For large arrays, prefer in-place approaches.
Summary & Best Practices
Array reversal is a fundamental operation with multiple implementation approaches. The two-pointer and single-pointer methods are preferred for their O(1) space complexity.
Key Takeaways
- Reversing an array swaps elements symmetrically.
- Temporary array: O(n) time, O(n) space.
- Two pointers: O(n) time, O(1) space.
- Single pointer: O(n) time, O(1) space.
- Recursive: O(n) time, O(n) stack space.
- Middle element of odd-length array stays in place.
Best Practices
- Use the two-pointer or single-pointer approach for in-place reversal.
- Use the temporary array approach only when the original must be preserved.
- Handle empty and single-element arrays gracefully.
- Avoid recursion for large arrays to prevent stack overflow.
- Free dynamically allocated memory for temporary arrays.
- Validate input pointers before processing.
- Use
size_tfor array sizes. - Test with odd and even lengths.
- Consider cache performance for very large arrays.
- Document whether the reversal is in-place.
By mastering array reversal, you’ll have a fundamental tool for string manipulation, algorithm design, and data processing.





