What are Declaring Pointer Variables in C – C Programming Course Online

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 3

Declaring Pointer Variables in C

A pointer is a variable that stores an address. Learn the declaration syntax, the base type, the size of a pointer and the one-asterisk trap that catches almost every beginner. Free C tutorial for embedded systems.

*
Marks a declaration as a pointer
4 / 8
Pointer bytes on 32 / 64-bit
1
Base type per pointer

Finally, the moment this free C programming course has been building towards: declaring pointer variables in C. You already know that every variable has an address and that the address operator reveals it. A pointer is simply a variable designed to hold such an address.

This lecture of our free C tutorial explains the syntax, the idea of a base type, and the size of a pointer. If you are learning c programming for embedded systems, this is the notation you will read in every driver, HAL and register header you ever open.

What You Will Learn

By the end of this lecture you can:

  • Explain what a pointer variable is in one sentence.
  • Write correct declarations for pointers to int, float, char and double.
  • Define the base type of a pointer and say why it exists.
  • Measure the size of a pointer with sizeof and explain why it does not depend on the base type.
  • Avoid the declaration trap where only the first name becomes a pointer.

Prerequisites

You need the two previous lectures of this chapter: memory as numbered bytes, and the address operator &. You should also be comfortable declaring ordinary variables of type int, float and char. Nothing else is needed. This free embedded C course introduces every new idea in small steps.

What Is a Pointer Variable

A pointer is a variable whose value is a memory address. Like any variable it has a name, it has a type, it is stored somewhere in memory, and it occupies a certain number of bytes. What makes it special is the meaning of what it holds: an ordinary int holds a number, a pointer holds the location of something else.

The word “points” is a good picture. A pointer stores the address of a target, so we say it points to that target. Follow the address and you arrive at the target.

Ordinary variable vs pointer variable
Ordinary variablePointer variable
What it holdsA data value, such as 42An address of another object
Has its own address?YesYes
Occupies memory?Yes, size by typeYes, size of an address
Must be declared?YesYes
A pointer pointing at a variable
The pointer ptr stores the address of the variable level.
ptr holds the address of level points to level = 87

Declaring Pointer Variables in C

The general declaration is:

data_type *pointer_name;

The pointer_name must be a valid C identifier, following the same rules as any variable name. The asterisk * in front of the name tells the compiler that this variable is a pointer. The data_type is the type of the thing the pointer is allowed to point to, which we call the base type (some books say referenced type).

int    *ip;      /* pointer to int    */
float  *fp;      /* pointer to float  */
char   *cp;      /* pointer to char   */
double *dp;      /* pointer to double */

Here ip is meant to point to int variables. We say its type is “pointer to int”, written int *, and its base type is int. Likewise fp is a float *, and so on.

Spacing styles

All of these are the same declaration to the compiler: int *p;, int* p; and int * p;. Embedded style guides usually write int *p; with the star next to the name, and the next section explains exactly why that style is safer.

The Base Type of a Pointer

If every pointer just stores an address, why does the declaration need a data type at all? The type is not about the pointer itself. It is about what lives at the other end. When you later follow the pointer to read the target, the compiler must know how many bytes to read and how to interpret them. Reading four bytes as an int gives a very different answer from reading eight bytes as a double, even from the same address.

Same address, different base type, different reading
Pointer declared asBytes read when followedInterpreted as
char *1A character or a byte
short *2A 16-bit integer
int *4 (typical)An integer
float *4A floating-point number
double *8A double-precision number

The base type also controls pointer arithmetic: adding 1 to an int * moves it forward by the size of an int, not by one byte. We cover that in a later lecture, but it is the second big reason the base type must be declared.

Rule to remember

A pointer remembers where the target is (the address) and what kind of target to expect (the base type). Both pieces of information are needed to use it safely.

How Much Memory Does a Pointer Use

A pointer is a variable, so the compiler reserves bytes for it. Because every pointer stores an address and nothing else, all object pointers on a given platform have the same size, regardless of the base type. The size equals the width of an address on that machine. Older books state that a pointer is 2 bytes, which was right for 16-bit systems. Today it varies:

PlatformTypical pointer size
8-bit AVR microcontroller2 bytes
32-bit ARM Cortex-M microcontroller4 bytes
64-bit Linux or Windows PC8 bytes

Let us measure it on your own machine. The program also demonstrates the trap we meet in the next section.

#include <stdio.h>

int main(void)
{
    int    *ip;
    float  *fp;
    char   *cp;
    double *dp;

    printf("sizeof(int *)    = %zu\n", sizeof ip);
    printf("sizeof(float *)  = %zu\n", sizeof fp);
    printf("sizeof(char *)   = %zu\n", sizeof cp);
    printf("sizeof(double *) = %zu\n", sizeof dp);

    int *a, b;
    char *s, t, u;
    printf("a is %zu bytes, b is %zu bytes\n", sizeof a, sizeof b);
    printf("s is %zu bytes, t is %zu byte, u is %zu byte\n", sizeof s, sizeof t, sizeof u);
    return 0;
}

Build and run

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

Expected output on a 64-bit Linux PC

sizeof(int *)    = 8
sizeof(float *)  = 8
sizeof(char *)   = 8
sizeof(double *) = 8
a is 8 bytes, b is 4 bytes
s is 8 bytes, t is 1 byte, u is 1 byte

