Pointers and Arrays

Arrays and pointers are like two views of the same person -- from different angles they present different forms, but underneath they point to the same contiguous block of memory.

The Array Name Is the Address of the First Element

In most expressions, the array name automatically converts to a pointer to the first element:

C
int arr[] = {10, 20, 30, 40, 50};
int *p = arr;

printf("%p\n", (void *)arr);
printf("%p\n", (void *)&arr[0]);
printf("%p\n", (void *)p);

All three addresses are identical. arr and &arr[0] are equivalent -- both are the address of the first element.

There are exceptions: sizeof(arr) returns the size of the entire array, not the pointer size. &arr is a pointer to the entire array with type int (*)[5], and its stride is the entire array.

C
printf("%zu\n", sizeof(arr));
printf("%zu\n", sizeof(p));

On a 64-bit system, these output 20 (5 x 4 bytes) and 8 (pointer size), respectively.

Pointer Traversal of Arrays

Since a pointer can point to array elements, you can traverse the entire array using pointer arithmetic:

C
int arr[] = {10, 20, 30, 40, 50};
int *p;
int len = sizeof(arr) / sizeof(arr[0]);

for (p = arr; p < arr + len; p++) {
    printf("%d ", *p);
}
printf("\n");

arr + len points to the position just past the last element, serving as the loop termination sentinel. This is a very common C pattern.

You can also use subscript notation:

C
int i;
for (i = 0; i < len; i++) {
    printf("%d ", *(arr + i));
}

Or:

C
int *p = arr;
int i;
for (i = 0; i < len; i++) {
    printf("%d ", p[i]);
}
💡 Tip: p[i] and *(p + i) are completely equivalent. The subscript operator is syntactic sugar for pointer arithmetic.

Pointer Arithmetic

Pointers support a limited set of arithmetic operations:

Adding and Subtracting Integers

C
int arr[] = {10, 20, 30, 40, 50};
int *p = arr + 2;

printf("%d\n", *p);
printf("%d\n", *(p + 1));
printf("%d\n", *(p - 1));

Output: 30, 40, 20. p+1 moves forward one int, p-1 moves backward one int.

Pointer Subtraction

Subtracting two pointers within the same array yields the number of elements between them:

C
int *q = &arr[4];
printf("%ld\n", (long)(q - p));

Output: 2, because p points to arr[2] and q points to arr[4], a difference of 2 elements.

Pointer Comparison

Pointers within the same array can be compared using <, <=, >, >= to determine relative positions:

C
int *start = arr;
int *end = arr + len;
while (start < end) {
    printf("%d ", *start);
    start++;
}
⚠️ Note: Pointer arithmetic is only meaningful within the same array. Subtracting or comparing pointers across different arrays is undefined behavior.

Pointer Stride Summary

Type Stride (bytes moved by p+1)
char * 1
int * 4
double * 8
int (*)[5] 20

Stride = sizeof(pointed-to type)

Equivalence of Pointers and Array Subscripts

The following two access forms are completely equivalent:

Expression Equivalent Form
arr[i] *(arr + i)
&arr[i] arr + i
p[i] *(p + i)
&p[i] p + i

The compiler converts subscript operations to pointer arithmetic. arr[3] and 3[arr] are even both legal in C (because *(arr+3) == *(3+arr)), though nobody writes the latter.

However, pointers and arrays have fundamental differences:

C
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;

Example

Reverse an array using pointers:

C
#include <stdio.h>

void reverse(int *arr, int len) {
    int *left = arr;
    int *right = arr + len - 1;

    while (left < right) {
        int temp = *left;
        *left = *right;
        *right = temp;
        left++;
        right--;
    }
}

int main(void) {
    int data[] = {1, 2, 3, 4, 5, 6, 7};
    int len = sizeof(data) / sizeof(data[0]);
    int i;

    reverse(data, len);

    for (i = 0; i < len; i++) {
        printf("%d ", data[i]);
    }
    printf("\n");
    return 0;
}
▶ Try it Yourself
TEXT
7 6 5 4 3 2 1

Two-pointer technique: left moves from the beginning toward the end, right moves from the end toward the beginning, swapping the elements they point to until they meet.

The Nature of Arrays as Function Parameters

When an array is passed to a function, the compiler only passes the address of the first element; the array length information is lost. This is "array decay to pointer":

C
void func(int arr[]) {
}

The parameter int arr[] is equivalent to int *arr. Inside the function:

C
void print_array(int *arr, int len) {
    int i;
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

Four equivalent signatures:

C
void func(int *arr, int len);
void func(int arr[], int len);
void func(int arr[5], int len);
void func(int arr[100], int len);

The number in the square brackets is ignored by the compiler; it merely indicates "this is a pointer".

Example

Deduplicate a sorted array using pointers:

C
#include <stdio.h>

int unique(int *arr, int len) {
    if (len == 0) return 0;

    int *dst = arr;
    int *src = arr + 1;
    int *end = arr + len;

    while (src < end) {
        if (*src != *dst) {
            dst++;
            *dst = *src;
        }
        src++;
    }

    return (int)(dst - arr + 1);
}

int main(void) {
    int data[] = {1, 1, 2, 2, 2, 3, 4, 4, 5};
    int len = sizeof(data) / sizeof(data[0]);
    int new_len = unique(data, len);
    int i;

    for (i = 0; i < new_len; i++) {
        printf("%d ", data[i]);
    }
    printf("\n");
    return 0;
}
▶ Try it Yourself
TEXT
1 2 3 4 5

dst tracks the write position for deduplicated data; src scans the original array. The function returns the new length. This is an in-place deduplication algorithm that requires no extra array.

❓ FAQ

Q Can an array name be assigned?
A No. arr = p; is illegal; the array name is a constant pointer. But p = arr; is legal because a pointer variable can be assigned.
Q What is the difference between arr and &arr?
A arr is the address of the first element, type int *, stride sizeof(int); &arr is the address of the entire array, type int (*)[5], stride sizeof(int[5]). The numeric value is the same, but the types differ.
Q Why can't I use sizeof on an array inside a function?
A When an array is passed as a parameter, it decays to a pointer, and sizeof gives the pointer size (4 or 8), not the array size. The length must be passed separately.
Q Is p[-1] legal?
A Syntactically legal, equivalent to *(p-1). If p points into the middle of an array, p[-1] accesses the previous element safely. But accessing outside the array bounds is undefined behavior.

📖 Summary

📝 Exercises

  1. Write a function that rotates an array left by one position (moving the first element to the end) using pointers, without an extra array.
  2. Write a function int *find(int *arr, int len, int target) that returns a pointer to the first element equal to target, or NULL if not found.
  3. Given a sorted array, implement binary search using pointers. Return a pointer to the found element, or NULL if not found.
100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