Classes in C with struct: solved modular design exercise

  3 minutes

If you are searching for classes in C with struct, this guide shows a practical object-like pattern in plain C: struct + functions + separated files.

The goal is to simulate encapsulation and clean responsibilities without native OOP features.

Design a Cuenta module that:

  1. defines an entity with owner name and balance,
  2. exposes functions to create, deposit, withdraw, and print state,
  3. separates interface (cuenta.h) and implementation (cuenta.c),
  4. uses main.c to test the full workflow.

cuenta.h

#ifndef CUENTA_H
#define CUENTA_H

typedef struct {
    char titular[64];
    double saldo;
} Cuenta;

Cuenta cuenta_crear(const char *titular, double saldo_inicial);
int cuenta_depositar(Cuenta *c, double importe);
int cuenta_retirar(Cuenta *c, double importe);
void cuenta_imprimir(const Cuenta *c);

#endif

cuenta.c

#include "cuenta.h"
#include <stdio.h>
#include <string.h>

Cuenta cuenta_crear(const char *titular, double saldo_inicial) {
    Cuenta c;
    strncpy(c.titular, titular, sizeof(c.titular) - 1);
    c.titular[sizeof(c.titular) - 1] = '\0';
    c.saldo = (saldo_inicial >= 0.0) ? saldo_inicial : 0.0;
    return c;
}

int cuenta_depositar(Cuenta *c, double importe) {
    if (!c || importe <= 0.0) return 0;
    c->saldo += importe;
    return 1;
}

int cuenta_retirar(Cuenta *c, double importe) {
    if (!c || importe <= 0.0 || importe > c->saldo) return 0;
    c->saldo -= importe;
    return 1;
}

void cuenta_imprimir(const Cuenta *c) {
    if (!c) return;
    printf("Owner: %s | Balance: %.2f\n", c->titular, c->saldo);
}

main.c

#include "cuenta.h"
#include <stdio.h>

int main(void) {
    Cuenta c = cuenta_crear("Rodrigo", 1000.0);
    cuenta_imprimir(&c);

    cuenta_depositar(&c, 250.0);
    cuenta_retirar(&c, 400.0);
    cuenta_imprimir(&c);

    if (!cuenta_retirar(&c, 2000.0)) {
        printf("Withdrawal rejected due to insufficient funds.\n");
    }

    return 0;
}

Build:

gcc -Wall -Wextra -std=c11 main.c cuenta.c -o cuenta_demo
Owner: Rodrigo | Balance: 1000.00
Owner: Rodrigo | Balance: 850.00
Withdrawal rejected due to insufficient funds.
  • Putting all business logic in main.c and losing modularity.
  • Skipping pointer and amount validation.
  • Copying strings without bounds checks.
  • Assuming this is full OOP: C still has no native inheritance or methods.

This pattern helps you:

  • design maintainable C modules,
  • separate public API from implementation details,
  • build cleaner foundations for larger projects.

It is a practical way to get object-like structure while staying in idiomatic C.

If you want a complete path with progressive difficulty:

Not natively. You can simulate parts of it with struct, function APIs, and pointers, but there is no built-in inheritance or method system.

Because it improves maintainability, reuse, and clarity of the module public contract.

Both. In interviews it shows structured thinking, and in production it prevents monolithic code.