Skip to main content

C Pointers & Arrays

Arrays and pointers in C share an intimate relationship that can be both powerful and potentially confusing. This page explores how they interact and how you can leverage this relationship to write efficient code.

The Array-Pointer Connection

In C, there's a fundamental relationship between arrays and pointers that is crucial to understand:

c
// When you declare an array
int numbers[5] = {10, 20, 30, 40, 50};

// The array name 'numbers' actually behaves like a pointer to its first element
// These are equivalent:
int firstElement = numbers[0]; // Array notation
int sameElement = *numbers; // Pointer notation
info

When an array name is used in most expressions, it's automatically converted to a pointer to the first element of the array.

Array Indexing with Pointers

Array indexing and pointer arithmetic are closely related:

c
int numbers[5] = {10, 20, 30, 40, 50};
int *ptr = numbers; // ptr points to the first element

// These are equivalent
int value1 = numbers[2]; // Array notation
int value2 = *(ptr + 2); // Pointer arithmetic
int value3 = *(numbers + 2); // Mixed notation
int value4 = ptr[2]; // Pointers can use array notation too!

Differences Between Arrays and Pointers

Despite their similarities, arrays and pointers aren't identical:

c
int numbers[5];
int *ptr = numbers;

// Arrays are fixed, immutable pointers
numbers++; // ERROR: Cannot modify the array name
ptr++; // Valid: Advances the pointer to the next integer

// sizeof behaves differently
printf("sizeof(numbers) = %zu\n", sizeof(numbers)); // Size of entire array (5 * sizeof(int))
printf("sizeof(ptr) = %zu\n", sizeof(ptr)); // Size of pointer only (typically 4 or 8 bytes)

Pointer Arithmetic with Arrays

Pointer arithmetic takes into account the size of the data type:

c
int numbers[5] = {10, 20, 30, 40, 50};
int *ptr = numbers;

ptr++; // Advances by sizeof(int) bytes, not just 1 byte
printf("%d\n", *ptr); // Prints 20, the second element

// We can also go backwards
ptr = &numbers[3]; // Points to the fourth element (40)
ptr--; // Now points to the third element (30)
printf("%d\n", *ptr); // Prints 30

Multi-dimensional Arrays and Pointers

Handling multi-dimensional arrays with pointers requires more care:

c
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};

// Accessing elements
int value1 = matrix[1][2]; // Value 7 using array notation

// With pointers (more complex)
int *ptr = &matrix[0][0]; // Points to the first element
int value2 = *(ptr + 1*4 + 2); // Value 7 using pointer arithmetic

// Or using pointer to array
int (*rowPtr)[4] = matrix; // Pointer to array of 4 integers
int value3 = rowPtr[1][2]; // Value 7

Arrays as Function Parameters

Arrays are always passed by reference (as pointers) to functions:

c
// Function that modifies an array
void modifyArray(int arr[], int size) {
// arr is actually a pointer here
arr[0] = 100; // This change affects the original array

// This proves arr is a pointer
printf("In function, sizeof(arr) = %zu\n", sizeof(arr)); // Prints the size of a pointer
}

int main() {
int numbers[5] = {10, 20, 30, 40, 50};
printf("Before: numbers[0] = %d\n", numbers[0]); // Prints 10

modifyArray(numbers, 5);

printf("After: numbers[0] = %d\n", numbers[0]); // Prints 100
return 0;
}

Iterating Through Arrays with Pointers

Pointers provide an alternative way to iterate through arrays:

c
int numbers[5] = {10, 20, 30, 40, 50};

// Method 1: Using array indexing
for (int i = 0; i < 5; i++) {
printf("%d ", numbers[i]);
}

// Method 2: Using pointer arithmetic
for (int *ptr = numbers; ptr < numbers + 5; ptr++) {
printf("%d ", *ptr);
}

Common Pitfalls

Beware of these common issues when working with arrays and pointers:

c
int numbers[5] = {10, 20, 30, 40, 50};
int *ptr = numbers;

// Out of bounds access (dangerous!)
int value = ptr[10]; // Accessing beyond the array bounds

// Dangling pointers
ptr = &numbers[0];
// ... some code that modifies ptr ...
if (ptr < numbers || ptr >= numbers + 5) {
printf("Pointer is outside array bounds!\n");
}
caution

C doesn't automatically check array bounds! Accessing elements outside the array's valid range can cause unpredictable behavior or crashes.

Applications and Best Practices

c
// Using pointers for efficient string processing
void reverseString(char *str) {
char *end = str;
while (*end) {
end++; // Move to the end of the string
}
end--; // Back up from null terminator

// Swap characters from outside in
while (str < end) {
char temp = *str;
*str++ = *end;
*end-- = temp;
}
}

// Using pointers for efficient array operations
void swapArrays(int *arr1, int *arr2, int size) {
for (int i = 0; i < size; i++) {
int temp = *(arr1 + i);
*(arr1 + i) = *(arr2 + i);
*(arr2 + i) = temp;
}
}

Conclusion

The relationship between pointers and arrays is one of C's most powerful features, allowing for efficient memory manipulation and flexible data access. Understanding this relationship is essential for mastering C programming and implementing efficient algorithms and data structures.

Understanding pointers and arrays together enables you to:

  • Write more efficient code with direct memory access
  • Implement complex data structures like linked lists and trees
  • Perform efficient string manipulation
  • Pass and modify arrays in functions effectively

In the next sections, we'll explore how pointers interact with functions and other advanced pointer concepts.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)