Arrays and pointers are closely related but not the same thing: an array is storage; a pointer refers to storage. The link is decay — an array name converts to a pointer to its first element.
a[i] ≡ *(a + i) ≡ *(i + a) ≡ i[a]
#include <stdio.h>
int main(void) {
int a[4] = {1, 2, 3, 4};
int *p = a; /* decay: p = &a[0] */
printf("%d %d %d %d\n", a[2], *(a + 2), p[2], 2[a]); /* all the same */
printf("sizeof a = %zu, sizeof p = %zu\n", sizeof a, sizeof p);
p++; /* a pointer can move... */
printf("*p = %d\n", *p);
/* a++; ...an array cannot: error, array type is not assignable */
return 0;
}3 3 3 3
sizeof a = 16, sizeof p = 8
*p = 2Array int a[4] | Pointer int *p | |
|---|---|---|
| What it is | 4 ints of storage | 8 bytes holding an address |
sizeof | 16 | 8 |
Assignable (a = …) | No | Yes |
&x | int (*)[4] — pointer to the whole array | int ** |
| Where the data is | Inside the array itself | Somewhere else |
&a vs a: same address, different types
#include <stdio.h>
int main(void) {
int a[4] = {0};
int *first = a; /* int * */
int (*whole)[4] = &a; /* int (*)[4] */
printf("same address: %d\n", (void *)first == (void *)whole);
printf("first + 1 moves %td bytes\n", (char *)(first + 1) - (char *)first);
printf("whole + 1 moves %td bytes\n", (char *)(whole + 1) - (char *)whole);
return 0;
}same address: 1
first + 1 moves 4 bytes
whole + 1 moves 16 bytesArrays of pointers vs pointer to array
#include <stdio.h>
int main(void) {
int x = 1, y = 2, z = 3;
int *arr_of_ptrs[3] = {&x, &y, &z}; /* 3 pointers */
int grid[2][3] = {{1, 2, 3}, {4, 5, 6}};
int (*row)[3] = grid; /* pointer to an array of 3 ints */
printf("%d %d\n", *arr_of_ptrs[1], *arr_of_ptrs[2]);
row++; /* moves one whole row */
printf("%d %d\n", (*row)[0], row[0][2]);
return 0;
}2 3
4 6sizeof inside a function
#include <stdio.h>
void f(int arr[10]) { /* the 10 is ignored: arr is int * */
printf("in f: %zu\n", sizeof arr);
}
int main(void) {
int data[10];
printf("in main: %zu\n", sizeof data);
f(data);
return 0;
}Are arrays and pointers the same in C?
What does int (*p)[5] declare, versus int *p[5]?