What are Dereferencing Pointers in C – Best C Language Course For Beginners

Need Help or More Information?

Questions about this free C programming course, embedded C training or career guidance? Get in touch.

Free C Programming Course · Pointers · Lecture 6

Dereferencing Pointers in C

The * operator explained for embedded C programming: read and write a variable through its address, with working code you can run today.

What You Will Learn

Welcome to the next lesson of our free C programming course. In the last lectures you learned how to declare a pointer, store an address in it and print that address. Now comes the part that makes pointers useful: dereferencing. This free C tutorial shows how the indirection operator lets you reach the variable that lives at an address, which is exactly how embedded C programming code talks to hardware registers, buffers and shared data.

  • What the indirection (dereference) operator * really does
  • Why *p can replace the variable name everywhere
  • How *(&x) collapses back to x
  • The difference between * in a declaration and * in an expression
  • Reading input straight into a variable through a pointer
  • Common dereferencing mistakes and how to avoid them

Prerequisites

You should know how to declare a pointer, use the address-of operator &, and initialise a pointer with a valid address or NULL. If any of that is hazy, revisit the earlier lectures of this free embedded C course first. You need only a C compiler such as gcc to follow along.

What Is Dereferencing in C?

A pointer variable stores an address. By itself an address is just a number. Dereferencing means following that number to the memory location it names and working with the object stored there. The operator that does this is the unary asterisk, written *, and it is called the indirection operator or dereference operator.

A handy way to read it aloud is “the value at the address”. So *ps is read as “the value at the address held in ps”. Whatever the pointer points to, *ps behaves exactly like that object: you can read it, assign to it, increment it or pass it to printf.

Pointer ps and the variable speed it points to

ps (pointer variable)holds address of speed
follow the address with *
speed (int variable)value 40
*ps names this same object

Suggested image 1: a labelled box-and-arrow picture of a pointer variable and its target variable. ALT text: “free C programming course dereferencing a pointer with the indirection operator”.

Two Meanings of the Asterisk

The star character appears in two different roles, and beginners often mix them up. Keep this table in mind for the whole embedded C programming journey.

Where it appearsExampleMeaning
In a declarationint *ps;ps is a pointer to int. The star is part of the type.
In an expression*ps = 5;Go to the address stored in ps and use the object there.
Multiplicationa * bBinary operator with two operands, nothing to do with pointers.

Pointer Dereference Rules: *p Stands in for the Variable

Once ps holds the address of speed, the expression *ps is an alias for speed. Every statement you can write with the variable you can also write with the dereferenced pointer. The table shows equivalent pairs for an int speed with ps = &speed and a float temp with pt = &temp.

Using the pointerUsing the variableWhat happens
*ps = 90;speed = 90;Store 90 in speed
(*ps)++;speed++;Add one to speed
adj = *pt + 10.0f;adj = temp + 10.0f;Read temp, add ten
printf("%d", *ps);printf("%d", speed);Print the current value
scanf("%d", ps);scanf("%d", &speed);Read input into speed
Mind the parentheses. The expression (*ps)++ increments the value that ps points to. Writing *ps++ means something different: it reads the value and then moves the pointer itself. We cover pointer movement in the next lectures, so for now always use parentheses when you want to change the pointed-to value.

Working Example: Reading and Writing Through a Pointer

Save this as deref_demo.c. It is a small original program that changes a speed and a temperature using only pointers, then lets you type a new speed that scanf stores directly through the pointer.

#include <stdio.h>

int main(void)
{
    int   speed = 40;
    float temp  = 36.5f;
    int   *ps   = &speed;
    float *pt   = &temp;

    *ps = 90;                  /* same as: speed = 90;      */
    (*ps)++;                   /* same as: speed++;         */
    float adj = *pt + 10.0f;   /* same as: temp + 10.0f     */

    printf("speed = %d, *ps = %d, *(&speed) = %d\n", speed, *ps, *(&speed));
    printf("temp  = %.1f, *pt = %.1f, adj = %.1f\n", temp, *pt, adj);

    printf("Enter a new speed: ");
    if (scanf("%d", ps) == 1)         /* ps already holds &speed */
        printf("speed is now %d\n", speed);
    return 0;
}

Build and run it:

$ gcc -Wall -Wextra -std=c11 -o deref_demo deref_demo.c
$ ./deref_demo
speed = 91, *ps = 91, *(&speed) = 91
temp  = 36.5, *pt = 36.5, adj = 46.5
Enter a new speed: 77
speed is now 77

