Skip to content

Intermediate · Structs, unions, enums and files · topic 32 of 60 · 25 min

Pointers to structs and the arrow operator

Explanation

p->field is a shortcut for (*p).field and is how you reach members through a pointer. Passing a pointer to a struct avoids copying and lets the function change the caller's struct; use const when it only reads. Structs are often allocated on the heap, can contain other structs, and can contain a pointer to their own type, which is how linked lists are built.

The arrow operator

c
typedef struct { char name[30]; long balance_paise; } Account;

Account acc = {"Asha", 500000};
Account *p = &acc;
(*p).balance_paise += 10000;    /* brackets needed: . binds tighter than * */
p->balance_paise += 10000;      /* the same thing, the usual way to write it */
printf("%s: %ld\n", p->name, p->balance_paise);   /* Asha: 520000 */

Passing structs by pointer

c
void deposit(Account *a, long paise) {          /* changes the caller's account */
    if (paise > 0) a->balance_paise += paise;
}

void print_account(const Account *a) {          /* read-only, no copy */
    printf("%-10s Rs %.2f\n", a->name, a->balance_paise / 100.0);
}

deposit(&acc, 25000);
print_account(&acc);

A struct with a 200-byte array would be copied on every by-value call. A pointer is 8 bytes. Mark it const when the function should not modify the struct; the compiler then rejects accidental writes.

Structs on the heap

c
Account *open_account(const char *name) {
    Account *a = malloc(sizeof *a);
    if (!a) return NULL;
    snprintf(a->name, sizeof a->name, "%s", name);
    a->balance_paise = 0;
    return a;
}
Account *a = open_account("Ravi");
if (a) { deposit(a, 100000); print_account(a); free(a); }

Nested structs

c
typedef struct { char city[20]; char pin[7]; } Address;
typedef struct { char name[30]; Address home; } Customer;

Customer c = { .name = "Meena", .home = { .city = "Kochi", .pin = "682001" } };
Customer *pc = &c;
printf("%s, %s\n", c.home.city, pc->home.pin);   /* dot for the inner struct value */

Self-referential structs

c
typedef struct Node {
    int value;
    struct Node *next;         /* a pointer to another Node (a struct cannot contain itself, but can point to one) */
} Node;

Node third  = {30, NULL};
Node second = {20, &third};
Node first  = {10, &second};
for (Node *n = &first; n != NULL; n = n->next) printf("%d ", n->value);   /* 10 20 30 */

first ──► [10 | ●] ──► [20 | ●] ──► [30 | NULL]
This is a linked list; module 10 builds one properly with malloc.
Careful: p->field on a NULL or dangling p crashes (or worse, silently corrupts memory). Check pointers returned by functions like malloc or a lookup before using ->, and do not keep pointers to stack structs after their function returns.
Think of it like this: The arrow is like reaching a house through its address written on a slip: p->balance means "go to the house on the slip, then open the balance cupboard". The dot is for when you are already standing inside the house.
Tip: Typical C library style: functions that create a struct return a pointer (or fill one passed in), and every other function takes a pointer to it as its first parameter: account_deposit(Account *a, …).

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Pointers to structs and the arrow operator · 1/6

Pointers to structs

In this lesson you will use pointers to structs.

Prefer a video by a teacher? Find free videos on “c pointer to struct arrow operator linked list node” on YouTube ↗

In real life: Updating a vehicle's FASTag balance

A toll-plaza simulator keeps each vehicle's tag as a struct. The function that charges a toll receives a pointer so it can reduce the caller's balance, and returns an error code if the balance is too low, without copying the struct.

c
typedef struct { char reg[12]; long balance_paise; } Tag;

int charge_toll(Tag *t, long toll_paise) {
    if (!t || toll_paise <= 0) return -1;
    if (t->balance_paise < toll_paise) return -2;   /* insufficient balance */
    t->balance_paise -= toll_paise;
    return 0;
}

Practice (0/3 done)

Task 1 · Question

Given Account *p = &acc;, which is NOT equivalent to p->name?

Task 2 · Code · Javascript

The same idea in JavaScript, where objects are always passed by reference (like a C pointer to a struct): write chargeToll(tag, toll) that returns -1 for a missing tag or a toll <= 0, -2 if tag.balance < toll, and otherwise subtracts the toll from tag.balance (changing the caller's object) and returns 0.

Task 3 · Practice

Write an Account struct and functions Account *account_new(const char *name), int account_withdraw(Account *a, long paise) (returning an error code for insufficient funds), void account_print(const Account *a) and void account_free(Account *a). Create two accounts on the heap, transfer money between them with a function that takes two pointers, print both and free them.

Quick quiz

Question 1

1.p->x is the same as…

Question 2

2.Why pass a large struct by pointer?

Question 3

3.Can a struct contain a member of its own struct type (not a pointer)?

Question 4

4.What happens with p->x when p is NULL?

Read more (free)

Before this, learn

This topic builds on these. If something here feels new, open them first.

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

p->x is the same as…

Answer: (*p).x

Dereference, then select the member.

Why pass a large struct by pointer?

Answer: To avoid copying it, and to allow changes

Use const when only reading.

Can a struct contain a member of its own struct type (not a pointer)?

Answer: No: it would be infinitely large; it can contain a pointer to its type

Self-reference must be through a pointer.

What happens with p->x when p is NULL?

Answer: Undefined behaviour (usually a crash)

Always check pointers before ->.

Which operator accesses a member of a struct variable?Related

Answer: .

-> is for pointers to structs.

From Structs

How does Go reuse code from another struct type?Related

Answer: Embedding (composition)

Embedding promotes the inner type's fields and methods to the outer type.

From Structs and methods

What is a struct?Related

Answer: A custom type that groups named fields

Structs group related values under one named type.

From Structs: your own data types

When is a struct a good choice?Related

Answer: For small, immutable, value-like data such as a point or money

Small, immutable values are the classic struct use.

From Structs, value types and reference types

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 3 more topics in “Structs, unions, enums and files” before its exam: Unions, enums and memory layout, Reading and writing text files, Binary files and records.
  2. Module 7 exam: Structs, unions, enums and files · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, The preprocessor, multi-file programs and make. 60 topics left in the course before the final exam.

← Previous: Structs