π‘ Tip: Rule of thumb: -> through a pointer, . on an object. Covers 90% of cases.
What is a struct?
Up to now we have declared int, double, and char variables individually. But real-world data often comes as a set of related values β for example, name, age, and height of a person.
A struct lets you bundle several variables of different types into a single new type.
Without a struct...
char name[20]; int age; double height;
Add another person and you need name1, name2, ... β variables explode.
With a struct
struct Person { char name[20]; int age; double height; };
Everything is bundled into one Person.
Defining and Using a struct
Structs are used in two steps: (1) define the type (the blueprint), then (2) declare a variable (make an instance).
// (1) Define the struct type (blueprint)
struct Student {
char name[20];
int score;
};
// (2) Declare variables and use them
struct Student s1;
strcpy(s1.name, "Tanaka"); // access with dot (.)
s1.score = 85;
// You can also initialize at declaration
struct Student s2 = {"Sato", 92};
Members are accessed with the "dot operator (.)":s1.score means "the score field inside s1".
Struct Memory Layout
Members of a struct are laid out in memory in declaration order, consecutively.
Memory layout of struct Student s1;
name[20] takes 20 bytes, score takes 4 bytes β one Student uses at least 24 bytes (padding may apply).
Arrays of Structs
Making an array of a struct lets you manage many records with the same shape. This is where structs really shine.
// Print every student's score
for(int i = 0; i < 3; i++){
printf("%s: %d points\n", class[i].name, class[i].score);
}
You combine the array index with the dot operator, as in class[i].score. It reads naturally as "the i-th student's score."
Passing a struct to a Function
Structs can be passed by value (copied), but for large structs the copy cost is high, so passing by pointer is common.
// Pass by value (the struct is copied)
void printStudent(struct Student s){
printf("%s: %d points\n", s.name, s.score);
}
// Pass by pointer (refers to the original)
void addBonus(struct Student *sp, int bonus){
sp->score += bonus; // equivalent to (*sp).score
}
addBonus(&s1, 5); // adds 5 points to s1.score
The arrow operator (->) is the special syntax to access members through a pointer. sp->score is the same as (*sp).score.
typedef β Giving a Type an Alias
With typedef you can give a type a clearer alias. It is especially handy with structs.
Basic usage
// An alias for unsigned inttypedefunsigned int uint;
uint score = 100; // same as unsigned int score = 100;
Structs and typedef (important)
// Without typedef β you need "struct" every timestructPoint { int x, y; };
structPoint p1 = {3, 7}; // "struct" required// With typedef β you can drop "struct"typedefstruct { int x, y; } Point;
Point p1 = {3, 7}; // cleaner
In practice, typedef'd structs are the norm. Your code is shorter and more readable.
Enum (enum) β A Group of Named Constants
With enum you can name and group related integer constants β a great way to avoid magic numbers.
enumColor { RED, GREEN, BLUE }; // RED=0, GREEN=1, BLUE=2enumColor c = GREEN;
printf("%d\n", c); // 1
Specifying values
enumMonth {
JAN = 1, FEB, MAR, APR, MAY, JUN,
JUL, AUG, SEP, OCT, NOV, DEC
}; // FEB=2, MAR=3, ... DEC=12 (auto-incremented)
enum + switch
enumDirection { UP, DOWN, LEFT, RIGHT };
enumDirection dir = UP;
switch (dir) {
case UP: printf("Up\n"); break;
case DOWN: printf("Down\n"); break;
case LEFT: printf("Left\n"); break;
case RIGHT: printf("Right\n"); break;
}
vs #define: You can also write #define RED 0, but an enum is treated as a type, so the compiler can help with type checks.
Method
Type check
Scope
Debugger display
#define RED 0
None
Whole file
Number only
enum { RED }
Yes
Controllable
Shown by name
Try It Yourself β Structs
Store three students in an array of structs and compute the average score.
struct.c
Output
Click Run...
π‘ Try these ideas too
Make an array of structs for multiple students
Pass a struct pointer to a function and mutate its members