Pointer Basics

Pointers are like street addresses -- the address itself is not the house, but through it you can find that exact house. Master addresses, and you master C's most powerful feature.

What Is a Pointer?

Every byte in memory has a unique number called an address. A pointer variable is a variable specifically designed to store an address.

C
int x = 42;
int *p = &x;

Pointers themselves also occupy memory. On a 32-bit system, a pointer is 4 bytes; on a 64-bit system, it is 8 bytes, regardless of the type it points to.

The Address-of Operator &

& is used to obtain a variable's address:

C
int a = 10;
printf("Value of a: %d\n", a);
printf("Address of a: %p\n", (void *)&a);

The %p format specifier prints an address; the argument should be cast to void *.

What you can take the address of:

What you cannot take the address of:

The Dereference Operator *

* is used to access the data a pointer points to:

C
int x = 42;
int *p = &x;

printf("%d\n", *p);
*p = 100;
printf("%d\n", x);

The first output is 42, the second is 100. *p = 100 modifies x through the pointer.

💡 Tip: * in a declaration means "this is a pointer"; in an expression it means "dereference" (get the pointed-to value). The meaning depends on context.

Dereferencing an uninitialized pointer is a serious error:

C
int *p;
*p = 10;

The value of p is random; writing to a random address may corrupt other data or crash immediately.

The NULL Pointer

NULL is a special pointer value meaning "does not point anywhere". It is defined in several headers including <stddef.h>, and its value is typically 0.

C
int *p = NULL;

if (p == NULL) {
    printf("Pointer does not point to a valid address\n");
}

Dereferencing a NULL pointer causes a segmentation fault and crashes the program. Therefore, always check whether a pointer is NULL before using it:

C
void safe_print(int *p) {
    if (p != NULL) {
        printf("%d\n", *p);
    }
}
⚠️ Note: If a pointer is not immediately assigned after definition, always initialize it to NULL. An uninitialized "wild pointer" has an indeterminate value and is more dangerous than a NULL pointer because it cannot be detected via a NULL check.

Pointer Types and Stride

The pointer type determines how many bytes are read during dereference, and how many bytes the pointer moves during arithmetic (the stride).

C
int a = 10;
double b = 3.14;

int *pi = &a;
double *pd = &b;

Pointer stride equals the size of the pointed-to type:

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

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

Output: 10, 20, 40. p+1 does not add 1 to the address value; it adds sizeof(int) (4 bytes), pointing to the next int element.

Pointer subtraction results are also measured in elements:

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

Output: 4, meaning 4 int elements separate the two pointers.

💡 Tip: Pointers of different types cannot be directly assigned. int *p = &d; (where d is a double) will produce a compiler warning because the type mismatch causes the wrong number of bytes to be read during dereference.

Example

Swap two variable values using pointers:

C
#include <stdio.h>

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main(void) {
    int x = 10, y = 20;
    printf("Before swap: x=%d, y=%d\n", x, y);
    swap(&x, &y);
    printf("After swap: x=%d, y=%d\n", x, y);
    return 0;
}
▶ Try it Yourself
TEXT
Before swap: x=10, y=20
After swap: x=20, y=10

Here, addresses are passed to the function, which modifies the original variables through dereference. This is the classic technique for "simulating pass by reference" -- the function parameter is an int * pointer, and the call passes &x.

Pointers and const

Combining const with pointers has two meanings:

Pointer to a Constant

C
const int *p = &x;
*p = 20;

Illegal. You cannot modify the data through p, but p itself can point to a different variable:

C
p = &y;

Legal.

Constant Pointer

C
int * const p = &x;
p = &y;

Illegal. p cannot change what it points to, but you can modify the data through p:

C
*p = 20;

Legal.

Memory trick: const to the left of * modifies the data; const to the right of * modifies the pointer itself.

Example

Sum an array using pointer traversal:

C
#include <stdio.h>

int array_sum(const int *arr, int len) {
    int sum = 0;
    const int *end = arr + len;
    while (arr < end) {
        sum += *arr;
        arr++;
    }
    return sum;
}

int main(void) {
    int data[] = {3, 7, 1, 9, 5};
    int total = array_sum(data, 5);
    printf("Sum: %d\n", total);
    return 0;
}
▶ Try it Yourself
TEXT
Sum: 25

The parameter const int *arr indicates the function will not modify the array contents. The pointer end marks the stopping position, avoiding the need for subscripts.

❓ FAQ

Q How many bytes does a pointer variable occupy?
A It depends on the system's address width: 4 bytes on 32-bit systems, 8 bytes on 64-bit systems, regardless of the pointed-to type.
Q Does the * in int *p belong to the type or the variable?
A It belongs to the variable. int* p, q; declares p as an int pointer and q as a plain int. It is recommended to declare only one pointer per line.
Q What is the difference between NULL and an uninitialized pointer?
A NULL is a definite value (0) that can be checked; an uninitialized pointer has a random value and cannot be reliably detected, making it more dangerous.
Q Does dereferencing a NULL pointer always crash?
A Not guaranteed. Address 0 may be a valid address on some embedded systems. However, on mainstream operating systems, accessing address 0 triggers a segmentation fault.

📖 Summary

📝 Exercises

  1. Write a function void divide(int a, int b, int *quotient, int *remainder) that returns the quotient and remainder through pointer parameters.
  2. Write a program that defines an int variable and a double variable, points to them with int * and double * respectively, prints their addresses and values, and observes the stride difference.
  3. Write a function int *find_max(int *arr, int len) that returns a pointer to the maximum element in the array.
100%

🙏 帮我们做得更好

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

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