Defining Structures
Struct declarations, members, initialization, the dot operator, and typedef for cleaner names.
Values That Belong Together
A student has a roll number and marks; a point has an x and a y; a date has three parts. Arrays collect many values of one kind; the structure collects different kinds that belong to one thing. It is C's mechanism for defining your own types, the foundation of every record-keeping program, and, later, of every dynamic data structure.
Declaring the Shape, Then the Variables
The struct Point { ... }; declaration defines a type, no memory yet: two int members, x and y, in every value of the type. Point is the tag, and here sits the rule that separates C from its descendants: the type's name is struct Point, both words. Bare Point is not a type in C (C++ made the tag alone work, and that habit leaking back is the classic cross-language error). Variables then declare like any other: struct Point origin, with brace initializers filling members in declaration order, constants in this dialect, and the chapter 7 rule carrying over: too-short lists zero the rest.
The dot operator selects a member: origin.x is an int, usable anywhere an int is, read, assigned, passed, scanned into as &origin.x. It binds tighter than every arithmetic and relational operator, so origin.x + 1 and a.x > b.x need no parentheses whatsoever: the member is selected first, always.
The Shorthand Exam Code Uses
Variables can be declared in the definition itself, in the space between the closing brace and the semicolon:
struct Point {
int x;
int y;
} origin = {0, 0}, corner = {40, 25};
One statement that defines the type and two variables of it, initializers included. Old papers lean on this form constantly, so read it fluently: whatever follows the closing brace is a variable list, never a second tag name. Dropping the tag is legal as well, struct { int x; int y; } screen;, and it is the one variant to avoid, because the type then has no name at all: nothing later can declare another variable of it, take it as a parameter, or return it.
One rule no shorthand bends: members cannot be initialized inside the template. struct Point { int x = 0; }; is not C in any dialect, and gcc rejects the line with expected ':', ',', ';', '}' or '__attribute__' before '=' token, the compiler saying it would accept a bit-field width or the end of the member declaration but never a value. The template describes layout; values arrive when a variable is declared.
Structs Assign (Arrays Never Did)
second = first copies every member at once, a genuine whole-value assignment that arrays never had, and the copy is independent: changing second.x leaves first alone. The same courtesy does not extend to ==: comparing structs needs member-by-member tests, because the language defines no struct equality (and memcmp is wrong, padding bytes, coming below, hold indeterminate values).
typedef: Naming the Type Once
Writing struct Point everywhere is honest but heavy. typedef creates a synonym:
typedef struct Point {
int x;
int y;
} Point;
After this, Point alone is a complete type name: Point origin = {0, 0};. The pattern reads as "define this struct type and also call it Point", tag and typedef name conventionally matching. Exams ask both spellings; real codebases split on taste; this course uses the plain struct form first and typedef where repetition earns it. What matters is knowing the two-word rule underneath: typedef is sugar over it, not a replacement.
Size and Padding
sizeof(struct Point) is 8 on this platform, two 4-byte ints, but the general rule surprises: a struct's size may exceed the sum of its members. The compiler inserts padding between members so each sits at an address its type prefers (alignment), and a char followed by an int typically costs 8 bytes, not 5. Two consequences worth owning now: never assume a struct's layout byte-for-byte, and always take sizes from sizeof, a rule that becomes load-bearing when structs meet malloc and binary files in later chapters.
Nesting
Members can themselves be structs, and the dots chain:
struct Line {
struct Point start;
struct Point end;
};
line.start.x = 0;
Read left to right: from line, take start, take x. Records containing records, a date inside an employee inside a department, model real data directly, and the chained dot is the whole access story.
Key Takeaways
struct Tag { members };defines a type; the type's name isstruct Tag, both words, and bare tags are a C++ habit that does not compile here.- The dot operator selects members and outranks every arithmetic and relational operator, so
a.x > b.xneeds no parentheses; brace initializers fill in order and zero the remainder. - Variables may be declared with the definition (
struct Point { ... } origin, corner;); omitting the tag works but leaves the type unnameable, and members can never be initialized inside the template. - Structs assign whole (
b = acopies all members, independently), but do not compare:==is undefined for structs, and equality is member-by-member. typedef struct Tag { ... } Name;makesNamea standalone synonym.- Padding means a struct's size can exceed its members' sum: take sizes from
sizeof, never by adding fields. - Nested structs chain dots:
line.start.x.
How did you find this lesson?
Your rating helps us improve the content.
Create an account to track your progress and access interactive exercises. Already have one? Sign in.
Defining Structures - Quiz
Test your understanding of the lesson.
Practice Exercises
Two Points, One Distance
Define struct Point with int x and y, read two points, and print their Manhattan distance: the absolute x difference plus the absolute y difference. The conditional operator supplies the absolute values.
Lesson Discussion
Share your thoughts and questions
No comments yet. Be the first to share your thoughts!