1. The Core Relationship
In C, pointers and arrays are extremely closely linked. The most important concept to understand is this:
The name of an array, when used in an expression, is a constant pointer to the first element of the array.
This means that if you have an array int arr[5];, the following two expressions are
identical:
·
arr (the
name of the array)
·
&arr[0] (the
address of the first element)
Both expressions give you the starting memory address of the array.
/* * Example 1: Array Name as a Pointer * Proves that the array name is the same as the * address of its first element.*/
#include <stdio.h>
int main() {
int nums[5] = {10, 20, 30, 40, 50};
printf("Value of 'nums': %p\n", nums);
printf("Value of '&nums[0]': %p\n", &nums[0]);
// Both print the exact same memory address!
return 0;
}2. Pointer Arithmetic
Because the array name is a pointer, you can use pointer arithmetic to
access its elements. When you add a number (like 1, 2, or i) to a pointer, C does something very smart:
It does not just
add 1 byte. It adds 1 * sizeof(data_type) bytes.
·
If arr is an int pointer (and int is 4 bytes):
o arr + 1 points to the next
integer, which is 4 bytes away.
o arr + 2 points to the second next
integer, which is 8 bytes away.
This allows you to move from element to element perfectly.
, arr[1], arr[2]]
3. Accessing Arrays: Notation vs. Pointer Notation
This leads to two ways to access the same element:
1.
Array Notation (Common): arr[i]
2.
Pointer Notation (Also valid): *(arr + i)
o (arr + i): First, calculate the
address of the i-th element.
o *: Second, dereference that address
to get the value.
The compiler treats arr[i] as
just a simpler way to write *(arr + i). They are
100% equivalent.
/* * Example 2: Array vs. Pointer Notation * Accessing array elements in two equivalent ways.*/
#include <stdio.h>
int main() {
int nums[5] = {10, 20, 30, 40, 50};
// Access element at index 2 (the value 30)
printf("Using array notation nums[2]: %d\n", nums[2]);
printf("Using pointer notation *(nums + 2): %d\n", *(nums + 2));
// They are identical. Let's prove it in a loop.
printf("\n--- Loop Demonstration ---\n");
int i;
for (i = 0; i < 5; i++) {
printf("Address: %p, Value (arr[i]): %d, Value (*(arr+i)): %d\n",
(nums + i), nums[i], *(nums + i)); } return 0;
}4. Passing Arrays to Functions (A Key Concept)
When you pass an array as an argument to a function, you are not passing a copy of the entire array. That would be very slow and waste memory.
Instead, C automatically passes a pointer to the first element of the array.
This is why the following two function declarations (prototypes) are 100% equivalent:
// Method 1: Using array notation (easier to read)
void myFunction(int arr[], int size);
// Method 2: Using pointer notation (what the compiler actually sees)
void myFunction(int *arr, int size);
This has a huge implication: Because
the function receives the actual
address of the original array (not a copy), any changes the
function makes to the array elements are permanent and will affect the original
array in your main function.
/* * Example 3: Passing Arrays to Functions * Demonstrates that the function can modify the * original array because it receives a pointer.*/
#include <stdio.h>
// This function takes a pointer to an array
// It triples every value in the array
void tripleElements(int *arr, int size) {
printf("\n[Inside Function] Modifying array...\n");
int i;
for (i = 0; i < size; i++) {
// We can use array notation [i] even though 'arr' is a pointer!
arr[i] = arr[i] * 3; }} // This function also takes a pointer (using [] notation)
void printArray(int arr[], int size) {
int i;
for (i = 0; i < size; i++) {
printf("%d ", arr[i]);
}printf("\n");
} int main() {
int nums[5] = {1, 2, 3, 4, 5};
printf("Original array in main: ");
printArray(nums, 5);
// Pass the array to the function.
// We are just passing 'nums', which is a pointer.
tripleElements(nums, 5);
printf("\n[Back in Main] Array is now: ");
printArray(nums, 5);
// Note that the original array in main() has been changed!
return 0;
}5. Array Name vs. Pointer Variable
This is a small but important advanced detail. While an array name acts like a pointer, there is one key difference:
·
An array
name (e.g., arr) is
a CONSTANT pointer.
Its value (the address it holds) is fixed and cannot be changed. You cannot do arr++;.
·
A pointer
variable (e.g., int
*p) is a VARIABLE.
You can change what it points to. You can do p++;.
/* * Example 4: Array Name vs. Pointer Variable * Shows the key difference in a loop.*/
#include <stdio.h>
int main() {
int nums[5] = {10, 20, 30, 40, 50};
// Create a pointer VARIABLE and make it point to the start of the array
int *p = nums; // This is valid. p now points to nums[0]
printf("Address in p: %p, Value at p: %d\n", p, *p);
// We can increment the pointer VARIABLE
p++; // This is valid. p now points to nums[1]
printf("Address in p: %p, Value at p: %d\n", p, *p);
// However, we CANNOT increment the array name itself
// nums++; // <-- This line will cause a COMPILE ERROR
// Error: "expression must be a modifiable lvalue"
return 0;
}