All four pointer types are the same size, 8 bytes here. Cross-compile the same file for a Cortex-M and you would see 4. The last two lines reveal something important, so let us look at them closely.

The One-Asterisk Trap

You can declare ordinary variables and pointers in one statement, but you need to know how the asterisk binds. Look at the line int *a, b;. Many beginners read it as “two pointers to int”. The output proves otherwise: a is 8 bytes (a pointer) and b is 4 bytes (a plain int).

The reason is that the asterisk belongs to the name that follows it, not to the type. The declaration really says “*a is an int, and b is an int”. Each name needs its own star if you want it to be a pointer.

Who becomes a pointer?
DeclarationFirst nameSecond nameThird name
int *a, b;a: pointer to intb: plain int–
int *a, *b;a: pointer to intb: pointer to int–
char *s, t, u;s: pointer to chart: plain charu: plain char
Safest habit for firmware code: declare one pointer per line. It removes the trap completely and it also makes code reviews easier. Writing int* a, b; is especially misleading because the spacing suggests that both are pointers when only a is.

You can still mix pointers and ordinary variables in one declaration when you really want to, for example char *cursor, first, last;. Just be sure you meant it.

Pointer Declarations in Embedded C Programming

The declarations in this lecture are the same ones you will see in real embedded C programming. A few patterns to recognise:

  • uint8_t *rx_buf; a pointer to a receive buffer of raw bytes.
  • const char *msg; a pointer to read-only text, commonly stored in flash.
  • volatile uint32_t *reg; a pointer to a hardware register. The volatile keyword tells the compiler the value can change on its own, so every access must really happen.
  • struct uart_cfg *cfg; a pointer to a configuration structure passed to a driver function.

Why 32-bit matters on a microcontroller

On a 32-bit Cortex-M each pointer costs 4 bytes of RAM. A table of 100 pointers uses 400 bytes, which is a significant slice of a chip with 8 KB of RAM. Knowing that a pointer is just a stored address helps you judge such costs before they bite.

const and volatile in pointer declarations

Two keywords often appear next to the star. We study them in detail in later chapters, but you should be able to read them today:

DeclarationMeaning
const int *p;p can point elsewhere, but you may not modify the target through p
int *const p;p always points to the same place, but the target can be modified
volatile uint32_t *p;the target may change outside program control, as with hardware registers

Common Mistakes

MistakeConsequenceFix
Writing int *a, b; and expecting two pointersb is just an intWrite int *a, *b; or one declaration per line
Assuming a pointer is 2 bytesWrong size calculationsUse sizeof
Thinking char * and int * differ in sizeConfused about memory useThey are the same size, only the base type differs
Declaring a pointer and using it immediatelyIt holds a garbage addressAlways give it a valid address first (next lecture)
Forgetting that a pointer needs its own storageMemory budget surprisesCount the bytes of every pointer

Best Practices

  • Declare one pointer per line, with the star next to the name.
  • Choose names that tell the reader what is pointed to, such as rx_buf or cfg, rather than p1.
  • Use const whenever a function only reads through a pointer.
  • Use volatile for pointers to hardware registers.
  • Print sizeof of a pointer on your target when memory is tight.

Performance and security note

A pointer that has been declared but not yet set is called an uninitialised or wild pointer. It holds whatever leftover bits were in that memory, so following it can read secrets or corrupt data. Many security vulnerabilities start this way. The next lecture shows how to initialise pointers safely.

Key Takeaways

  • A pointer variable stores a memory address.
  • Declare it with data_type *name;. The data type is the base type.
  • The base type tells the compiler how to read the target and how far to step during arithmetic.
  • All pointers on a platform have the same size, set by the address width.
  • In int *a, b; only a is a pointer.

Conclusion

You now know how to create a pointer variable and what its type means. At this point the pointers declared above contain nothing useful: they have names and sizes but no targets. In the next lecture of this free C programming course we give pointers real addresses, copy them between variables, and meet the special NULL value. As practice, compile the size program for another target if you have a cross-compiler, and write down how each pointer size compares with the 64-bit result.

Frequently Asked Questions

What is a pointer in C?

A pointer is a variable that stores the memory address of another object. It points to that object by holding its location.

How do you declare a pointer in C?

Write the base type, then an asterisk, then the name: int *ptr; declares a pointer to int.

Why does a pointer need a data type?

The type tells the compiler how many bytes to read at the target and how to interpret them, and it sets the step size of pointer arithmetic.

Is a char pointer smaller than an int pointer?

No. Every object pointer on a platform has the same size, because each one only stores an address. Only the base type differs.

What is the size of a pointer in C?

It equals the address width of the platform: about 2 bytes on 8-bit AVR, 4 on 32-bit ARM Cortex-M, and 8 on a 64-bit PC. Check with sizeof.

In int *a, b; is b a pointer?

No. Only a is a pointer. The star applies to the name next to it, so b is a plain int.

Do I need pointers for embedded C programming?

Yes. Hardware registers, buffers and driver interfaces all use pointers, so they are essential in embedded C programming.

Continue the Free Embedded C Course

Next: assign real addresses to your pointers, copy one pointer into another, and learn why NULL matters.

Need Help or More Information?

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

1 Comment

Leave a Reply

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