Structs and Unions

Code Properties

  • Language: C

Overview

C allows creating custom composite data types using struct and union. Structures group related variables together, while unions allow storing different data types in the same memory location.

Code

Basic Struct

#include <stdio.h>
#include <string.h>
 
struct Person {
    char name[50];
    int age;
    float height;
};
 
int main(void) {
    // declaration and initialization
    struct Person person1;
    strcpy(person1.name, "Alice");
    person1.age = 30;
    person1.height = 5.6f;
    
    // designated initializer (C99+)
    struct Person person2 = {
        .name = "Bob",
        .age = 25,
        .height = 5.9f
    };
    
    // positional initializer
    struct Person person3 = {"Charlie", 35, 6.0f};
    
    printf("%s is %d years old\n", person1.name, person1.age);
    printf("%s is %.1f feet tall\n", person2.name, person2.height);
    
    return 0;
}

Typedef with Structs

#include <stdio.h>
 
// typedef for cleaner usage
typedef struct {
    double x;
    double y;
} Point;
 
typedef struct {
    Point center;
    double radius;
} Circle;
 
double distance(Point a, Point b) {
    double dx = b.x - a.x;
    double dy = b.y - a.y;
    return sqrt(dx * dx + dy * dy);
}
 
int main(void) {
    Point p1 = {0.0, 0.0};
    Point p2 = {3.0, 4.0};
    
    Circle c = {
        .center = {5.0, 5.0},
        .radius = 2.5
    };
    
    printf("Point: (%.1f, %.1f)\n", p1.x, p1.y);
    printf("Circle center: (%.1f, %.1f), radius: %.1f\n", 
           c.center.x, c.center.y, c.radius);
    
    return 0;
}

Pointers to Structs

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
typedef struct {
    char title[100];
    char author[50];
    int year;
    double price;
} Book;
 
void print_book(const Book *book) {
    // arrow operator for pointer access
    printf("Title: %s\n", book->title);
    printf("Author: %s\n", book->author);
    printf("Year: %d\n", book->year);
    printf("Price: $%.2f\n", book->price);
}
 
int main(void) {
    // stack allocation
    Book book1 = {"The C Programming Language", "K&R", 1988, 59.99};
    print_book(&book1);
    
    printf("\n");
    
    // heap allocation
    Book *book2 = malloc(sizeof(Book));
    if (book2 == NULL) return EXIT_FAILURE;
    
    strcpy(book2->title, "Expert C Programming");
    strcpy(book2->author, "Peter van der Linden");
    book2->year = 1994;
    book2->price = 49.99;
    
    print_book(book2);
    
    free(book2);
    return EXIT_SUCCESS;
}

Arrays of Structs

#include <stdio.h>
 
typedef struct {
    int id;
    char name[30];
    double score;
} Student;
 
void print_students(const Student students[], int count) {
    printf("%-5s %-20s %s\n", "ID", "Name", "Score");
    printf("%-5s %-20s %s\n", "---", "----", "-----");
    
    for (int i = 0; i < count; i++) {
        printf("%-5d %-20s %.2f\n", 
               students[i].id, 
               students[i].name, 
               students[i].score);
    }
}
 
int main(void) {
    Student class[] = {
        {101, "Alice", 92.5},
        {102, "Bob", 88.0},
        {103, "Charlie", 95.5},
        {104, "Diana", 91.0}
    };
    
    int count = sizeof(class) / sizeof(class[0]);
    print_students(class, count);
    
    return 0;
}

Nested Structs

#include <stdio.h>
 
typedef struct {
    int day;
    int month;
    int year;
} Date;
 
typedef struct {
    char street[100];
    char city[50];
    char state[3];
    char zip[10];
} Address;
 
typedef struct {
    char name[50];
    Date birth_date;
    Address address;
} Employee;
 
