Array Name Semantics
When accessing array elements with pointers, we often write code like this:
int data[10] = {1,2,3,4,5,6,7,8,9,10};
int *ptr = &data[0];
While using &data[0] retrieves the address of the first element, the array name itself serves as the address. Consider the following demonstration:
#include <stdio.h>
int main() {
int data[10] = {0};
printf("%p\n", &data[0]);
printf("%p\n", data);
return 0;
}
Both expressions produce identical output, confirming that the array name equals the address of the first element.
However, this rule has exceptions. Examine the output of this code:
int main() {
int data[10] = {1,2,3,4,5,6,7,8,9,10};
printf("%zu\n", sizeof(data));
return 0;
}
The result is 40, not 4 or 8. If data were simply an address, sizeof(data) should return the pointer size, not the entire array size.
Two scenarios break the "array name equals first element address" rule:
- sizeof(array_name) — When the array name appearrs alone inside
sizeof, it represents the entire array, and the result is the total byte count. - &array_name — Taking the address of the array name yields the address of the whole array, not just the first element.
Everywhere else, the array name behaves as a pointer to the first element.
Let's examine the difference between array address and element address:
#include <stdio.h>
int main() {
int data[10] = {1,2,3,4,5,6,7,8,9,10};
printf("&data[0] = %p\n", &data[0]);
printf("&data[0]+1 = %p\n", &data[0] + 1);
printf("data = %p\n", data);
printf("data+1 = %p\n", data + 1);
printf("&data = %p\n", &data);
printf("&data+1 = %p\n", &data + 1);
return 0;
}
Both &data[0] and data represent the first element's address. Adding 1 to either advances by 4 bytes, moving to the next element.
How ever, &data represents the entire array's address. Adding 1 to this advances by 40 bytes, jumping past the complete array.
Accessing Arrays with Pointers
With this foundation, pointer-based aray access becomes straightforward:
#include <stdio.h>
int main() {
int data[10] = {0};
int count = sizeof(data) / sizeof(data[0]);
int *ptr = data;
for (int i = 0; i < count; i++) {
scanf("%d", ptr + i);
}
for (int i = 0; i < count; i++) {
printf("%d ", *(ptr + i));
}
return 0;
}
Since data represents the first element's address, it can be assigned to a pointer variable. Both data and ptr point to the same location.
The expression data[i] accesses elements just like ptr[i]. In fact, ptr[i] is equivalent to *(ptr + i), and data[i] is equivalent to *(data + i). The compiler converts array element access into: compute the address (base address + offset), then dereference.
Due to the commutative property of addition, i[data] and *(i + data) are also valid but rarely used in practice.
One-Dimensional Array Parameter Passing
Arrays can be passed to functions, but what happens inside the function? Consider this example:
void printSize(int arr[]) {
int count = sizeof(arr) / sizeof(arr[0]);
printf("%d", count);
}
int main() {
int data[10] = {0};
printSize(data);
return 0;
}
The output is 1, not 10. Why?
Array parameter passing transfers the address of the first element, not the entire array. The parameter arr receives a pointer, not a copy of the array.
On an x86 architecture, an int pointer occupies 4 bytes. Inside printSize, sizeof(arr) yields 4, and sizeof(arr[0]) yields 4, resulting in 4 / 4 = 1.
Therefore, array parameter passing本质上 passes the first element's address. The parameter declaration int arr[] is syntactic sugar—the compiler treats it as int *arr. Consequently, calculating element count inside the function is impossible using sizeof.
In summary: one-dimensional array parameters can be written as int arr[] or int *arr—both are equivalent.
Double Pointers
Pointer variables are still variables, meaning they have addresses. Where do pointer addresses get stored? In a double pointer (pointer to pointer).
int a = 10;
int *p = &a; // p holds address of a
int **pp = &p; // pp holds address of p
Operations on double pointers:
*ppdereferencesppto obtainp(the address ofa).**ppfirst dereferences to getp, then dereferencespto obtaina's value (10).
Pointer Arrays
What exactly is a pointer array?
Analogous reasoning:
- Integer array: stores integers
- Character array: stores characters
- Pointer array: stores pointers
A pointer array is an array where each element is a pointer.
Simulating Two-Dimensional Arrays
Pointer arrays can simulate two-dimensional array behavior:
#include <stdio.h>
int main() {
int row1[] = {1, 2, 3, 4, 5};
int row2[] = {2, 3, 4, 5, 6};
int row3[] = {3, 4, 5, 6, 7};
int *matrix[3] = {row1, row2, row3};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 5; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
return 0;
}
Here, matrix is an array of three pointers. Each pointer points to a one-dimensional array. The expression matrix[i][j] accesses the j-th element of the i-th row.
Important distinction: Unlike a true two-dimensional array where rows are contiguous in memory, pointer-array simulation stores each row at a separate location. The rows are not necessarily adjacent in memory.