Menu
CoddyTech

C Structures and Unions Interview Questions

Structs, unions, padding and the self-referential structs linked lists are made of.

10 questions
  1. What is the difference between a structure and a union in C?

    A struct gives each member its own storage; a union makes all members share one, so only one holds a value at a time and the size is the largest member's (plus padding).

    C
    #include <stdio.h>
    
    struct S { int i; double d; char c; };
    union  U { int i; double d; char c; };
    
    int main(void) {
        printf("struct: %zu bytes\n", sizeof(struct S));
        printf("union:  %zu bytes\n", sizeof(union U));
        union U u;
        u.d = 2.5;
        printf("u.d = %.1f\n", u.d);
        return 0;
    }

    Here the struct is 24 bytes and the union 8. A union usually pairs with a tag field naming the active member. See unions.

  2. Does member order change the sizeof of a struct?

    C
    #include <stdio.h>
    
    struct A { char c; int i; char d; };
    struct B { int i; char c; char d; };
    
    int main(void) {
        printf("%zu %zu\n", sizeof(struct A), sizeof(struct B));
        return 0;
    }

    It prints 12 8. Each int is aligned to 4 bytes, so A pads 3 bytes after c and 3 after d, while B keeps the chars together: 4 + 1 + 1 + 2. Padding is implementation-defined (these numbers are GCC on x86-64); order members largest first.

  3. Does assigning one struct to another copy it or share it?

    C
    #include <stdio.h>
    
    struct Point { int x, y; };
    
    int main(void) {
        struct Point a = {1, 2};
        struct Point b = a;
        b.x = 9;
        printf("%d %d\n", a.x, b.x);
        return 0;
    }

    It prints 1 9. Struct assignment copies every member, so b is independent. A pointer member is copied shallowly, though: both structs then share one buffer.

  4. What does typedef do, and why is it used with structs?

    typedef creates an alias for an existing type, not a new type, so you can write Point instead of struct Point.

    typedef struct Point {
        int x, y;
    } Point;
    
    typedef int (*Compare)(const void *, const void *);  /* names a function pointer type */
    

    It helps most with function pointer types.

  5. How do you define a linked list node in C, and why does it need a pointer to itself?

    A node holds data and a pointer to the next node. A struct cannot contain itself (its size would be infinite), but it can contain a pointer to itself, since a pointer has a fixed size.

    C
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct Node {
        int value;
        struct Node *next;   /* the typedef name is not defined yet here */
    } Node;
    
    Node *push(Node *head, int value) {
        Node *n = malloc(sizeof *n);
        if (!n) return head;
        n->value = value;
        n->next = head;
        return n;
    }
    
    int main(void) {
        Node *head = NULL;
        for (int i = 1; i <= 4; i++) head = push(head, i * 10);
        for (Node *p = head; p; p = p->next) printf("%d -> ", p->value);
        printf("NULL\n");
        while (head) { Node *next = head->next; free(head); head = next; }
        return 0;
    }

    It prints 40 -> 30 -> 20 -> 10 -> NULL. See the linked list visualizer.

    Practice it: Reverse Linked List, Middle of the Linked List, Linked List Cycle

  6. Can you compare two structs with == in C?

    No. == is not defined for structs, so it is a compile error; compare member by member. memcmp is wrong in general, because padding bytes have unspecified values and floating point members (0.0 and -0.0, NaN) need their own rules.

  7. What value does C get in enum { A, B = 5, C }?

    C
    #include <stdio.h>
    
    enum Level { A, B = 5, C };
    
    int main(void) {
        printf("%d %d %d\n", A, B, C);
        return 0;
    }

    It prints 0 5 6. Enumerators start at 0 and each is one more than the previous unless given a value, so C follows B = 5. In C an enumerator is an int constant (C23 also allows wider ones), and the compiler does not stop an enum variable from holding other values.

  8. What is a flexible array member?

    A flexible array member (C99) is a size-less array as the last member of a struct, so one malloc holds the struct and its data together.

    C
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef struct {
        size_t len;
        char data[];     /* flexible array member, must be last */
    } Buffer;
    
    int main(void) {
        const char *text = "packet payload";
        size_t n = strlen(text) + 1;
        Buffer *b = malloc(sizeof *b + n);
        if (!b) return 1;
        b->len = n - 1;
        memcpy(b->data, text, n);
        printf("%zu: %s\n", b->len, b->data);
        free(b);
        return 0;
    }

    It prints 14: packet payload; sizeof(Buffer) excludes the array. The old char data[1] trick is undefined behavior past element 0.

  9. What are bit fields in C, and when should you avoid them?

    A bit field gives a struct member an exact width in bits, so several small values share one word. They are used for hardware registers and compact sets of flags.

    C
    #include <stdio.h>
    
    struct Flags {
        unsigned int ready : 1;  /* 0 or 1 */
        unsigned int mode : 3;   /* 0 to 7 */
        unsigned int level : 4;  /* 0 to 15 */
    };
    
    int main(void) {
        struct Flags f = {1, 7, 12};
        printf("%d %d %d\n", f.ready, f.mode, f.level);
        f.mode++;                /* 8 does not fit in 3 bits: wraps to 0 */
        printf("%d\n", f.mode);
        return 0;
    }

    It prints 1 7 12, then 0: an unsigned bit field wraps modulo its width. You cannot take a bit field's address (&f.mode does not compile), and bit order and padding are implementation-defined, so for a file or network format use shifts and masks instead.

  10. What is the difference between . and ->, and should you pass a struct by value or by pointer?

    . accesses a member of a struct and -> a member through a pointer to a struct: p->x means (*p).x. The parentheses are needed because . binds tighter than *.

    C
    #include <stdio.h>
    
    struct Point { int x, y; };
    
    void move_copy(struct Point p) { p.x += 10; }   /* changes a copy */
    void move_ptr(struct Point *p) { p->x += 10; }  /* p->x is (*p).x */
    
    int main(void) {
        struct Point pt = {1, 2};
        move_copy(pt);
        printf("after move_copy: %d\n", pt.x);
        move_ptr(&pt);
        printf("after move_ptr: %d\n", pt.x);
        return 0;
    }

    It prints 1, then 11: a struct passed by value is copied, so only the pointer version changes the caller's struct. Pass large structs by pointer (const struct Point * when the function only reads) to avoid the copy. See structs and pointers.

Coddy programming languages illustration

Learn to code with Coddy

Get started