Chapter 1 — Pointers
A pointer is a variable that **stores the address** of another variable. This is what makes C "low-level" — and what makes most C bugs.
What you'll learn
- 1Read and write the address-of (`&`) and dereference (`*`) operators.
- 2Understand pointer arithmetic on arrays.
- 3Pass by reference using pointers.
- 4Recognize NULL and dangling pointers.
Core Concepts
1) Declaration and basic ops
int x = 10;
int *p = &x; // p holds the address of x
printf("%d\n", *p); // 10 — dereference reads the value
*p = 20; // modify x through p| Symbol | Meaning |
|---|---|
| `&x` | address of x |
| `*p` | value at p |
| `int *p` | "pointer to int" |
2) Arrays decay to pointers
int a[3] = {1, 2, 3};
int *p = a; // same as &a[0]
printf("%d\n", *(p + 1)); // 2
printf("%d\n", p[1]); // 2 (a[i] ≡ *(a+i))3) Pointer arithmetic
int *p = a;
p + 1; // advances by sizeof(int) bytesArithmetic is **scaled by the type size**, not raw bytes.
4) Pass by reference
void inc(int *p) { (*p)++; }
int x = 10;
inc(&x);
printf("%d\n", x); // 11C is pass-by-value; to mutate the caller's variable you pass its address.
5) NULL
int *p = NULL;
if (p != NULL) { ... }Dereferencing `NULL` crashes. Always check before `*p`.
Examples
Example 1 — `ex01_basic.c`: address and dereference
int x = 42;
int *p = &x;
printf("x = %d\n", x);
printf("&x = %p\n", (void*)&x);
printf("p = %p\n", (void*)p);
printf("*p = %d\n", *p);**Output**
x = 42
&x = 0x7fff...
p = 0x7fff...
*p = 42Key: `p` and `&x` are the same address; `*p` reads the value at that address.
Example 2 — `ex02_swap.c`: swap two ints via pointers
void swap(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}
int x = 1, y = 2;
swap(&x, &y);
printf("x=%d y=%d\n", x, y);**Output**
x=2 y=1Key: passing addresses is how C does "by reference".
Example 3 — `ex03_array_ptr.c`: array via pointer
int a[] = {10, 20, 30};
int *p = a;
for (int i = 0; i < 3; i++) {
printf("%d ", *(p + i));
}**Output**
10 20 30Key: `a[i]` and `*(a+i)` mean the exact same thing.
Example 4 — `ex04_ptr_arith.c`: pointer arithmetic step
int a[] = {10, 20, 30};
int *p = a;
printf("p = %p\n", (void*)p);
printf("p+1 = %p\n", (void*)(p+1));
printf("diff = %ld bytes\n", (char*)(p+1) - (char*)p);**Output**
p = 0x7fff...
p+1 = 0x7fff... (offset by 4)
diff = 4 bytesKey: `p+1` shifts by `sizeof(int)` bytes, not 1.
Common mistakes
- **Uninitialized pointer** — `int *p; *p = 5;` writes to random memory.
- **Dangling pointer** — using a pointer after the pointee is freed/out-of-scope.
- **Confusing `*p++` and `(*p)++`** — different precedence.
- **`&p[i]` vs `p[i]`** — first is address, second is value.
Recap
- `&` takes an address; `*` reads/writes through it.
- Arrays decay to pointers when passed or assigned.
- Pointer arithmetic is type-scaled.
- Always init pointers (NULL if no target yet) and check before deref.
Try it
cd src
gcc -std=c11 -Wall -o ex01 ex01_basic.c && ./ex01
gcc -std=c11 -Wall -o ex02 ex02_swap.c && ./ex02
gcc -std=c11 -Wall -o ex03 ex03_array_ptr.c && ./ex03
gcc -std=c11 -Wall -o ex04 ex04_ptr_arith.c && ./ex04💻 Examples
Compilable, runnable examples — see the output yourself.
#include <stdio.h>
int main(void) {
int x = 42;
int *p = &x;
printf("x : %d\n", x);
printf("x : %p\n", (void*)&x);
printf("p : %p (= x )\n", (void*)p);
printf("*p: %d (p )\n", *p);
*p = 100;
printf("*p = 100 x = %d\n", x);
return 0;
}
x = 42
&x = 0x7fff...
p = 0x7fff...
*p = 42#include <stdio.h>
void swap(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}
int main(void) {
int x = 1, y = 2;
printf(" : x=%d, y=%d\n", x, y);
swap(&x, &y);
printf(" : x=%d, y=%d\n", x, y);
return 0;
}
x=2 y=1#include <stdio.h>
int main(void) {
int arr[5] = {10, 20, 30, 40, 50};
int *p = arr;
for (int i = 0; i < 5; i++) {
printf("arr[%d]=%d, *(p+%d)=%d, p[%d]=%d\n",
i, arr[i], i, *(p + i), i, p[i]);
}
printf("sizeof(arr) = %zu\n", sizeof(arr)); // 20
printf("sizeof(p) = %zu\n", sizeof(p)); // 8 (64-bit)
return 0;
}
10 20 30#include <stdio.h>
int main(void) {
int arr[] = {100, 200, 300, 400};
int *p = arr;
/* p */
printf("p -> %d ( %p)\n", *p, (void*)p);
p++;
printf("p+1 -> %d ( %p)\n", *p, (void*)p);
p += 2;
printf("p+3 -> %d ( %p)\n", *p, (void*)p);
/* = */
int *first = arr, *last = &arr[3];
printf("last - first = %ld\n", (long)(last - first));
return 0;
}
p = 0x7fff...
p+1 = 0x7fff... (offset by 4)
diff = 4 bytes📝 Exercises
Try them yourself first, then open the solution to compare.
Problem 1 (hw01.c)
Goal: Write a `swap(int *a, int *b)` that swaps two ints; demonstrate.
- Filename: hw01.c
▶Toggle solution
#include <stdio.h>
static void swap(int *x, int *y) { int t = *x; *x = *y; *y = t; }
void sort3(int *a, int *b, int *c) {
if (*a > *b) swap(a, b);
if (*b > *c) swap(b, c);
if (*a > *b) swap(a, b);
}
int main(void) {
int a, b, c;
printf(" Enter int: ");
scanf("%d %d %d", &a, &b, &c);
sort3(&a, &b, &c);
printf("sorted: %d %d %d\n", a, b, c);
return 0;
}
Problem 2 (hw02.c)
Goal: Write `void double_all(int *a, int n)` that doubles every element in place.
- Filename: hw02.c
▶Toggle solution
#include <stdio.h>
int sum(const int *arr, int n) {
int s = 0;
for (int i = 0; i < n; i++) s += arr[i];
return s;
}
int main(void) {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int n = (int)(sizeof(arr) / sizeof(arr[0]));
printf("sum: %d\n", sum(arr, n));
return 0;
}
Problem 3 (hw03.c)
Goal: Read N ints into a dynamically sized array (use a fixed size like 100) and print sum via pointer arithmetic.
- Filename: hw03.c
▶Toggle solution
#include <stdio.h>
void doubleAll(int *arr, int n) {
for (int i = 0; i < n; i++) arr[i] *= 2;
}
int main(void) {
int arr[] = {1, 2, 3, 4, 5};
int n = (int)(sizeof(arr) / sizeof(arr[0]));
doubleAll(arr, n);
for (int i = 0; i < n; i++) printf("%d ", arr[i]);
putchar('\n');
return 0;
}
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