Structures, Unions & Bit Fields

নিজের type বানানো — composite data

~35 min Advanced 18 practice problems Live code

1. Your Own Types

একটি struct সম্পর্কযুক্ত কয়েকটি field-কে একটি ইউনিটে গ্রুপ করে। এটি প্রতিটি non-trivial data structure-এর ভিত্তি।

student.c
#include <stdio.h>

struct Student {
    char   name[50];
    int    id;
    double gpa;
};

int main(void) {
    struct Student s = {"Arif", 201, 3.85};
    printf("%s (ID %d): %.2f\n", s.name, s.id, s.gpa);
    return 0;
}

2. typedef for Readability

point.c
#include <stdio.h>

typedef struct { double x, y; } Point;

double mag2(Point p) { return p.x * p.x + p.y * p.y; }

int main(void) {
    Point p = { 3.0, 4.0 };
    printf("|p|^2 = %.2f\n", mag2(p));
    return 0;
}
typedef করলে আর struct Student লিখতে হয় না — শুধু Student। Code পড়া সহজ হয়।

3. Access — Dot vs Arrow

Point p;
p.x = 5;                // direct access
Point *pp = &p;
pp->x = 5;               // through pointer — same as (*pp).x

4. Nested Structs and Arrays of Structs

nested.c
#include <stdio.h>

typedef struct { double x, y; } Point;
typedef struct { Point start, end; } Line;

int main(void) {
    Line l = { {0, 0}, {3, 4} };
    printf("start=(%.1f, %.1f) end=(%.1f, %.1f)\n",
           l.start.x, l.start.y, l.end.x, l.end.y);

    Point poly[3] = { {0,0}, {1,0}, {0,1} };
    for (int i = 0; i < 3; i++)
        printf("vertex %d = (%.1f, %.1f)\n", i, poly[i].x, poly[i].y);
    return 0;
}

5. Struct Padding & Alignment

Compiler প্রতিটি field-কে "natural alignment"-এ রাখে, তাই struct-এর ভেতর ফাঁক (padding) থাকে।

c1 byte pad3 bytes padpad padpad i (int, 4 bytes)total = 8 bytes, not 5 struct { char c; int i; }; Figure 18.1 — Padding-এর কারণে struct {char; int;} সাধারণত 8 byte।
padding.c
#include <stdio.h>

struct A { char c; int  i; };   // often 8 bytes
struct B { int  i; char c; };   // also 8 bytes (trailing padding)
struct C { int  i; char a; char b; char c; char d; };  // 8 bytes

int main(void) {
    printf("sizeof(A) = %zu\n", sizeof(struct A));
    printf("sizeof(B) = %zu\n", sizeof(struct B));
    printf("sizeof(C) = %zu\n", sizeof(struct C));
    return 0;
}
Performance tip Field গুলিকে বড় থেকে ছোট আকারে সাজালে padding কমে। Binary protocol বা network packet-এ size গুরুত্বপূর্ণ।

6. Unions — One Memory, Many Views

union.c
#include <stdio.h>

union Data {
    int   i;
    float f;
    char  bytes[4];
};

int main(void) {
    union Data d;
    d.i = 0x41424344;     // 'A','B','C','D' on little-endian
    printf("as int : 0x%X\n", d.i);
    printf("bytes  : %c %c %c %c\n", d.bytes[0], d.bytes[1], d.bytes[2], d.bytes[3]);
    printf("size   : %zu\n", sizeof(union Data));
    return 0;
}
Union-এর সব member একই memory share করে। তার size সবচেয়ে বড় member-এর size-এর সমান। ব্যবহার: endianness check, tagged union (variant type), memory-saving।

7. Bit Fields — Compact Packing

bitfield.c
#include <stdio.h>

struct Flags {
    unsigned int read  : 1;
    unsigned int write : 1;
    unsigned int exec  : 1;
    unsigned int level : 5;    // 5-bit int: 0..31
};

int main(void) {
    struct Flags f = { 1, 1, 0, 7 };
    printf("r=%u w=%u x=%u lvl=%u  size=%zu\n",
           f.read, f.write, f.exec, f.level, sizeof f);
    return 0;
}

