Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.
Pointer Basics in Embedded C: Addresses, Dereferencing, NULL and Register Pointers
What an address is, the & and * operators, declaring pointers, why the pointer type matters, pointer size on the Cortex-M4, NULL and wild pointers, aliasing and a first look at register pointers. Keep this in mind whenever you apply pointer basics in embedded C.
What You Will Learn
& and dereference *Key Terms
1. Memory Is a Row of Numbered Bytes
A microcontroller sees its memory as one long row of bytes, each with a number called its address. On the STM32F407 the SRAM starts at address 0x20000000 and the Flash at 0x08000000; peripherals such as GPIOD appear at 0x40020C00. Every variable occupies one or more consecutive bytes, so each has three properties: a name, a value and an address. Many bugs in pointer basics in embedded C start here.
A pointer is a variable whose value is the address of another variable. Knowing the address, the program can read or change that variable indirectly, without using its name. Pointers are the foundation of arrays, strings, callbacks, data structures and, in embedded work, every access to a peripheral register. This is the core rule of pointer basics in embedded C.
All pointer types have the same size on a given machine: the width of an address. The STM32F407 has a 32-bit address space (4 GB), so a pointer is 4 bytes; the 64-bit PC used to run these programs shows 8. The explanations below hold on both; where a number differs, the text says so. Reviewers check pointer basics in embedded C closely.
2. The Two Operators: & and *
Two operators do all the work. The address-of operator &x gives the address of x. The dereference (indirection) operator *p gives the object that p points to. They are opposites: *(&x) is x again. Interviewers test pointer basics in embedded C on exactly this point.
| Expression | Meaning | Example result |
|---|---|---|
int x = 10; | x holds the value 10 | x = 10 |
int *p = &x; | p holds the address of x | p points to x |
*p | the int at that address | 10 |
*p = 25; | writes 25 to x through p | x = 25 |
&x == p | comparison of addresses | 1 (true) |
The variable and the pointer see the same memory: a change through either is visible through the other. The exact address is not printed because it changes between runs and platforms; only relations such as &x == p are meaningful. Master pointer basics in embedded C by practising this case.
int *p;) the star says “p is a pointer”. In an expression (*p = 5;) it means “the object p points to”. Multiplication is a third use.3. Declaring Pointers
A pointer declaration names the type of object it points to. Read it from the variable name outward. Remember this when you review pointer basics in embedded C in code reviews.
| Declaration | Reads as |
|---|---|
int *p; | p is a pointer to int |
uint8_t *buf; | buf is a pointer to uint8_t (a byte pointer) |
char *s; | s is a pointer to char |
const int *q; | q is a pointer to const int (Lesson 8.2) |
int *a, b; | a is a pointer to int, b is a plain int |
int *a; then int b;). The star binds to the name, not to the type, so int* a, b; misleads the reader.4. The Pointer Type Decides What Is Read
A pointer holds only an address; the type tells the compiler how many bytes to access and how to interpret them. The same address read through three different pointer types yields three different values. On both the Cortex-M4 and an x86 PC the byte order is little-endian: the least significant byte is stored at the lowest address.
Reading the same memory through a pointer of a different type is the basis of byte-level access to buffers and registers (Lesson 9.5 treats casting and alignment in depth). It also means a pointer of the wrong type silently reads the wrong number of bytes: the compiler warns about incompatible types, so never silence the warning with a cast unless you understand the consequences.
5. Initialising Pointers: NULL and Wild Pointers
An uninitialised local pointer holds garbage, a wild pointer: dereferencing it reads or writes a random address. On the STM32F407 that can hit a peripheral register, corrupt another variable, or cause a BusFault. Always initialise a pointer, either to a valid address or to NULL, the null pointer constant (a pointer value that points to no object, written 0 or NULL).
A NULL pointer converts to false in a condition, so if (p) and if (p != NULL) are equivalent. Dereferencing NULL is undefined behavior; on a Cortex-M4 address 0 is readable (it is an alias of the start of Flash), so a stray read of NULL often succeeds silently and returns the first word of the vector table, which makes the bug harder to find than the crash on a PC.
6. Several Pointers, One Object (Aliasing)
Nothing stops two pointers from holding the same address. A write through one is then visible through the other. This is useful (a handle shared between modules, a hardware register accessed from two places) and dangerous (a function that assumes its two pointer parameters are distinct, see the XOR swap in Lesson 8.2).
7. A First Look at Register Pointers
The most important pointer in embedded C is a pointer to a peripheral register. The STM32F407 reference manual gives a fixed address for each register; the program turns that number into a pointer and dereferences it. Writing GPIOD_ODR then writes the output data register of port D (base 0x40020C00, ODR at offset 0x14).
Read the macro from the inside: the integer 0x40020C14 is cast to “pointer to volatile uint32_t”, and the outer * dereferences it, so the macro behaves like an ordinary variable that happens to live in the peripheral space. volatile tells the compiler that every access matters. On a PC this address does not exist, so the next program uses an ordinary variable as a stand-in register with the same macro shape.
Lesson 9.6 builds this idea out into register structs and safe access macros. For now remember the principle: a register is just a memory location with a fixed address, and a pointer reaches it.
8. Common Pointer Mistakes
| Mistake | Effect | Fix |
|---|---|---|
| Uninitialised pointer | Write to a random address | Initialise to a valid address or NULL |
| Dereferencing NULL | Undefined behavior (silent read on Cortex-M) | Check before use |
| Returning the address of a local | Dangling pointer | Return a value, a static, or fill a caller buffer |
| Wrong pointer type | Wrong number of bytes read | Match the type to the data |
int *a, b; misread | b is not a pointer | One declaration per line |
| Assigning an integer to a pointer | Compiler warning, wrong address | Cast deliberately: (volatile uint32_t *)0x40020C14 |
GCC reports each of these (the exact wording varies between versions). Treat pointer warnings as errors in firmware: -Werror=incompatible-pointer-types -Werror=int-conversion -Werror=return-local-addr.
9. Best Practices for Pointer Basics in Embedded C
- Initialise every pointer at its declaration (to an address or
NULL). - Declare one pointer per line and keep the star next to the name.
- Use fixed-width types for what is pointed to (
uint8_t *,uint32_t *). - Check pointers received from outside for NULL before dereferencing.
- Use
constfor read-only data andvolatilefor registers. - Never print or compare pointer values in portable logic; use
uintptr_tif you must convert to an integer. - Do not return the address of a local variable.
- Keep the warnings on: pointer warnings usually mean real bugs.
Key Takeaways — Lesson 9.1
- A pointer is a variable that stores an address;
&produces an address and*follows one. - The pointer type decides how many bytes are accessed and how they are interpreted.
- A pointer is 4 bytes on the Cortex-M4 (8 on a 64-bit PC).
- Initialise pointers; NULL means “no object” and must be checked before use.
- Two pointers can alias one object; writes are visible through both.
- A peripheral register is a fixed address reached through a (volatile) pointer.
Frequently Asked Questions
Ready to practise?
Next: worked examples with swaps, byte access, buffers, NULL checks and simulated GPIO registers.
Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.

2 Comments