# Pointers in C — Addresses, Dereferencing and Pointer Arithmetic

Source: https://skills101.in/learn/c-programming/c-pointers — Skills101 free tutorial (C Programming). Updated 2026-11-09.

A **pointer** is a variable that stores the **address** of another variable. That's it. Everything else follows from this one idea.

## 1. & and *

![int x holds 10 at address 1000; int *p holds 1000, so p points to x. &x is 1000, p is 1000 and *p is 10; *p = 25 changes x](https://skills101.in/learn-img/c-programming/pointer-basic.svg)

- **`&x`** — "address of x"
- **`int *p`** — "p is a pointer to an int"
- **`*p`** — "the value at the address in p" (dereferencing)

```c
#include <stdio.h>

int main(void) {
    int x = 10;
    int *p = &x;
    printf("%d %d\n", x, *p);
    *p = 25;                 /* change x through p */
    printf("%d\n", x);
    printf("%d\n", p == &x);
    return 0;
}
```

```text
10 10
25
1
```

(Actual addresses change every run, so we compare them instead of printing them.)

## 2. Pointers and arrays

![Array a holds 10, 20, 30, 40, 50 at addresses 100, 104, 108, 112, 116; a + 2 is 108 and *(a + 2) equals a[2], which is 30](https://skills101.in/learn-img/c-programming/array-pointer.svg)

The name of an array is (in most expressions) a pointer to its first element. And **`a[i]` is exactly `*(a + i)`**.

```c
#include <stdio.h>

int main(void) {
    int a[5] = {10, 20, 30, 40, 50};
    int *p = a;                       /* same as &a[0] */
    printf("%d %d %d\n", *p, *(p + 2), p[4]);
    p++;                              /* move to the next int */
    printf("%d\n", *p);
    printf("%d\n", (int)(&a[4] - &a[0]));   /* distance in elements */
    return 0;
}
```

```text
10 30 50
20
4
```

### Pointer arithmetic

`p + 1` moves by **sizeof(type)** bytes, not 1 byte. For an `int *` that's 4 bytes; for a `double *`, 8 bytes. You can:
- add/subtract an integer (`p + 2`, `p--`)
- subtract two pointers into the same array (gives the number of elements between them)
- compare pointers

You **can't** add two pointers.

## 3. NULL and safety

```c
int *p = NULL;      /* points nowhere */
if (p != NULL) {
    printf("%d", *p);
}
```

- Dereferencing **NULL** crashes the program (segmentation fault).
- A **wild pointer** is uninitialised (points anywhere) — always initialise pointers.
- A **dangling pointer** points to memory that was freed or a local variable that no longer exists.

## 4. Pointer to pointer

```c
#include <stdio.h>

int main(void) {
    int x = 7;
    int *p = &x;
    int **pp = &p;
    printf("%d %d %d\n", x, *p, **pp);
    **pp = 99;
    printf("%d\n", x);
    return 0;
}
```

```text
7 7 7
99
```

Used for dynamic 2D arrays and when a function must change a pointer (e.g. inserting at the head of a linked list).

## 5. const and pointers

| Declaration | Can change the value? | Can point elsewhere? |
|---|---|---|
| `const int *p` | ✗ | ✓ |
| `int *const p` | ✓ | ✗ |
| `const int *const p` | ✗ | ✗ |

Read it **right to left**: `int *const p` = "p is a const pointer to int".

## 6. void pointers

`void *` can hold the address of any type (used by `malloc`). You must cast it to a real type before dereferencing.

## Common mistakes

- Using `*p` before `p` points to valid memory.
- Confusing `*p++` (move p, value of old position) with `(*p)++` (increase the value).
- Returning the address of a local variable from a function (dangling pointer).

## Quick recap

- `&x` = address; `*p` = value at address; `int *p` declares a pointer.
- `a[i] == *(a + i)`; `p + 1` moves by sizeof(type).
- Initialise pointers; check for NULL; avoid dangling pointers.
- `**pp` = pointer to pointer; read const declarations right to left.


Practice quiz and free certificate: https://skills101.in/learn/c-programming/c-pointers