A structured lesson workspace with readable content, hands-on examples, and a clean path to completion.
A struct groups related variables under a single name. An int, a char array, a double, a pointer: bundle them together and you have a record, an entity, a thing. C does not have classes. It does not have objects. It has structs and functions that operate on them. Every data structure in C, from linked lists to hash tables to database rows, starts with a struct definition. This is the foundation of data modeling in the language.
#include <stdio.h>#include <string.h>struct Point {double x;double y;};struct Player {char name[32];int health;double speed;struct Point position;};int main(void) {struct Point p1 = {3.0, 4.0};printf("p1: (%.1f, %.1f)\n", p1.x, p1.y);struct Player hero;strncpy(hero.name, "Alex", sizeof(hero.name) - 1);hero.name[sizeof(hero.name) - 1] = '\0';hero.health = 100;hero.speed = 5.5;hero.position.x = 10.0;hero.position.y = 20.0;printf("%s: HP=%d, speed=%.1f, pos=(%.1f, %.1f)\n",hero.name, hero.health, hero.speed,hero.position.x, hero.position.y);return 0;}
The dot operator accesses members. Nested structs use chained dots: hero.position.x. The initializer {3.0, 4.0} sets members in declaration order. C99 designated initializers let you name them: {.x = 3.0, .y = 4.0}. We cover those in a later lesson. The struct keyword is required in C when referring to the type: struct Point, not just Point. The typedef trick removes that requirement, as we covered in the typedef lesson.
#include <stdio.h>#include <math.h>struct Point {double x;double y;};double distance(struct Point a, struct Point b) {double dx = a.x - b.x;double dy = a.y - b.y;return sqrt(dx * dx + dy * dy);}void translate(struct Point *p, double dx, double dy) {p->x += dx;p->y += dy;}int main(void) {struct Point a = {0.0, 0.0};struct Point b = {3.0, 4.0};printf("Distance: %.2f\n", distance(a, b));translate(&a, 1.0, 1.0);printf("After translate: (%.1f, %.1f)\n", a.x, a.y);return 0;}
distance takes structs by value. It receives copies. The originals are untouched. This is fine for small structs. For large structs, the copy overhead matters, and you pass a const pointer instead. translate takes a pointer because it modifies the original. The -> operator accesses members through a pointer. p->x is shorthand for (*p).x. Use -> with pointers, . with values.
Structs are the atoms of data modeling in C. Every record, every node, every state object is a struct. The functions that operate on them take them by value for reads and by pointer for writes. This pattern scales from two-field points to hundred-field database rows. Next: the arrow operator in depth, and why it exists.
Finish the lesson once you have worked through the material. This awards ★ 30 XP.