Pointer vs Array in C: Key Differences Explained
Pointer vs Array in C: A Comprehensive Tutorial
Pointers and arrays are closely related in C, and in many expressions an array name behaves like a pointer to its first element. However, they are fundamentally different entities with distinct characteristics in memory allocation, assignment, arithmetic, and behavior with operators. Understanding these differences is crucial for writing correct and efficient C code.
This tutorial provides an in-depth exploration of the differences between pointers and arrays in C: their fundamental nature, behavior with operators, memory layout, common pitfalls, and best practices.
Conceptual Introduction & Fundamentals
What is an Array?
An array is a fixed-size collection of elements of the same data type stored in contiguous memory locations. The array name represents the entire collection.
Key characteristics:
- Fixed size determined at declaration
- Elements stored contiguously
- Array name acts as a constant pointer to first element
- Cannot be reassigned
sizeofgives total array size
c
int array[5] = {10, 20, 30, 40, 50}; /* 5 integers = 20 bytes (assuming 4-byte int) */ What is a Pointer?
A pointer is a variable that stores the memory address of another variable. It can be reassigned to point to different memory locations.
Key characteristics:
- Variable that holds an address
- Can be reassigned
- Supports pointer arithmetic
sizeofgives pointer size (4 or 8 bytes)- Can be initialized to
NULL
c
int *pointer = array; /* Points to first element */ /* Pointer itself occupies 8 bytes (64-bit system) */
The Fundamental Difference
| Aspect | Array | Pointer |
|---|---|---|
| Nature | Collection of elements | Variable holding address |
| Memory allocation | Allocates memory for all elements | Allocates memory only for the address |
| Reassignment | Cannot be reassigned | Can be reassigned |
sizeof | Total array size | Pointer size (4 or 8 bytes) |
| Arithmetic | Not allowed on array name | Allowed (increment, decrement, etc.) |
| Address-of | &array = address of entire array | &pointer = address of pointer variable |
Syntax & Core Mechanics
Basic Comparison
c
#include <stdio.h> int main(void) { int array[5] = {10, 20, 30, 40, 50}; int *pointer = array; /* Accessing elements */ printf("array[0] = %d\n", array[0]); printf("*pointer = %d\n", *pointer); printf("array[1] = %d\n", array[1]); printf("*(pointer + 1) = %d\n", *(pointer + 1)); /* Size comparison */ printf("sizeof(array) = %zu bytes\n", sizeof(array)); /* 20 */ printf("sizeof(pointer) = %zu bytes\n", sizeof(pointer)); /* 8 */ /* Pointer arithmetic */ pointer++; printf("*pointer after ++ = %d\n", *pointer); /* 20 */ /* Array name cannot be modified */ /* array++; // Error: cannot increment array */ return 0; } Expected output:
text
array[0] = 10 *pointer = 10 array[1] = 20 *(pointer + 1) = 20 sizeof(array) = 20 bytes sizeof(pointer) = 8 bytes *pointer after ++ = 20
sizeof Behavior
c
#include <stdio.h> int main(void) { int array[10]; int *pointer = array; printf("sizeof(array) = %zu\n", sizeof(array)); /* 40 (10 * 4) */ printf("sizeof(pointer) = %zu\n", sizeof(pointer)); /* 8 (pointer size) */ printf("sizeof(*array) = %zu\n", sizeof(*array)); /* 4 (element size) */ printf("sizeof(*pointer) = %zu\n", sizeof(*pointer)); /* 4 (element size) */ return 0; } Expected output (64-bit system):
text
sizeof(array) = 40 sizeof(pointer) = 8 sizeof(*array) = 4 sizeof(*pointer) = 4
Address-of Operator
c
#include <stdio.h> int main(void) { int array[5] = {10, 20, 30, 40, 50}; int *pointer = array; printf("array = %p\n", (void*)array); printf("&array = %p\n", (void*)&array); printf("&array[0] = %p\n", (void*)&array[0]); printf("\npointer = %p\n", (void*)pointer); printf("&pointer = %p\n", (void*)&pointer); printf("&pointer[0] = %p\n", (void*)&pointer[0]); return 0; } Expected output (addresses will vary):
text
array = 0x7ffc1000 &array = 0x7ffc1000 &array[0] = 0x7ffc1000 pointer = 0x7ffc1000 &pointer = 0x7ffc0ff8 &pointer[0] = 0x7ffc1000
Key insight: array and &array have the same address (but different types: int* vs int (*)[5]). pointer and &pointer have different addresses.
Assignment
c
#include <stdio.h> int main(void) { int array1[5] = {1, 2, 3, 4, 5}; int array2[5] = {6, 7, 8, 9, 10}; int *pointer; /* Pointer can be reassigned */ pointer = array1; printf("*pointer = %d\n", *pointer); /* 1 */ pointer = array2; printf("*pointer = %d\n", *pointer); /* 6 */ /* Array cannot be reassigned */ /* array1 = array2; // Error: assignment to expression with array type */ return 0; } Expected output:
text
*pointer = 1 *pointer = 6
String Initialization Differences
c
#include <stdio.h> int main(void) { /* Array: creates a writable copy */ char array[] = "Hello"; array[0] = 'h'; /* OK: modifying array */ printf("array: %s\n", array); /* Pointer: points to string literal (read-only) */ const char *pointer = "Hello"; /* pointer[0] = 'h'; // BUG: string literal is read-only */ printf("pointer: %s\n", pointer); return 0; } Expected output:
text
array: hello pointer: Hello
Full Practical Code Example with Explanation
This program demonstrates the differences between pointers and arrays in a realistic scenario: a data processing system comparing array and pointer behavior.
Program: Pointer vs Array Comparison
c
/** * pointer_vs_array.c * Demonstrates differences between pointers and arrays. * Shows sizeof, address-of, assignment, and arithmetic differences. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #define ARRAY_SIZE 5 #define MAX_LINE_LEN 100 /* Function prototypes */ void demonstrateSizeofDifference(void); void demonstrateAddressDifference(void); void demonstrateAssignmentDifference(void); void demonstrateArithmeticDifference(void); void demonstrateStringDifference(void); void demonstrateFunctionParameter(void); void arrayParameter(int arr[], int size); void pointerParameter(int *arr, int size); int main(void) { int choice; char buffer[MAX_LINE_LEN]; printf("=== Pointer vs Array Comparison ===\n"); while (1) { printf("\n--- Menu ---\n"); printf("1. sizeof Difference\n"); printf("2. Address-of Difference\n"); printf("3. Assignment Difference\n"); printf("4. Arithmetic Difference\n"); printf("5. String Initialization Difference\n"); printf("6. Function Parameter (Array Decay)\n"); printf("7. 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: demonstrateSizeofDifference(); break; case 2: demonstrateAddressDifference(); break; case 3: demonstrateAssignmentDifference(); break; case 4: demonstrateArithmeticDifference(); break; case 5: demonstrateStringDifference(); break; case 6: demonstrateFunctionParameter(); break; case 7: printf("Exiting.\n"); return EXIT_SUCCESS; default: printf("Invalid choice. Please try again.\n"); break; } } return EXIT_SUCCESS; } /* Demonstrates sizeof difference */ void demonstrateSizeofDifference(void) { printf("\n=== sizeof Difference ===\n"); int array[ARRAY_SIZE] = {10, 20, 30, 40, 50}; int *pointer = array; printf("Array: %d elements of int\n", ARRAY_SIZE); printf("sizeof(array) = %zu bytes (total array size)\n", sizeof(array)); printf("sizeof(pointer) = %zu bytes (pointer size only)\n", sizeof(pointer)); printf("sizeof(array[0]) = %zu bytes (single element)\n", sizeof(array[0])); printf("sizeof(*pointer) = %zu bytes (single element via pointer)\n", sizeof(*pointer)); printf("\nElements in array via sizeof: %zu\n", sizeof(array) / sizeof(array[0])); /* The following gives incorrect result for pointer */ printf("Elements via pointer sizeof: %zu (incorrect!)\n", sizeof(pointer) / sizeof(pointer[0])); } /* Demonstrates address-of difference */ void demonstrateAddressDifference(void) { printf("\n=== Address-of Difference ===\n"); int array[ARRAY_SIZE] = {10, 20, 30, 40, 50}; int *pointer = array; printf("array address: %p\n", (void*)array); printf("&array address: %p\n", (void*)&array); printf("&array[0] address: %p\n", (void*)&array[0]); printf("\npointer address: %p\n", (void*)pointer); printf("&pointer address: %p\n", (void*)&pointer); printf("\nNote: array and &array have same address (different types)\n"); printf("Note: pointer and &pointer have different addresses\n"); } /* Demonstrates assignment difference */ void demonstrateAssignmentDifference(void) { printf("\n=== Assignment Difference ===\n"); int array1[ARRAY_SIZE] = {1, 2, 3, 4, 5}; int array2[ARRAY_SIZE] = {6, 7, 8, 9, 10}; int *pointer; /* Pointer reassignment */ pointer = array1; printf("pointer = array1: *pointer = %d\n", *pointer); pointer = array2; printf("pointer = array2: *pointer = %d\n", *pointer); printf("\nArray cannot be reassigned:\n"); printf(" /* array1 = array2; */ // Compile error\n"); } /* Demonstrates arithmetic difference */ void demonstrateArithmeticDifference(void) { printf("\n=== Arithmetic Difference ===\n"); int array[ARRAY_SIZE] = {10, 20, 30, 40, 50}; int *pointer = array; printf("Pointer arithmetic (valid):\n"); printf(" *pointer = %d\n", *pointer); pointer++; printf(" pointer++: *pointer = %d\n", *pointer); pointer += 2; printf(" pointer += 2: *pointer = %d\n", *pointer); pointer--; printf(" pointer--: *pointer = %d\n", *pointer); printf("\nArray arithmetic (invalid):\n"); printf(" /* array++; */ // Compile error\n"); printf(" /* array = array + 1; */ // Compile error\n"); } /* Demonstrates string initialization difference */ void demonstrateStringDifference(void) { printf("\n=== String Initialization Difference ===\n"); char charArray[] = "Hello"; const char *stringLiteral = "Hello"; printf("char array: %s\n", charArray); printf("string literal pointer: %s\n", stringLiteral); printf("\nModifying char array (valid):\n"); charArray[0] = 'h'; printf(" After charArray[0] = 'h': %s\n", charArray); printf("\nModifying string literal (invalid):\n"); printf(" /* stringLiteral[0] = 'h'; */ // Undefined behavior\n"); } /* Demonstrates array decay in function parameters */ void demonstrateFunctionParameter(void) { printf("\n=== Function Parameter (Array Decay) ===\n"); int array[ARRAY_SIZE] = {10, 20, 30, 40, 50}; printf("In main: sizeof(array) = %zu\n", sizeof(array)); arrayParameter(array, ARRAY_SIZE); pointerParameter(array, ARRAY_SIZE); } /* Function with array parameter */ void arrayParameter(int arr[], int size) { printf("In arrayParameter: sizeof(arr) = %zu (pointer size)\n", sizeof(arr)); printf(" arr decays to pointer\n"); } /* Function with pointer parameter */ void pointerParameter(int *arr, int size) { printf("In pointerParameter: sizeof(arr) = %zu (pointer size)\n", sizeof(arr)); printf(" Same behavior as array parameter\n"); } Explanation of Differences
sizeofDifference: Array gives total size; pointer gives pointer size.- Address-of Difference:
&arrayequalsarray(different type);&pointerdiffers frompointer. - Assignment Difference: Pointers can be reassigned; arrays cannot.
- Arithmetic Difference: Pointer arithmetic is allowed; array name arithmetic is not.
- String Initialization: Array is writable; string literal pointer is read-only.
- Function Parameter: Both array and pointer parameters decay to pointers.
Expected Output (sample run)
text
=== Pointer vs Array Comparison === --- Menu --- 1. sizeof Difference 2. Address-of Difference 3. Assignment Difference 4. Arithmetic Difference 5. String Initialization Difference 6. Function Parameter (Array Decay) 7. Exit Enter choice: 1 === sizeof Difference === Array: 5 elements of int sizeof(array) = 20 bytes (total array size) sizeof(pointer) = 8 bytes (pointer size only) sizeof(array[0]) = 4 bytes (single element) sizeof(*pointer) = 4 bytes (single element via pointer) Elements in array via sizeof: 5 Elements via pointer sizeof: 2 (incorrect!) --- Menu --- ... Enter choice: 2 === Address-of Difference === array address: 0x7ffc1000 &array address: 0x7ffc1000 &array[0] address: 0x7ffc1000 pointer address: 0x7ffc1000 &pointer address: 0x7ffc0ff8 Note: array and &array have same address (different types) Note: pointer and &pointer have different addresses --- Menu --- ... Enter choice: 6 === Function Parameter (Array Decay) === In main: sizeof(array) = 20 In arrayParameter: sizeof(arr) = 8 (pointer size) arr decays to pointer In pointerParameter: sizeof(arr) = 8 (pointer size) Same behavior as array parameter
Common Pitfalls, Edge Cases & Memory Considerations
1. Using sizeof on Function Parameters
Array parameters decay to pointers; sizeof gives pointer size.
c
void func(int arr[]) { sizeof(arr); // Pointer size (8), not array size } Solution: Pass array size as a separate parameter.
2. Attempting to Reassign Array Name
Array names are constant; they cannot be reassigned.
c
int arr1[5], arr2[5]; arr1 = arr2; // Error: assignment to expression with array type
Solution: Use a pointer: int *ptr = arr1; ptr = arr2;
3. Modifying String Literals via Pointer
String literals are read-only; modifying them is undefined behavior.
c
char *str = "Hello"; str[0] = 'h'; // BUG: modifying read-only memory
Solution: Use const char * or char str[] = "Hello";
4. Confusing &array with array
While they have the same address, their types differ:
arrayisint*(pointer to first element)&arrayisint (*)[5](pointer to entire array)
c
int arr[5]; int *p1 = arr; // OK int *p2 = &arr; // Warning: incompatible pointer type int (*p3)[5] = &arr; // Correct
Solution: Use the correct pointer type for &array.
5. sizeof on Dynamically Allocated Memory
sizeof on a pointer to malloc‘d memory gives pointer size, not allocated size.
c
int *arr = malloc(10 * sizeof(int)); sizeof(arr); // Pointer size (8), not 40
Solution: Track allocated size manually.
6. Pointer Arithmetic on void*
Cannot perform arithmetic on void* (GCC extension allows, but not standard).
c
void *ptr = malloc(10); ptr++; // Error in standard C: arithmetic on void*
Solution: Cast to a typed pointer: ((char*)ptr)++.
7. Array Bounds Checking
Neither arrays nor pointers have built-in bounds checking.
c
int arr[5]; int *p = arr; p[10] = 42; // Undefined behavior: out of bounds
Solution: Validate indices before access.
8. String Comparison with ==
Comparing strings with == compares pointers, not contents.
c
char arr1[] = "Hello"; char arr2[] = "Hello"; if (arr1 == arr2) { // False: different addresses } Solution: Use strcmp for string comparison.
9. Returning Pointer to Local Array
Returning a pointer to a local array is undefined behavior.
c
int *createArray(void) { int arr[5] = {1, 2, 3, 4, 5}; return arr; // BUG: arr destroyed on return } Solution: Use static, malloc, or pass a buffer.
10. Memory Considerations
- Arrays allocate contiguous memory for all elements.
- Pointers allocate memory only for the address (8 bytes on 64-bit).
- Dynamically allocated arrays (
malloc) must be freed. - Array decay in functions means no copying of array data (efficient).
Summary & Best Practices
Pointers and arrays are distinct entities in C, despite their close relationship. Arrays are fixed collections of elements; pointers are variables holding addresses. Understanding their differences is essential for correct memory management and efficient programming.
Key Takeaways
- Array: Fixed collection, contiguous memory, cannot be reassigned.
- Pointer: Variable holding address, can be reassigned.
sizeof(array)= total array size;sizeof(pointer)= pointer size.- Array name cannot be modified; pointer can.
- Array decays to pointer in function parameters.
- String literals via pointers are read-only; character arrays are writable.
&arrayandarrayhave same address but different types.
Best Practices
- Use arrays for fixed-size collections.
- Use pointers for dynamic memory and reassignment.
- Pass array size explicitly to functions (avoid relying on
sizeof). - Use
const char *for string literals; usechar[]for writable strings. - Use correct pointer types for
&array(e.g.,int (*)[5]). - Track dynamically allocated memory size manually.
- Avoid pointer arithmetic on
void*(cast first). - Use
strcmpfor string comparison, not==. - Never return pointers to local arrays.
- Enable compiler warnings to catch array/pointer type mismatches.
By mastering the differences between pointers and arrays, you’ll write safer, more efficient C code and avoid common pitfalls.