Bit field-এর layout (bit ordering, padding) implementation-defined — তাই network protocol cross-platform binary-format-এ bit field-এর উপর ভরসা না করাই ভালো। Embedded system-এ hardware register-এর জন্য কার্যকর।

8. Passing Structs to Functions

void print_point(const Point *p) {     // prefer pointer — no copy
    printf("(%.2f, %.2f)\n", p->x, p->y);
}

ছোট struct (≤ 16 bytes) pass-by-value ঠিক আছে। বড় struct-এ pointer pass-by-value-এর চেয়ে দ্রুত (কপি হয় না)।

9. Practice Problems

  1. Define a Date struct (day, month, year) and write print_date.
    Date struct বানান ও print_date লিখুন।
    ✨ Show Answer
    date.c
    #include <stdio.h>
    typedef struct { int d, m, y; } Date;
    void print_date(Date x) { printf("%02d-%02d-%04d\n", x.d, x.m, x.y); }
    int main(void) { print_date((Date){16, 12, 2026}); return 0; }
  2. Write int compare_dates(const Date *, const Date *).
    দুটি Date তুলনা করার ফাংশন লিখুন।
    ✨ Show Answer
    cmp_date.c
    #include <stdio.h>
    typedef struct { int d, m, y; } Date;
    int compare_dates(const Date *a, const Date *b) {
        if (a->y != b->y) return a->y - b->y;
        if (a->m != b->m) return a->m - b->m;
        return a->d - b->d;
    }
    int main(void) {
        Date a = {10, 3, 2026}, b = {1, 4, 2026};
        int c = compare_dates(&a, &b);
        puts(c < 0 ? "a < b" : c == 0 ? "a == b" : "a > b");
        return 0;
    }
  3. Define a Rectangle with two Points and compute its area and perimeter.
    দুটি Point দিয়ে Rectangle ঘোষণা করুন এবং area/perimeter বের করুন।
    ✨ Show Answer
    rect.c
    #include <stdio.h>
    #include <math.h>
    typedef struct { double x, y; } Point;
    typedef struct { Point tl, br; } Rect;
    int main(void) {
        Rect r = { {0,4}, {3,0} };
        double w = fabs(r.br.x - r.tl.x);
        double h = fabs(r.tl.y - r.br.y);
        printf("area=%.2f perim=%.2f\n", w * h, 2 * (w + h));
        return 0;
    }
  4. Build an array of Students and print them sorted by GPA (descending).
    Student-এর array বানিয়ে GPA-এর descending ক্রমে প্রিন্ট করুন।
    ✨ Show Answer
    sort_students.c
    #include <stdio.h>
    #include <stdlib.h>
    typedef struct { char name[32]; double gpa; } Student;
    int by_gpa_desc(const void *a, const void *b) {
        double d = ((const Student *)b)->gpa - ((const Student *)a)->gpa;
        return (d > 0) - (d < 0);
    }
    int main(void) {
        Student s[] = { {"Arif",3.72}, {"Nusrat",3.92}, {"Zahid",3.55} };
        int n = 3;
        qsort(s, n, sizeof s[0], by_gpa_desc);
        for (int i = 0; i < n; i++) printf("%s : %.2f\n", s[i].name, s[i].gpa);
        return 0;
    }
  5. Show the size of struct { char; int; } and explain padding.
    struct { char; int; }-এর size দেখান ও padding ব্যাখ্যা করুন।
    ✨ Show Answer

    Section 5-এর padding.c-ই সম্পূর্ণ উত্তর — output-এ সাধারণত 8, 8, 8 আসবে।

  6. Use __attribute__((packed)) (GCC) to remove padding and compare sizes.
    GCC-তে __attribute__((packed)) দিয়ে padding সরিয়ে size তুলনা করুন।
    ✨ Show Answer
    packed.c
    #include <stdio.h>
    struct A              { char c; int i; };
    struct __attribute__((packed)) B { char c; int i; };
    int main(void) {
        printf("sizeof(A)=%zu\n", sizeof(struct A));
        printf("sizeof(B)=%zu\n", sizeof(struct B));
        return 0;
    }

    Packed struct-এ misaligned access-এর কারণে কিছু আর্কিটেকচারে (ARM) performance কমতে পারে।

  7. Define a tagged union (enum + union) for variant values: int, float, string.
    Tagged union (enum + union) বানান — int, float, string variant-এর জন্য।
    ✨ Show Answer
    variant.c
    #include <stdio.h>
    
    typedef enum { VAL_INT, VAL_FLT, VAL_STR } Tag;
    typedef struct {
        Tag tag;
        union { int i; float f; const char *s; } u;
    } Value;
    
    void print_value(Value v) {
        switch (v.tag) {
            case VAL_INT: printf("int: %d\n", v.u.i); break;
            case VAL_FLT: printf("flt: %.2f\n", v.u.f); break;
            case VAL_STR: printf("str: %s\n", v.u.s); break;
        }
    }
    
    int main(void) {
        print_value((Value){VAL_INT, .u.i = 42});
        print_value((Value){VAL_FLT, .u.f = 3.14f});
        print_value((Value){VAL_STR, .u.s = "ABCL"});
        return 0;
    }
  8. Use a union to read the individual bytes of an int.
    Union দিয়ে একটি int-এর byte গুলো পড়ুন।
    ✨ Show Answer

    উপরের Section 6-এর union.c-ই উত্তর।

  9. Detect endianness with a union.
    Union দিয়ে endianness detect করুন।
    ✨ Show Answer
    endian.c
    #include <stdio.h>
    int main(void) {
        union { int i; char c[sizeof(int)]; } u;
        u.i = 1;
        puts(u.c[0] == 1 ? "Little-endian" : "Big-endian");
        return 0;
    }
  10. Define a bit field for a small CPU flags register (carry, zero, sign, overflow, 4-bit priv).
    ছোট CPU flags register-এর জন্য bit field ঘোষণা করুন।
    ✨ Show Answer
    cpu_flags.c
    #include <stdio.h>
    struct CPU {
        unsigned int carry : 1;
        unsigned int zero  : 1;
        unsigned int sign  : 1;
        unsigned int over  : 1;
        unsigned int priv  : 4;
    };
    int main(void) {
        struct CPU f = { 1, 0, 1, 0, 3 };
        printf("C=%u Z=%u S=%u O=%u priv=%u size=%zu\n",
               f.carry, f.zero, f.sign, f.over, f.priv, sizeof f);
        return 0;
    }
  11. Build a linked-list node struct and write push_front.
    Linked-list node বানান ও push_front লিখুন।
    ✨ Show Answer
    list_push.c
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct Node { int v; struct Node *next; } Node;
    
    void push_front(Node **head, int v) {
        Node *n = malloc(sizeof *n);
        n->v = v; n->next = *head;
        *head = n;
    }
    
    void print_list(Node *h) {
        for (; h; h = h->next) printf("%d ", h->v);
        putchar('\n');
    }
    
    int main(void) {
        Node *head = NULL;
        for (int i = 1; i <= 5; i++) push_front(&head, i);
        print_list(head);
        while (head) { Node *t = head; head = head->next; free(t); }
        return 0;
    }
  12. Pass a struct by value vs by pointer — and see performance difference.
    Struct pass-by-value vs pass-by-pointer — performance পার্থক্য।
    ✨ Show Answer

    ছোট struct-এ পার্থক্য সামান্য; বড় struct (যেমন 1 KB-র matrix) pass-by-value প্রতিবার পুরো কপি করবে — বাস্তব programming-এ কখনোই pass-by-value করবেন না বড় struct-কে। সবসময় const SomeType * ব্যবহার করুন যদি modify না করতে চান।

  13. Implement Point add(Point, Point) that returns a struct.
    Struct return করার ফাংশন Point add লিখুন।
    ✨ Show Answer
    add_point.c
    #include <stdio.h>
    typedef struct { double x, y; } Point;
    Point add(Point a, Point b) { return (Point){ a.x + b.x, a.y + b.y }; }
    int main(void) {
        Point p = add((Point){1,2}, (Point){3,4});
        printf("(%.1f, %.1f)\n", p.x, p.y);
        return 0;
    }
  14. Build a self-referential struct (struct Node { ...; struct Node *next; };).
    Self-referential struct বানান।
    ✨ Show Answer

    Problem 11-এর list_push.c-ই self-referential struct দেখায়। Field type হিসেবে নিজেই একটি pointer থাকে, কিন্তু সরাসরি struct Node inside struct Node (pointer ছাড়া) চলবে না — infinite size।

  15. Initialize a struct using designated initializers {.x = 1, .y = 2}.
    Designated initializer ব্যবহার করে struct init করুন।
    ✨ Show Answer
    designated.c
    #include <stdio.h>
    typedef struct { int id; double x, y, z; } Point3;
    int main(void) {
        Point3 p = { .id = 7, .x = 1.0, .y = 2.0, .z = 3.0 };
        printf("id=%d  (%.1f, %.1f, %.1f)\n", p.id, p.x, p.y, p.z);
        return 0;
    }

    C99 designated initializer — field নাম দিয়ে নির্দিষ্টভাবে initialize করা যায়, অর্ডার লাগে না।

  16. Why can't you put struct Foo directly inside itself (without a pointer)?
    struct Foo-র ভেতরে সরাসরি নিজেই কেন রাখা যায় না?
    ✨ Show Answer

    সরাসরি রাখলে struct Foo-র size হবে = তার নিজের size + ... — যা infinite। তাই C-তে এটি অনুমোদিত নয়। Pointer ব্যবহার করলে সমস্যা নেই — pointer-এর size fixed (4 বা 8 byte)।

  17. Reorder fields to minimize padding — show the improvement.
    Field পুনর্বিন্যাস করে padding কমান — উন্নতি দেখান।
    ✨ Show Answer
    reorder.c
    #include <stdio.h>
    struct Bad  { char a; double b; char c; int d; };   // lots of padding
    struct Good { double b; int d; char a; char c; };  // big → small
    int main(void) {
        printf("Bad  = %zu\n", sizeof(struct Bad));
        printf("Good = %zu\n", sizeof(struct Good));
        return 0;
    }
  18. Define a struct for an IPv4 header using bit fields (simplified).
    IPv4 header-এর জন্য bit field-ভিত্তিক struct লিখুন (সরলীকৃত)।
    ✨ Show Answer
    ipv4.c
    #include <stdio.h>
    
    struct IPv4 {
        unsigned int version : 4;
        unsigned int ihl     : 4;
        unsigned int tos     : 8;
        unsigned int total   : 16;
    };
    
    int main(void) {
        struct IPv4 h = { 4, 5, 0, 1500 };
        printf("ver=%u ihl=%u tos=%u total=%u size=%zu\n",
               h.version, h.ihl, h.tos, h.total, sizeof h);
        return 0;
    }

    বাস্তবে IPv4 parser-এ bit field-এর পরিবর্তে manual bit masking বেশি portable, কারণ bit layout implementation-নির্ভর।

