PY
C

Python to C

10 lessons

Progress0%
1Variables & Types2Functions3Lists → Arrays4Memory Management5String Handling6Structs7Preprocessor8File I/O9Pointers and Manual Memory10Build System: Makefile
All Mirror Courses
PY
C
Structs
MirrorLesson 6 of 10
Lesson 6

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.

Mirror Card
PY
From Python:

In Python, you're familiar with c struct and typedef — grouping related data without classes.

C
In C:

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:

C
C 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:

PY
Python (What you know)
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.0
Mirror Card
PY
From Python:

You may be used to different syntax or behavior.

C
In C:

C structs are pure data — no methods, no inheritance, no encapsulation

Mirror Card
PY
From Python:

You may be used to different syntax or behavior.

C
In C:

typedef struct {} Name; avoids writing 'struct Name' every time

Mirror Card
PY
From Python:

You may be used to different syntax or behavior.

C
In C:

Struct members accessed with . (value) or -> (pointer)

Mirror Card
PY
From Python:

You may be used to different syntax or behavior.

C
In C:

Nested structs are stored by value inline — not by reference like Python

Mirror Card
PY
From Python:

You may be used to different syntax or behavior.

C
In C:

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.

PY
Python
@dataclass
class Point:
    x: float = 0.0
    y: float = 0.0
p = Point(1.0, 2.0)
C
C
typedef struct { float x, y; } Point;
Point p = { .x = 1.0f, .y = 2.0f };
// or: Point p = { 1.0f, 2.0f }; // positional

2. Pointer vs Value Access

Use . for direct struct access, -> when accessing via pointer. ptr->field is shorthand for (*ptr).field.

PY
Python
p.x
person.address.city
C
C
p.x              // direct
ptr->x           // via pointer
ptr->addr.city   // nested via pointer then direct

3. Passing Structs to Functions

Passing a struct to a function copies it (pass by value). To modify the original, pass a pointer.

PY
Python
def move(p: Point, dx, dy):
    p.x += dx  # modifies original (Python objects are refs)
C
C
// 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; }
Common Pitfall
In C, structs passed by value are fully copied. Large structs should be passed by pointer for efficiency.

4. Struct Arrays

Arrays of structs are stored contiguously in memory. Access elements with [i] and use . to access fields.

PY
Python
people = [Person("Alice",30), Person("Bob",25)]
C
C
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)
Common Pitfall
Don't assume C works exactly like Python. While the concepts may be similar, the syntax and behavior can differ significantly.

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
Rule of Thumb
The best way to learn is by doing. Try rewriting some of your Python code in C to practice these concepts.
PreviousNext