A struct is like a custom form β you design the fields, C fills them in.
Designing Your Own Data Type
Imagine you're building a student database. Each student has a name, an age, and a GPA. You could juggle three separate arrays β one for names, one for ages, one for GPAs β but that's like storing a person's ID, photo, and address in three different filing cabinets. Messy.
A struct lets you bundle related data into a single package. Think of it as designing a custom form: you pick the fields, and C lets you stamp out as many copies as you need.
Defining and Using a Struct
#include <stdio.h>
#include <string.h>
struct Student{
char name[50];
int age;
float gpa;
};
int main(){
struct Student alice;
strcpy(alice.name,"Alice");
alice.age=20;
alice.gpa=3.85;
printf("Name: %s\n", alice.name);
printf("Age: %d\n", alice.age);
printf("GPA: %.2f\n", alice.gpa);
return0;
}
Output
Name: Alice
Age: 20
GPA: 3.85
typedef β The Shorthand
Typing struct Student everywhere gets old fast. typedef lets you create an alias so you can just write Student instead. It's like giving your form a short name for the label maker.
typedef Makes Life Easier
#include <stdio.h>
#include <string.h>
typedef struct {
char name[50];
int age;
float gpa;
}Student;
int main(){
// No need to write "struct Student" anymore!
Student bob;
strcpy(bob.name,"Bob");
bob.age=22;
bob.gpa=3.42;
printf("%s is %d years old with a %.2f GPA\n",
bob.name, bob.age, bob.gpa);
return0;
}
Output
Bob is 22 years old with a 3.42 GPA
Dot (.) vs Arrow (->)
When you have a struct variable, use the dot operator to access fields: alice.name. But when you have a pointer to a struct, use the arrow operator: ptr->name.
The arrow is just shorthand for (*ptr).name β dereferencing the pointer first, then accessing the field. But the arrow is much cleaner.
Pointer to Struct with Arrow Operator
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char name[50];
int age;
}Person;
voidbirthday(Person*p){
p->age++;// Arrow operator for pointer-to-struct
printf("Happy birthday, %s! You're now %d.\n",
p->name, p->age);
}
int main(){
Person john;
strcpy(john.name,"John");
john.age=29;
printf("Before: %s is %d\n", john.name, john.age);
birthday(&john);// Pass pointer to avoid copying
printf("After: %s is %d\n", john.name, john.age);
return0;
}
Output
Before: John is 29
Happy birthday, John! You're now 30.
After: John is 30
Note: When you pass a struct to a function, C copies the ENTIRE struct β every byte of it. For a struct with a 1000-char array inside, that's 1000+ bytes copied on every call. For large structs, always pass a pointer instead.
Nested Structs
Structs can contain other structs β like a form that has a sub-section. An Address struct inside a Person struct keeps things organized.
Nested Structs
#include <stdio.h>
#include <string.h>
typedef struct {
char street[100];
char city[50];
int zip;
}Address;
typedef struct {
char name[50];
Address home;// Struct inside a struct
}Person;
int main(){
Person p;
strcpy(p.name,"Carol");
strcpy(p.home.street,"123 Main St");
strcpy(p.home.city,"Springfield");
p.home.zip=62704;
printf("%s lives at %s, %s %d\n",
p.name, p.home.street,
p.home.city, p.home.zip);
return0;
}
Output
Carol lives at 123 Main St, Springfield 62704
Array of Structs
Need a class roster? An inventory list? Just make an array of structs. Each element is a complete record β like a row in a spreadsheet.
Array of Structs
#include <stdio.h>
#include <string.h>
typedef struct {
char name[50];
int score;
}Player;
int main(){
Player leaderboard[3];
strcpy(leaderboard[0].name,"Alice");
leaderboard[0].score=950;
strcpy(leaderboard[1].name,"Bob");
leaderboard[1].score=870;
strcpy(leaderboard[2].name,"Carol");
leaderboard[2].score=920;
printf("=== Leaderboard ===\n");
for(int i =0; i <3; i++){
printf("%d. %-10s %d pts\n",
i +1, leaderboard[i].name,
leaderboard[i].score);
}
return0;
}
Output
=== Leaderboard ===
1. Alice 950 pts
2. Bob 870 pts
3. Carol 920 pts
Note: Structs in C don't have methods (functions inside them) like classes in C++ or Java. If you want a function that operates on a struct, pass the struct (or a pointer to it) as a parameter.