Recommended resources
The freely available resources this lesson will direct you to.
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
structvariable, 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.

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.
- Create a new C file.
- Define a
structnamedUserwith the following members:char username[50]int idfloat activity_score
- Use
typedefto create aUseralias for yourstruct. - In your
mainfunction:- Declare a
Uservariable nameduser1. - Using the dot (
.) operator, initializeuser1's members (e.g.,strcpy(user1.username, "coder123");,user1.id = 101;,user1.activity_score = 95.5;). - Declare a pointer to a
Usernameduser_ptr. - Make
user_ptrpoint touser1. - Now, using the arrow (
->) operator withuser_ptr, change theactivity_scoreto a new value (e.g.,88.0). - Finally, print all three members of the original
user1variable (using the dot operator) to confirm that itsactivity_scorewas successfully changed via the pointer.
- Declare a
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 astructvariable itself. - Use the arrow (
->) operator to access members when you have a pointer to astruct. - 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
structsare essential for working with dynamically allocated memory frommalloc().
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.