Glossary (শব্দকোষ)

TermMeaningবাংলায়
structA user-defined type grouping multiple fields.একাধিক field একসাথে রাখা user-defined type।
unionLike a struct, but all fields share the same memory.সব field একই memory ভাগাভাগি করে।
Member / FieldOne named component inside a struct or union.Struct/union-এর ভিতরের একটি নামকরা component।
Member Access (.)Access a member of a struct value.Struct-এর field access করার operator।
Arrow (->)Access a member through a pointer to a struct.Pointer-এর মাধ্যমে struct field access।
typedefCreates an alias for an existing type.Type-এর জন্য alias তৈরি।
PaddingBytes inserted between fields for alignment.Alignment-এর জন্য field-এর মাঝে যোগ হওয়া byte।
AlignmentThe required address-multiple for a type's storage.Type-এর সংরক্ষণে যে address-multiple দরকার।
Bit FieldA struct member with explicit bit width.নির্দিষ্ট bit-width-যুক্ত struct member।
Designated Initializer{.x = 1} syntax to set members by name.নাম ধরে field initialize করার গঠন।
Tagged UnionA struct combining a union with a "type" field.Type-tag সহ union — কোন variant সক্রিয় তা বোঝাতে।
Forward DeclarationDeclaring a struct name before its full definition.পূর্ণ সংজ্ঞার আগেই struct-এর নাম ঘোষণা।

Summary — Module 18

struct groups data; union overlays it. typedef cleans up syntax. Know padding — it surprises beginners. Bit fields and unions let you get close to the bytes. Pass large structs by pointer.

Next Module → Midterm Project — একটি real CLI tool।