Structs
C struct and typedef — grouping related data without classes
Introduction
In this lesson, you'll learn about structs in C. Coming from Python, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.
In Python, you're familiar with c struct and typedef — grouping related data without classes.
C has its own approach to c struct and typedef — grouping related data without classes, which we'll explore step by step.
The C Way
Let's see how C handles this concept. Here's a typical example:
#include <stdio.h>
#include <string.h>
// Struct definition
struct Point {
float x;
float y;
};
// typedef for cleaner syntax (avoid "struct Point" every time)
typedef struct {
char name[50];
int age;
} Person;
// Nested struct
typedef struct {
char street[100];
char city[50];
} Address;
typedef struct {
char name[50];
int age;
Address address; // nested by value
} Employee;
int main(void) {
// Initialization
struct Point p = { 1.0f, 2.0f };
printf("%.1f %.1f\n", p.x, p.y); // 1.0 2.0
// Designated initializers (C99)
Person alice = { .name = "Alice", .age = 30 };
strcpy(alice.name, "Alice");
// Nested
Employee emp = {
.name = "Bob",
.age = 25,
.address = { .street = "123 Main", .city = "NYC" }
};
printf("%s\n", emp.address.city); // NYC
// Pointer to struct — use -> for member access
Person *ptr = &alice;
printf("%s %d\n", ptr->name, ptr->age);
// Pass by pointer (like Python's pass-by-reference effect)
return 0;
}
// Function taking struct pointer
void birthday(Person *p) {
p->age += 1; // modifies original
}Comparing to Python
Here's how you might have written similar code in Python:
from dataclasses import dataclass
# Simple class/dataclass for grouped data
@dataclass
class Point:
x: float
y: float
@dataclass
class Person:
name: str
age: int
address: "Address" # nested
@dataclass
class Address:
street: str
city: str
p = Point(1.0, 2.0)
print(p.x, p.y) # 1.0 2.0
person = Person("Alice", 30, Address("123 Main", "NYC"))
print(person.address.city) # NYC
# Pointer-like: pass by reference via mutation
def move(point: Point, dx: float, dy: float) -> None:
point.x += dx
point.y += dy
move(p, 1, 2)
print(p.x, p.y) # 2.0 4.0You may be used to different syntax or behavior.
C structs are pure data — no methods, no inheritance, no encapsulation
You may be used to different syntax or behavior.
typedef struct {} Name; avoids writing 'struct Name' every time
You may be used to different syntax or behavior.
Struct members accessed with . (value) or -> (pointer)
You may be used to different syntax or behavior.
Nested structs are stored by value inline — not by reference like Python
You may be used to different syntax or behavior.
To modify a struct in a function, pass a pointer and use ->
Step-by-Step Breakdown
1. Define and Initialize Structs
C99 designated initializers (.field = value) make struct initialization readable. Members not specified are zero-initialized.
@dataclass
class Point:
x: float = 0.0
y: float = 0.0
p = Point(1.0, 2.0)typedef struct { float x, y; } Point;
Point p = { .x = 1.0f, .y = 2.0f };
// or: Point p = { 1.0f, 2.0f }; // positional2. Pointer vs Value Access
Use . for direct struct access, -> when accessing via pointer. ptr->field is shorthand for (*ptr).field.
p.x
person.address.cityp.x // direct
ptr->x // via pointer
ptr->addr.city // nested via pointer then direct3. Passing Structs to Functions
Passing a struct to a function copies it (pass by value). To modify the original, pass a pointer.
def move(p: Point, dx, dy):
p.x += dx # modifies original (Python objects are refs)// By value — copy; original unchanged
void printP(Point p) { printf("%.1f", p.x); }
// By pointer — modifies original
void move(Point *p, float dx) { p->x += dx; }4. Struct Arrays
Arrays of structs are stored contiguously in memory. Access elements with [i] and use . to access fields.
people = [Person("Alice",30), Person("Bob",25)]Person people[2] = {
{ .name="Alice", .age=30 },
{ .name="Bob", .age=25 },
};
printf("%s\n", people[0].name); // Alice
people[1].age += 1;Common Mistakes
When coming from Python, developers often make these mistakes:
- C structs are pure data — no methods, no inheritance, no encapsulation
- typedef struct {} Name; avoids writing 'struct Name' every time
- Struct members accessed with . (value) or -> (pointer)
Key Takeaways
- typedef struct {} Name; for clean type names without repeating 'struct'
- C99 designated initializers (.field = value) make struct init readable
- . for direct access; -> when using a pointer (ptr->field = (*ptr).field)
- Pass struct pointer to modify original; pass by value for read-only or small structs