Defining structs, accessing members, combining with arrays, typedef, and enum.
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.