Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Accessing Struct Members: Dot and Arrow Operators

Welcome to the next lesson in our C programming journey. In the previous lesson, we introduced structs as a way to bundle related data together, creating our own custom types. We practiced accessing the members of a struct variable directly using the dot (.) operator.

Today, we will build directly on that foundation by combining structs with one of C's most powerful features: pointers. This is a critical step that unlocks the ability to manage data more flexibly and dynamically. The central question for this lesson is: how do we access the members of a struct when we don't have the struct variable itself, but only a pointer to it?

By the end of this lesson, you will master the two fundamental ways to access struct members: the familiar dot (.) operator for struct variables, and the new arrow (->) operator for pointers to structs.

1. Accessing Members: A Quick Recap

Let's start with what we already know. When you have a struct variable, you use the dot operator to access its members.




#include <stdio.h>

// Using typedef to create a 'Point' alias for our struct
typedef struct {
    int x;
    int y;
} Point;

int main() {
    // Create a Point variable directly
    Point p1 = {10, 20};

    // Access its members using the dot (.) operator
    printf("Point p1 is at (%d, %d)\n", p1.x, p1.y);

    return 0;
}

The following video quickly demonstrates this familiar concept before introducing pointers.

Arrow Operator For Pointers To Structs | C Programming Tutorial

Watch this first segment of "Arrow Operator For Pointers To Structs" from Portfolio Courses for a quick review of the dot operator.

Focus on the part from dot notation. This will serve as a solid starting point before we introduce pointers into the mix.

2. Pointers to Structs

Now, let's introduce a pointer. Just as we can have a pointer to an int or a char, we can have a pointer to a struct. This pointer doesn't hold the struct itself, but rather the memory address where the struct is stored.

int main() {
    Point p1 = {10, 20};
    
    // Declare a pointer that can hold the address of a Point struct
    Point *p1_ptr;

    // Assign the address of p1 to the pointer
    p1_ptr = &p1; 
    
    // Now, p1_ptr "points to" p1.
    // How do we get to p1's x and y members via p1_ptr?
    
    return 0;
}

This raises a new challenge. We can't write p1_ptr.x because p1_ptr is not a struct variable; it's a pointer. We need a way to first follow the pointer to the struct it points to, and then access the member.

3. Accessing Members Through a Pointer

There are two ways to solve this problem in C. One is a bit more verbose but follows logically from what we know, and the other is a convenient shorthand provided by the language.

The "Hard Way": Dereference and Dot

Since p1_ptr holds the address of p1, we can get the actual p1 struct by dereferencing the pointer: *p1_ptr. Because *p1_ptr is now effectively the same as the p1 variable itself, we can then use the familiar dot operator:

(*p1_ptr).x

The parentheses are mandatory. This is due to operator precedence in C: the dot operator (.) has a higher precedence than the dereference operator (*). Without the parentheses, the compiler would try to evaluate p1_ptr.x first, which is an error.

The "Easy Way": The Arrow Operator (->)

Writing (*ptr).member is clumsy and easy to forget the parentheses. Because this operation is so common, C provides a dedicated arrow operator (->) as a cleaner, more readable alternative.

The expression p1_ptr->x is exactly equivalent to (*p1_ptr).x.

The rule is simple and fundamental:

  • If you have a struct variable, use the dot operator (.).
  • If you have a pointer to a struct, use the arrow operator (->).

The following video explains both of these methods, showing how the arrow operator simplifies the code.

Arrow Operator For Pointers To Structs | C Programming Tutorial

Let's continue with the "Arrow Operator" video to see how to use pointers with structs.

First, watch how the arrow operator works with a pointer to an existing struct variable in the section from arrow notation. Then, skip to the explanation, where the presenter clarifies that the arrow operator is simply shorthand for the dereference-and-dot syntax (*ptr).member.

This image from the tutorial clearly contrasts the two ways of accessing a struct member through a pointer: the cleaner arrow operator `p3->x` and the equivalent, but more verbose, dereference/dot syntax `(*p3).x`.

4. Struct Pointers with Dynamic Memory

The true power of struct pointers becomes apparent when we work with memory that is allocated at runtime. As you've seen, the malloc() function returns a pointer to a block of memory on the heap. When we use malloc() to create space for a struct, we get back a pointer, making the arrow operator the natural and necessary tool for the job.

Arrow Operator For Pointers To Structs | C Programming Tutorial

Watch this final clip from the "Arrow Operator" video to see how this applies to dynamically allocated structs.

Focus on the section from dynamic allocation. Notice how malloc returns a pointer, and the arrow operator is immediately used to access the members of the newly created struct.

This is a brief preview of a topic we will explore in detail in the next lesson. For now, the key takeaway is that when you allocate a struct with malloc, you get a pointer, so you must use the arrow (->) operator.

5. Summary: Dot vs. Arrow

To solidify your understanding, please read the following article from Sanfoundry. It provides a concise summary and a clear comparison table that is excellent for review.

Structure - Dot vs. Arrow Notation in C

This article provides a clear, side-by-side comparison of the dot and arrow operators.

Read the sections titled "What is the Dot (.) Operator?", "What is the Arrow (->) Operator?", and pay special attention to the table under "Key Differences Between Dot and Arrow Operators in C". This table is a perfect summary of when to use each operator.

Your Turn: A Practical Exercise

Let's apply these concepts. The goal of this exercise is to use both operators and see how a pointer can be used to modify a struct's data indirectly.

  1. Create a new C file.
  2. Define a struct named User with the following members:
    • char username[50]
    • int id
    • float activity_score
  3. Use typedef to create a User alias for your struct.
  4. In your main function:
    • Declare a User variable named user1.
    • Using the dot (.) operator, initialize user1's members (e.g., strcpy(user1.username, "coder123");, user1.id = 101;, user1.activity_score = 95.5;).
    • Declare a pointer to a User named user_ptr.
    • Make user_ptr point to user1.
    • Now, using the arrow (->) operator with user_ptr, change the activity_score to a new value (e.g., 88.0).
    • Finally, print all three members of the original user1 variable (using the dot operator) to confirm that its activity_score was successfully changed via the pointer.

This exercise will confirm your understanding of how and when to use both operators.

Conclusion

In this lesson, we bridged the gap between structs and pointers. You've learned the essential distinction between the dot (.) and arrow (->) operators, a fundamental concept in C programming.

Key Takeaways:

  • Use the dot (.) operator to access members when you have a struct variable itself.
  • Use the arrow (->) operator to access members when you have a pointer to a struct.
  • The arrow operator (->) is just convenient syntactic sugar for dereferencing a pointer and then using the dot operator ((*ptr).member). The parentheses in the latter form are crucial due to operator precedence.
  • Pointers to structs are essential for working with dynamically allocated memory from malloc().

Preview of the Next Lesson:
We've had a small taste of malloc(). In our next lesson, we will dive deep into how memory is organized into the stack and the heap. Understanding this distinction is crucial for mastering dynamic memory management in C and avoiding common errors like memory leaks.

Can't find a good explanation? Sign up and we'll make it for you

Sign up