Understanding C Pointers: Arrays, Parameters, and Pointer Operations

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:

  1. sizeof(array_name) — When the array name appearrs alone inside sizeof, it represents the entire array, and the result is the total byte count.
  2. &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:

  • *pp dereferences pp to obtain p (the address of a).
  • **pp first dereferences to get p, then dereferences p to obtain a'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.

Tags: c programming pointers Arrays double pointers pointer arrays

Posted on Mon, 31 Aug 2026 16:27:15 +0000 by bigshwa05