int main(void) {
    Employee emp = {
        .name = "John Doe",
        .birth_date = {15, 6, 1990},
        .address = {
            .street = "123 Main St",
            .city = "Springfield",
            .state = "IL",
            .zip = "62701"
        }
    };
    
    printf("Name: %s\n", emp.name);
    printf("DOB: %02d/%02d/%d\n", 
           emp.birth_date.month, 
           emp.birth_date.day, 
           emp.birth_date.year);
    printf("Address: %s, %s, %s %s\n",
           emp.address.street,
           emp.address.city,
           emp.address.state,
           emp.address.zip);
    
    return 0;
}

Unions

#include <stdio.h>
 
// union shares memory among members
typedef union {
    int i;
    float f;
    char str[20];
} Data;
 
int main(void) {
    Data data;
    
    printf("Size of union: %zu bytes\n", sizeof(Data));
    
    // only one member valid at a time
    data.i = 42;
    printf("data.i = %d\n", data.i);
    
    data.f = 3.14f;
    printf("data.f = %f\n", data.f);
    // data.i is now garbage
    
    return 0;
}

Tagged Union (Discriminated Union)

#include <stdio.h>
#include <string.h>
 
typedef enum {
    TYPE_INT,
    TYPE_FLOAT,
    TYPE_STRING
} ValueType;
 
typedef struct {
    ValueType type;
    union {
        int int_val;
        float float_val;
        char string_val[50];
    } data;
} Value;
 
void print_value(const Value *v) {
    switch (v->type) {
        case TYPE_INT:
            printf("Integer: %d\n", v->data.int_val);
            break;
        case TYPE_FLOAT:
            printf("Float: %f\n", v->data.float_val);
            break;
        case TYPE_STRING:
            printf("String: %s\n", v->data.string_val);
            break;
    }
}
 
int main(void) {
    Value values[3];
    
    values[0].type = TYPE_INT;
    values[0].data.int_val = 42;
    
    values[1].type = TYPE_FLOAT;
    values[1].data.float_val = 3.14f;
    
    values[2].type = TYPE_STRING;
    strcpy(values[2].data.string_val, "Hello");
    
    for (int i = 0; i < 3; i++) {
        print_value(&values[i]);
    }
    
    return 0;
}

Bit Fields

#include <stdio.h>
 
typedef struct {
    unsigned int active : 1;    // 1 bit
    unsigned int ready : 1;     // 1 bit
    unsigned int error : 1;     // 1 bit
    unsigned int mode : 3;      // 3 bits (values 0-7)
    unsigned int priority : 4;  // 4 bits (values 0-15)
} Flags;
 
int main(void) {
    Flags status = {0};
    
    printf("Size of Flags: %zu bytes\n", sizeof(Flags));
    
    status.active = 1;
    status.ready = 1;
    status.mode = 5;
    status.priority = 10;
    
    printf("Active: %u\n", status.active);
    printf("Mode: %u\n", status.mode);
    printf("Priority: %u\n", status.priority);
    
    return 0;
}

Details

Struct vs Union Memory Layout

TypeMemoryUsage
structSum of all member sizes (plus padding)Store multiple values simultaneously
unionSize of largest memberStore one value at a time, save memory

Struct Padding and Alignment

#include <stdio.h>
 
// may have padding between members
struct Padded {
    char a;     // 1 byte + 3 padding
    int b;      // 4 bytes
    char c;     // 1 byte + 3 padding
};              // total: 12 bytes
 
// reordered for better packing
struct Packed {
    int b;      // 4 bytes
    char a;     // 1 byte
    char c;     // 1 byte + 2 padding
};              // total: 8 bytes
 
int main(void) {
    printf("Padded: %zu bytes\n", sizeof(struct Padded));
    printf("Packed: %zu bytes\n", sizeof(struct Packed));
    return 0;
}

Appendix

Note created on 2025-12-31 and last modified on 2025-12-31.

See Also


(c) No Clocks, LLC | 2025