Notice three things. First, speed became 91 even though we never wrote to it by name. Second, temp stayed at 36.5 because we only read it through pt. Third, scanf wanted an address as its second argument, and ps already is one, so we passed ps without an extra &.

Understanding *(&x) Equals x

The address-of operator and the dereference operator are inverses. The expression &speed produces the address of speed, and applying * to an address gives back the object stored there, which is speed. Therefore *(&speed) is the same thing as writing speed. The program above prints all three forms and they show the same number, which proves the point.

Mental model

Think of & as “give me the street address of this house” and * as “go to this street address and open the door”. Doing one right after the other lands you back in the same house.

Dereferencing in Real Embedded C Programming

On a microcontroller, peripherals are exposed as memory-mapped registers. Firmware writes to them by dereferencing a pointer whose value is the register address. A simplified pattern looks like this (the address is only an example, real values come from your chip’s reference manual):

#include <stdint.h>

#define LED_PORT_ADDR  0x40020014u

void led_on(void)
{
    volatile uint32_t *port = (volatile uint32_t *)LED_PORT_ADDR;
    *port |= (1u << 5);   /* set bit 5 of the register */
}

Do not run that on a PC: the address does not exist there and the program would crash. It shows why dereferencing matters so much in a free embedded C course. The word volatile tells the compiler the register can change on its own, so every * access must really happen.

Common Dereferencing Mistakes

MistakeWhy it is wrongFix
Using *p while p is uninitialisedp holds garbage, so you touch random memoryInitialise at declaration: int *p = &x; or NULL
Dereferencing NULLAddress 0 is not a valid object, usually a crashCheck if (p != NULL) first
Writing p = 9; instead of *p = 9;Assigns an integer to the pointer, not to the targetAdd the star, and enable compiler warnings
Dereferencing a pointer to a dead local variableThe stack slot was reused after the function returnedNever return the address of a local variable
Forgetting parentheses in (*p)++Operator precedence changes the meaningParenthesise the dereference
Security note. A wild dereference is the root cause of many memory-safety bugs. Validate pointers that come from outside your function, and compile with -Wall -Wextra so the compiler helps you.

Best Practices

  • Initialise every pointer at the moment you declare it.
  • Use a descriptive name so *ps and *pt tell the reader what they touch.
  • Use const (for example const int *p) when the function only reads through the pointer.
  • Use volatile for pointers to hardware registers.
  • Print with %p and a (void *) cast when you need to see an address, never %u.

Key Takeaways

  • * applied to a pointer means “the object at that address”.
  • *ps can appear anywhere the variable speed can appear, on either side of an assignment.
  • *(&x) is simply x because & and * undo each other.
  • The star in a declaration is part of the type, the star in an expression is the operator.
  • Always make sure a pointer holds a valid address before you dereference it.

Conclusion

Dereferencing turns a pointer from a plain number into a handle on real data. With it you can change a caller’s variable from inside a function, walk through arrays, and program hardware registers, which is why every serious embedded C programming course spends time on it. In the next lecture of this free C tutorial we will ask an important question: how does the compiler know how many bytes to read when you write *p? The answer lies in the pointer’s type.

Frequently Asked Questions

What does the * operator do in C?

Applied to a pointer, it accesses the object stored at the address the pointer holds. This is called dereferencing.

Is *p the same as the variable it points to?

Yes. If p holds the address of x, then *p and x refer to the same memory, so changing one changes the other.

Why does scanf not need an ampersand when I pass a pointer?

scanf needs an address. A pointer variable already contains one, so you pass it directly.

What is the difference between *p++ and (*p)++?

(*p)++ increments the pointed-to value. *p++ yields the value and then advances the pointer to the next element.

What happens if I dereference a NULL pointer?

The behaviour is undefined. On most systems the program crashes, and on some microcontrollers it may silently read address zero.

Do I need to learn pointers for embedded systems?

Absolutely. Registers, buffers, callbacks and drivers all depend on pointers, so this free embedded C course treats them in depth.

Continue the Free C Programming Course

Practise by changing the demo to use a double and a char, then move on to the next lecture to learn why pointer type decides how many bytes are read.

Need Help or More Information?

Questions about this free C programming course, embedded C training or career guidance? Get in touch.

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *