What are C Address Operator Explained – Best C Programming Course

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 · Chapter 8 · Pointers · Lecture 2

C Address Operator Explained

Learn how the & operator returns the address of a variable, where it works, where it fails, and why scanf has always needed it. Part of our free C tutorial for embedded systems learners.

&
Reads as “address of”
%p
Correct format for addresses
2
Lectures to go before dereferencing

In the last lecture of this free C programming course you learned that every variable lives at an address. Now we learn how to ask for that address. The tool is the address operator, written &, and it is the first real pointer-related skill in this free C tutorial.

For anyone studying embedded C programming, the address operator is not a classroom curiosity. It is how you hand a buffer to a UART driver, give a DMA controller its target, or pass a variable to a function that must fill it in.

What You Will Learn

By the end of this lecture you can:

  • Use the C address operator on variables and array elements.
  • Explain which operands are legal and which cause a compiler error.
  • Print an address with %p and understand the result.
  • Explain why scanf needs & in front of variable names.
  • Show that array elements have neighbouring addresses that differ by the element size.

Prerequisites

Finish the previous lecture on memory and addresses first. You should know that memory is a row of numbered bytes and that a variable’s address is the address of its first byte. You also need to know how to compile with gcc, which every lesson in this free embedded C course assumes.

The C Address Operator

The address operator is a unary operator: it takes one operand and is written directly in front of it. Place & before a variable and the expression produces the address of that variable. Read it aloud as “address of”: &voltage means “the address of voltage”.

What the address operator does
Input: a variable that lives in memory
variable: voltage apply & result: address of voltage
The result is a memory address, the lowest address of the variable’s bytes.

Two facts are worth fixing in your mind right now:

  • The result of &x is not the value of x. It is where x is stored.
  • The type of the result is “pointer to the type of x”. For an int variable, &x has type int *. We will use that in the next lecture when we declare pointer variables.

Address Operator Demo Program

The program below takes the address of a normal variable and of each element of a small array. It then measures the distance in bytes between two neighbouring elements.

#include <stdio.h>

int main(void)
{
    int readings[3] = {10, 20, 30};
    double voltage = 3.3;

    printf("voltage = %.1f stored at %p\n", voltage, (void *)&voltage);
    for (int i = 0; i < 3; i++)
        printf("&readings[%d] = %p\n", i, (void *)&readings[i]);

    printf("gap between neighbours = %td bytes\n",
           (char *)&readings[1] - (char *)&readings[0]);
    return 0;
}

Build and run

gcc -Wall -Wextra -o addr_demo addr_demo.c
./addr_demo

Sample output

voltage = 3.3 stored at 0x7fff3faae200
&readings[0] = 0x7fff3faae20c
&readings[1] = 0x7fff3faae210
&readings[2] = 0x7fff3faae214
gap between neighbours = 4 bytes

What the output shows

The three element addresses end in 0c, 10 and 14 in hex. In decimal that is 12, 16 and 20, so each step is exactly 4 bytes, which is the size of an int on this machine. The final line proves it by casting both addresses to char * first, so the subtraction counts raw bytes. (Subtracting addresses is a pointer topic that we cover properly later in the chapter; here it is only a measuring tool.) Your own addresses will differ, but the 4-byte gap will not, unless your platform has a different int size.

Neighbouring array elements
ElementValueAddress (hex, last digits)Distance from previous
readings[0]10…20cstart
readings[1]20…2104 bytes
readings[2]30…2144 bytes

What You Can and Cannot Take the Address Of

The address operator needs something that actually occupies memory. A variable does. An array element does. The result of an arithmetic expression, or the number 289 typed in the source, is a temporary value with no fixed home, so asking for its address makes no sense. C calls things that have a storage location lvalues, and the address operator demands an lvalue.

ExpressionValid?Reason
&countYesA named variable has storage
&table[2]YesAn array element has storage
&config.modeYesA struct member has storage
&289NoA constant has no storage location
&(a + b)NoThe sum is a temporary value
&register_var (declared with register)NoThe register keyword forbids it

Let the compiler show you. Here is a deliberately broken program:

int main(void)
{
    int a = 1, b = 2;
    int *p = &(a + b);
    int *q = &289;
    return 0;
}

Compiling it with GCC gives:

bad.c: In function 'main':
bad.c:4:14: error: lvalue required as unary '&' operand
    4 |     int *p = &(a + b);
      |              ^
bad.c:5:14: error: lvalue required as unary '&' operand
    5 |     int *q = &289;
      |              ^
Remember this error message. “lvalue required as unary ‘&’ operand” always means you tried to take the address of something that is not a stored object. It is one of the first pointer errors every student sees.

Why scanf Needs the Address Operator

You have used the address operator since your first input program without being told. When you write scanf("%d", &temperature);, the function receives the address of temperature, not its value. C passes arguments by value, so if you passed the plain variable, scanf would only get a copy and could never change your original. With the address, it knows exactly where to write the number it reads.

Why the & in scanf
Without &: scanf receives a copy of the value. The original stays unchanged.
temperature = 0 copy sent temperature still 0
With &: scanf receives the location. It writes the input straight into the variable.
&temperature sent scanf writes there temperature = 36

This same idea is the basis for returning more than one result from a function, and we build on it in later lectures. One exception worth knowing: when you read a string into a char array, you write the array name without &, because an array name already stands for the address of its first element. We will explain that fully when arrays and pointers meet.

Printing Addresses Correctly

Old textbooks print addresses with %u and say that this does not mean addresses are unsigned integers, only that no better format was handy. On modern systems there is a better format. Use %p and cast the address to (void *):

FormatCorrect?Problem
%uNoOn 64-bit systems an address does not fit in an unsigned int, so the value is cut off
%dNoSigned, and the same truncation problem
%luRiskyWorks on some platforms, not portable
%p with (void *)YesThe portable, standard way

An address is simply a whole number, but its width depends on the machine. That is why the standard gave us a dedicated format.

Address Operator in Embedded C Programming

Here is how this operator shows up in real c programming for embedded systems work:

  • Passing a buffer to a driver. A function such as uart_send(&frame, sizeof frame) needs the location of the data to transmit.
  • Reading sensors into variables. A driver call like sensor_read(&temperature) fills your variable directly, avoiding global state.
  • DMA setup. Controllers want the memory address of the source or destination buffer, which you obtain with & or an array name.
  • Struct fields. &config.baud lets you hand one field of a configuration structure to a helper function.

Safety rule for firmware

Never take the address of a local variable and keep it after the function returns. The local lives on the stack, and that space is reused by the next function call. The address becomes meaningless, and your firmware may crash or behave randomly. We revisit this in the pitfalls lecture.

Common Mistakes

MistakeWhat happensFix
Forgetting & in scanf for a numberWarning at best, crash or garbage at worstAlways & for non-array targets
Writing &(x + y)Compile error: lvalue requiredStore the sum in a variable first
Printing an address with %dTruncated value on 64-bitUse %p and cast to (void *)
Confusing &x with xWrong value used&x is the location, x is the content
Mixing up bitwise AND with the address operatorWrong behaviourBinary a & b is AND; unary &a is address-of

Two meanings of the same symbol

The symbol & also means bitwise AND when it sits between two operands. The compiler tells them apart from the position: with one operand on its right it is the address operator, with an operand on each side it is AND. You will use both constantly in embedded work, for example to mask a status register.

Best Practices

  • Always cast to (void *) and use %p when printing addresses.
  • Check the return value of scanf to confirm the input was read.
  • Do not store the address of a short-lived local variable for later use.
  • Compile with warnings on so a missing & in scanf is reported.

Key Takeaways

  • The address operator & gives the address of a variable or any stored object.
  • It needs an lvalue, so constants and expressions are not allowed.
  • Array elements have neighbouring addresses separated by the element size.
  • scanf needs & so it can write into your variable.
  • Use %p to print addresses portably.

Conclusion

You can now ask C where any variable lives. That is half of the pointer story. The other half is a place to keep the answer, which is what a pointer variable is. In the next lecture of this free C programming course we declare our first pointers and look at the notation that confuses so many beginners. Before moving on, try the demo again with a char array and confirm that the gap is 1 byte, and with a double array to see 8.

Frequently Asked Questions

What does the & operator do in C?

Placed before a variable it returns the address of that variable. It is called the address-of operator.

Why can’t I take the address of a constant?

A constant such as 289 is a value written in the code, not an object stored in memory, so there is no address to return. The compiler reports that an lvalue is required.

Why does scanf need & before the variable name?

C passes arguments by value. scanf must change your variable, so you give it the variable’s address instead of a copy.

Why do array strings in scanf not need &?

An array name already converts to the address of its first element, so adding & is unnecessary for reading into a char array.

How do I print an address in C?

Use printf("%p", (void *)&variable);. It is the portable way and works on both 32-bit and 64-bit systems.

Is the address operator used in embedded C programming?

Yes, constantly: passing buffers to drivers, filling variables from sensor functions and configuring DMA all rely on addresses.

Keep Going with the Free C Tutorial

Next: declare pointer variables, understand the asterisk notation and see why every pointer needs a base type.

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 *