Structures, Unions and Enums · Lesson 29 of 35
Arrays of Structures and Pointers to Structures
Real programs work with many records: all the students in a class, all the products in a shop. An array of structures stores them, and pointers to structures let functions read and update records efficiently. The "student record" or "employee database" program built here is a standard lab and mini-project exercise.
In this lesson
- Arrays of structures
- Pointers to structures and the arrow operator
- Passing structs to functions by value vs by pointer
- Searching and sorting records with qsort
An array of structures
#include <stdio.h>
typedef struct {
int roll;
char name[20];
int marks[3];
} Student;
int main(void) {
Student cls[] = {
{1, "Asha", {78, 85, 92}},
{2, "Ravi", {65, 70, 58}},
{3, "Meera", {90, 88, 95}},
};
int n = sizeof cls / sizeof cls[0];
int top = 0, best_total = -1;
for (int i = 0; i < n; i++) {
int total = cls[i].marks[0] + cls[i].marks[1] + cls[i].marks[2];
printf("%d %-6s total %3d average %.1f\n", cls[i].roll, cls[i].name, total, total / 3.0);
if (total > best_total) { best_total = total; top = i; }
}
printf("Topper: %s with %d\n", cls[top].name, best_total);
return 0;
}
1 Asha total 255 average 85.0 2 Ravi total 193 average 64.3 3 Meera total 273 average 91.0 Topper: Meera with 273
Pointers to structures and the arrow operator
#include <stdio.h>
typedef struct {
char name[20];
double balance;
} Account;
int main(void) {
Account acc = {"Asha", 5000.0};
Account *p = &acc;
printf("%s has %.2f\n", (*p).name, (*p).balance); // dereference, then dot
p->balance += 1500; // arrow: the same, shorter
printf("%s has %.2f\n", p->name, p->balance);
return 0;
}
Asha has 5000.00 Asha has 6500.00
p->member means (*p).member. The brackets in the long form are required, because . binds tighter than *.
Passing structures to functions
#include <stdio.h>
#include <stdbool.h>
typedef struct {
char name[20];
double balance;
} Account;
void print_account(const Account *a) { // read-only: const pointer, no copy
printf("%-6s %10.2f\n", a->name, a->balance);
}
bool withdraw(Account *a, double amount) { // modifies the caller's struct
if (amount <= 0 || amount > a->balance) return false;
a->balance -= amount;
return true;
}
Account with_interest(Account a, double rate) { // by value: works on a copy, returns a new struct
a.balance *= 1 + rate / 100;
return a;
}
int main(void) {
Account acc = {"Ravi", 2000.0};
print_account(&acc);
printf("withdraw 500: %s\n", withdraw(&acc, 500) ? "ok" : "refused");
printf("withdraw 9000: %s\n", withdraw(&acc, 9000) ? "ok" : "refused");
Account next_year = with_interest(acc, 7.5);
print_account(&acc);
print_account(&next_year);
return 0;
}
Ravi 2000.00 withdraw 500: ok withdraw 9000: refused Ravi 1500.00 Ravi 1612.50
| Pass by | Copies the struct? | Can modify the original? | Use for |
|---|---|---|---|
value: f(Account a) | yes | no | small structs, returning a modified copy |
pointer: f(Account *a) | no | yes | updates; large structs |
const pointer: f(const Account *a) | no | no | read-only access to large structs |
Sorting and searching records
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int id;
char name[20];
double salary;
} Employee;
int by_salary_desc(const void *a, const void *b) {
const Employee *x = a, *y = b;
return (y->salary > x->salary) - (y->salary < x->salary);
}
int by_name(const void *a, const void *b) {
return strcmp(((const Employee *)a)->name, ((const Employee *)b)->name);
}
Employee *find_by_id(Employee *list, int n, int id) {
for (int i = 0; i < n; i++) if (list[i].id == id) return &list[i];
return NULL;
}
int main(void) {
Employee staff[] = {{11, "Kiran", 72000}, {12, "Asha", 95000}, {13, "Ravi", 61000}, {14, "Dev", 88000}};
int n = sizeof staff / sizeof staff[0];
qsort(staff, n, sizeof staff[0], by_salary_desc);
printf("By salary:\n");
for (int i = 0; i < n; i++) printf(" %-6s %.0f\n", staff[i].name, staff[i].salary);
qsort(staff, n, sizeof staff[0], by_name);
printf("By name:");
for (int i = 0; i < n; i++) printf(" %s", staff[i].name);
printf("\n");
Employee *e = find_by_id(staff, n, 13);
if (e != NULL) {
e->salary *= 1.10; // raise via the pointer
printf("%s now earns %.0f\n", e->name, e->salary);
}
return 0;
}
By salary: Asha 95000 Dev 88000 Kiran 72000 Ravi 61000 By name: Asha Dev Kiran Ravi Ravi now earns 67100
Practice
Try it yourself
Write
void apply_discount(Product *p, int percent)and use it on every product in an array.Show solution
#include <stdio.h> typedef struct { char name[20]; double price; } Product; void apply_discount(Product *p, int percent) { p->price -= p->price * percent / 100.0; } int main(void) { Product items[] = {{"Mouse", 600}, {"Keyboard", 2500}}; for (int i = 0; i < 2; i++) { apply_discount(&items[i], 10); printf("%s: %.2f\n", items[i].name, items[i].price); } return 0; }Mouse: 540.00 Keyboard: 2250.00
Quick check
What does p->x mean?
(*p).x – member x of the struct p points to.
Why pass large structs by pointer?
To avoid copying them and (without const) to let the function modify the original.
How do you sort an array of structs by a member?
qsort with a comparator that casts its void pointers to the struct type and compares that member.
Summary
- Arrays of structs hold records; index then dot:
cls[i].name. - Use the arrow operator with pointers; pass by const pointer to read, by pointer to modify.
- qsort with a struct comparator sorts records by any member.
Finished this lesson?
Mark it complete to track your progress, then carry on with the next lesson.