Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 7

Pointers: Value vs. Pointed-To Value

Recommended resources

Hello! Welcome to your seventh lesson.

In our previous lesson, we concluded our first module by untangling the const volatile combination, a concept directly applicable to your work with read-only hardware registers. We established that const and volatile are orthogonal keywords, addressing separate concerns of code contract and compiler optimization.

Today, we begin a new module: Pointers, const, and Core Operations. We'll start with the most fundamental concept of all, which is the cornerstone for every advanced pointer topic. While you use pointers daily, the goal here is to refine your ability to explain their mechanics with precision—a skill essential for interviews.

Our learning outcome is to explain the difference between a pointer's value (an address) and the value it points to. We will break this down using memory diagrams and code analysis to build an unshakeable mental model.

1. The Core of Pointers: Indirection

At the most basic level, every variable in C has two attributes:

  • Its value: The data it holds.
  • Its address: The location in memory where that value is stored.

Usually, we're only concerned with the value. If we have int var = 10;, we think of var as being 10.

A pointer introduces a layer of indirection. It's a special type of variable designed not to hold a data value directly, but to hold the address of another variable.

  • The address-of operator (&) is used to get the memory address of a variable. &var gives us the address where 10 is stored.
  • The dereference operator (*) is used to access the value at the address a pointer is holding.

Let's start with a foundational reading that explains this relationship.

Understanding Pointers vs References with Memory Diagrams

This article, 'Understanding Pointers vs References with Memory Diagrams', provides a clear, concise explanation of the relationship between values, addresses, and indirection. It's a great refresher to frame our thinking.

Please read the first two sections: 'Values, Addresses, and Indirection' and 'What a Pointer Is and How It Behaves'. Focus on how the author defines a pointer as a variable that stores an address, and how the * operator is used to follow that address.


2. Visualizing the Pointer in Memory

A clear mental model of memory is the key to mastering pointers. Let's visualize the concepts from the article.

Consider this simple code:

int a = 30;
int *ptr = &a;

Here's what this looks like in memory:

Pointer in C: Address vs. Value
This diagram illustrates the relationship between a variable `a` and a pointer `ptr`. The variable `a` is at memory address `0x123` and holds the value `30`. The pointer `ptr` is at a different memory address, `0x345`, and its own value is `0x123`—the address of `a`.

From this diagram, we can make the crucial distinctions an interviewer is looking for:

  • a: The value is 30.
  • &a: The address of a is 0x123.
  • ptr: The value of the pointer ptr is 0x123. Printing ptr would show this address.
  • *ptr: The value at the address ptr points to. The pointer holds 0x123, and the value at that address is 30.
  • &ptr: The address of the pointer variable itself is 0x345. The pointer, being a variable, also has its own location in memory.

This second diagram expands on the idea, showing how different data types, including a pointer, are laid out in memory. Notice how the ptrSum variable's content is the address of the sum variable.

Memory Address and Content Representation
This image shows various variables in memory. The pointer `ptrSum`, located at address `8012`, contains the value `8000`, which is the starting address of the `sum` variable. This visually separates the pointer's own address, its value (an address), and the value it points to.

To solidify this with code, let's turn to another resource that demonstrates how to print these different values.

Pointers in C - GeeksforGeeks

The article 'Pointers in C' from GeeksforGeeks provides simple, executable code examples that explicitly show the difference between printing a pointer's value and the value it's pointing to.

Read the sections explaining pointer declaration, initialization, and dereferencing. Pay close attention to the code snippets. Note the use of the %p format specifier, which is the correct, portable way to print addresses.


3. Code Analysis: A Practical Walkthrough

Now let's trace the flow of pointers through a function call. This is a common pattern and a great way to test your understanding. Given your familiarity with C++, you'll recognize this as the C-style equivalent of passing by reference.

Analyze the following code. Before running it, predict what each printf statement will output.




#include <stdio.h>

// This function takes a pointer to an integer as its argument.
void modify_value(int *p_num) {
    printf("\n--- Inside modify_value ---\n");
    printf("Value of the pointer p_num (the address it holds): %p\n", (void*)p_num);
    printf("Value at the address p_num points to (*p_num):    %d\n", *p_num);

    // Now, we dereference the pointer and change the value AT THAT ADDRESS.
    *p_num = 250;

    printf("New value at the address p_num points to (*p_num): %d\n", *p_num);
    printf("--- Exiting modify_value ---\n\n");
}

int main() {
    int my_var = 42;

    printf("--- In main (before call) ---\n");
    printf("Value of my_var:    %d\n", my_var);
    printf("Address of my_var:  %p\n", (void*)&my_var);

    // We pass the ADDRESS of my_var to the function.
    modify_value(&my_var);

    printf("--- In main (after call) ---\n");
    printf("Value of my_var:    %d\n", my_var);

    return 0;
}

Analysis Breakdown:

  1. In main, before the call:

    • my_var is initialized to 42.
    • &my_var will print the memory address of my_var (e.g., 0x7ffc...).
  2. The function call modify_value(&my_var):

    • The value being passed to the function is the address of my_var.
    • The function parameter p_num is a new local variable on the stack, but its value is initialized with the address of my_var. So, p_num now "points to" my_var.
  3. Inside modify_value:

    • printfing p_num will show the same address as &my_var from main. This confirms the pointer's value is the address we passed in.
    • printfing *p_num will show 42, the value at that address.
    • The line *p_num = 250; is the critical step. It says: "Go to the address stored in p_num and change the value there to 250." This directly modifies my_var in the main function's scope.
    • The final printf inside the function will confirm that *p_num is now 250.
  4. In main, after the call:

    • When we print my_var again, its value will be 250. The change made via the pointer in modify_value persists because we weren't operating on a copy of the value, but on the original variable's memory location.

This example cleanly separates the pointer p_num (which holds an address) from the data *p_num (which is the integer at that address).


Conclusion

Mastering this distinction is non-negotiable for C programming. It is the foundation upon which pointer arithmetic, dynamic memory, data structures, and the complex callback mechanisms you use in AUTOSAR are built.

Key Takeaways:

  • A pointer's value is always a memory address. It answers the question, "Where is the data?"
  • The value a pointer points to is the data located at that memory address. It is accessed using the dereference operator (*).
  • The address-of (&) and dereference (*) operators are complements. For a variable var, *(&var) evaluates to var.
  • Passing an address to a function allows that function to modify the original variable in the caller's scope, a technique known as "pass-by-pointer."

In our next lesson, we will build directly on this foundation. Now that we understand a pointer's value is an address (which is essentially an integer), we will explore pointer arithmetic: how to perform mathematical operations like addition and subtraction on pointers and why the pointer's data type is crucial for these calculations.