C Structures
A structure in C is a user-defined type that groups related values under one name. Instead of passing separate variables for a book title, page count, and price, you can define one struct that represents a book. Structures matter because they let C programs model real data clearly while still keeping the low-level memory control C is known for.
Overview: How Structures Work
A struct defines a new compound layout. Each field, also called a member, has its own type and name. A structure variable stores all of those members together in one object, in the order declared, with possible padding bytes inserted by the compiler for alignment.
For example, a structure containing an int, a double, and a character array is not just three unrelated variables. It is one object whose memory contains space for each member. When you write book.pages, the compiler calculates where the pages member lives inside the book object and reads or writes that part.
Structures are value types in C. Assigning one structure variable to another copies the entire structure object, member by member as raw stored values. Passing a structure to a function also copies it unless you pass a pointer. This is different from many higher-level languages where object variables often behave like references by default.
Structures can contain arrays, other structures, pointers, integers, floating-point values, and more. They cannot contain a member of their own exact type directly, because that would require infinite size, but they can contain a pointer to their own type. That pattern is used for linked lists and trees.
Syntax
struct Book {
char title[40];
int pages;
double price;
};
| Part | Meaning |
|---|---|
struct |
The keyword that begins a structure type definition. |
Book |
The structure tag. The full type name is struct Book. |
| Members | The fields stored inside each structure object. |
| Semicolon | Required after the closing brace because this is a declaration. |
You can declare variables after the definition with struct Book first;. You can initialize members in order with { "C Programming", 320, 39.95 }, or use designated initializers such as { .pages = 320, .price = 39.95 }. Designated initializers are clearer when a structure has many fields.
Examples
A Simple Structure Variable
#include <stdio.h>
struct Book {
char title[40];
int pages;
double price;
};
int main(void) {
struct Book guide = {"C Programming", 320, 39.95};
printf("Title: %s
", guide.title);
printf("Pages: %d
", guide.pages);
printf("Price: %.2f
", guide.price);
return 0;
}
Output:
Title: C Programming
Pages: 320
Price: 39.95
This program defines a structure type named struct Book, creates one variable named guide, and initializes its three members. The dot operator, ., accesses a member through a structure object.
An Array of Structures
#include <stdio.h>
struct Student {
char name[20];
int score;
};
int main(void) {
struct Student class_list[] = {
{"Ada", 95},
{"Ken", 88},
{"Mina", 91}
};
int count = (int)(sizeof class_list / sizeof class_list[0]);
int total = 0;
for (int i = 0; i < count; i++) {
printf("%s: %d
", class_list[i].name, class_list[i].score);
total += class_list[i].score;
}
printf("Average: %.2f
", (double)total / count);
return 0;
}
Output:
Ada: 95
Ken: 88
Mina: 91
Average: 91.33
An array of structures is useful when every item has the same shape. Here, each element stores a student’s name and score. The expression class_list[i].score first selects the array element, then selects the member inside that element.
Nested Structures and typedef
#include <stdio.h>
typedef struct {
char name[30];
char street[40];
} Address;
typedef struct {
char item[30];
int quantity;
int unit_cents;
Address ship_to;
} Order;
int main(void) {
Order order = {
.item = "USB Cable",
.quantity = 3,
.unit_cents = 799,
.ship_to = {"Noor Patel", "17 Oak Road"}
};
printf("Order 1042
");
printf("Ship to: %s, %s
", order.ship_to.name, order.ship_to.street);
printf("Item: %s x %d
", order.item, order.quantity);
printf("Total cents: %d
", order.quantity * order.unit_cents);
return 0;
}
Output:
Order 1042
Ship to: Noor Patel, 17 Oak Road
Item: USB Cable x 3
Total cents: 2397
The typedef declarations let the program use Address and Order instead of writing struct Address style names. The Order structure contains another structure as a member, so the program accesses nested data with two dot operations: order.ship_to.name.
How It Works Step by Step
When the compiler sees a structure definition, it records the member list and decides the offset of each member. An offset is the number of bytes from the beginning of the structure object to that member. If a member needs a certain alignment, the compiler may insert padding bytes before it or at the end of the structure.
When a variable is created, storage is reserved for the whole structure. A local structure variable usually lives on the stack, just like other local variables. A dynamically allocated structure lives on the heap if you obtain it with malloc. A global or static structure has static storage duration.
Member access is compile-time arithmetic. In guide.pages, the compiler knows the offset of pages inside struct Book. In ptr->pages, the arrow operator first follows the pointer and then accesses the member. These two expressions are equivalent: ptr->pages and (*ptr).pages. Parentheses are required in the second form because . binds more tightly than *.
Structure assignment copies the stored member values. If a structure contains a character array, the array contents are copied as part of the structure. If a structure contains a pointer, the pointer value is copied, not the memory it points to. That distinction is one of the most important structure rules in C.
Common Mistakes
Trying to Assign to an Array Member
If a structure member is a character array, you can initialize it when the structure is created, but you cannot later assign a new string with book.title = "New Title";. Arrays are not assignable in C. Use strcpy, snprintf, or direct character operations, making sure the destination has enough space.
Forgetting That Pointer Members Are Shared
#include <stdio.h>
struct Label {
char *text;
};
int main(void) {
char word[] = "red";
struct Label first = {word};
struct Label second = first;
second.text[0] = 'R';
printf("%s %s
", first.text, second.text);
return 0;
}
Output:
Red Red
The structure assignment copies the pointer value, so both structures point at the same character array. If you need independent text, store an array inside the structure or allocate and copy separate memory for each object.
Using the Wrong Member Operator
Use . when you have a structure object, such as student.score. Use -> when you have a pointer to a structure, such as student_ptr->score. Writing student_ptr.score is a type error because the pointer itself does not contain the members.
Best Practices
- Group data that changes together. A structure should represent one coherent concept, not a random bag of variables.
- Prefer clear member names such as
unit_centsinstead of vague names such asxorvalue. - Use designated initializers for larger structures so the code does not depend on remembering field order.
- Pass large structures to functions by pointer to avoid expensive copies. Use
constpointers when the function should only read the structure. - Be careful with pointer members. Decide who owns the pointed-to memory and document that decision in the surrounding code.
- Do not assume a structure has no padding. Use members by name, not by manually guessing byte positions.
- Keep public structure definitions stable if other files depend on them. Changing member order or type can break binary compatibility.
Practice Exercises
- Define a
struct Rectanglewithwidthandheight. Create one variable and print its area. - Create an array of three
struct Productvalues with a name and price in cents. Print the most expensive product. - Write a function
void discount(Order *order, int percent)that reduces the unit price inside an order structure. Hint: use the arrow operator.
Summary
- A C structure groups related members into one user-defined type.
- Structure variables store their members together, with possible padding for alignment.
- The dot operator accesses members through an object; the arrow operator accesses members through a pointer.
- Structure assignment copies stored values, but pointer members still point to the same external memory.
- Arrays of structures, nested structures, and
typedefnames make larger C programs easier to organize.
