1. What will be the output of the following integer evaluation due to Sequence Point / Evaluation rules?
int i = 5;
int val = i++ + ++i;
Output: Undefined behavior (the program has no defined result).
The expression i++ + ++i modifies i twice in the same full expression, with no sequence point ordering the two modifications. The C standard says: if a scalar is modified more than once (or modified and read) between two sequence points, the behavior is undefined. So:
- The result isn’t “12” or “13” — it could be anything.
- The compiler may evaluate in any order; there’s no guaranteed value.
This is the classic C trap: don’t use a variable more than once in an expression where it’s being modified. The interview answer: undefined behavior — i is modified twice without an intervening sequence point.
Answer:
Undefined behavior (the program has no defined result).
The expression i++ + ++i modifies i twice in the same full expression, with no sequence point ordering the two modifications. The C standard says: if a scalar is modified more than once (or modified and read) between two sequence points, the behavior is undefined. So:
- The result isn’t “12” or “13” — it could be anything.
- The compiler may evaluate in any order; there’s no guaranteed value.
This is the classic C trap: don’t use a variable more than once in an expression where it’s being modified. The interview answer: undefined behavior — i is modified twice without an intervening sequence point.
2. What structural padding issue arises in this struct on 64-bit systems?
struct Data {
char a;
double b;
int c;
};
Answer: Padding bytes are inserted after a (7 bytes) and after c (4 bytes), making the struct 24 bytes with 8-byte alignment.
Members must sit at natural alignment boundaries — a double needs 8-byte alignment:
char aat offset 0 (1 byte), then 7 padding bytes.double bat offset 8 (8 bytes, ends at 16).int cat offset 16 (4 bytes, ends at 20).- The struct’s total size must be a multiple of its alignment (8, the strictest member), so 4 trailing padding bytes → 24 bytes total.
So sizeof(struct Data) is 24, not 1 + 8 + 4 = 13. The compiler never reorders members (order is guaranteed by the standard); it only inserts padding. Reordering members manually (biggest first) is the classic way to shrink struct sizes. The interview answer: 7 padding after a, 4 after c, struct size 24 with 8-byte alignment.
Answer:
Padding bytes are inserted after a (7 bytes) and after c (4 bytes), making the struct 24 bytes with 8-byte alignment.
Members must sit at natural alignment boundaries — a double needs 8-byte alignment:
char aat offset 0 (1 byte), then 7 padding bytes.double bat offset 8 (8 bytes, ends at 16).int cat offset 16 (4 bytes, ends at 20).- The struct’s total size must be a multiple of its alignment (8, the strictest member), so 4 trailing padding bytes → 24 bytes total.
So sizeof(struct Data) is 24, not 1 + 8 + 4 = 13. The compiler never reorders members (order is guaranteed by the standard); it only inserts padding. Reordering members manually (biggest first) is the classic way to shrink struct sizes. The interview answer: 7 padding after a, 4 after c, struct size 24 with 8-byte alignment.
3. What does typedef do in C?
Answer: It creates an alias (new name) for an existing type.
typedef doesn’t create a new kind of type — it introduces a synonym:
typedef unsigned long ulong;
typedef struct { int x, y; } Point;
ulong big = 42; // unsigned long
Point p = {1, 2}; // the struct
Uses:
- Readability — names like
Pointinstead ofstruct {...}. - Portability — abstract platform-specific types (
size_t,uint32_t) behind one name. - Reducing verbosity —
typedef struct Node { ... } Node;lets you writeNodeinstead ofstruct Nodein C.
Note: typedef names are part of the ordinary identifier namespace (unlike struct tags), so they follow normal scope rules. The interview answer: typedef defines an alias for an existing type.
Answer:
It creates an alias (new name) for an existing type.
typedef doesn’t create a new kind of type — it introduces a synonym:
typedef unsigned long ulong;
typedef struct { int x, y; } Point;
ulong big = 42; // unsigned long
Point p = {1, 2}; // the struct
Uses:
- Readability — names like
Pointinstead ofstruct {...}. - Portability — abstract platform-specific types (
size_t,uint32_t) behind one name. - Reducing verbosity —
typedef struct Node { ... } Node;lets you writeNodeinstead ofstruct Nodein C.
Note: typedef names are part of the ordinary identifier namespace (unlike struct tags), so they follow normal scope rules. The interview answer: typedef defines an alias for an existing type.
4. What does the enum feature in C construct?
Answer: A user-defined enumeration type: named integer constants that improve readability.
enum creates a set of named constants:
enum Color { RED, GREEN, BLUE };
enum Color c = GREEN; // c == 1
By default the constants start at 0 and increment by 1 (RED=0, GREEN=1, BLUE=2), but you can assign explicit values:
enum Status { OK = 0, ERROR = -1, TIMEOUT = 2 };
Benefits: self-documenting code (names instead of magic numbers), and the compiler can warn about unhandled cases. In C, enum values are just ints underneath — they interconvert freely with integers (unlike C++ where the rules are stricter). The interview answer: an enumeration of named integer constants for readability and type-organization.
Answer:
A user-defined enumeration type: named integer constants that improve readability.
enum creates a set of named constants:
enum Color { RED, GREEN, BLUE };
enum Color c = GREEN; // c == 1
By default the constants start at 0 and increment by 1 (RED=0, GREEN=1, BLUE=2), but you can assign explicit values:
enum Status { OK = 0, ERROR = -1, TIMEOUT = 2 };
Benefits: self-documenting code (names instead of magic numbers), and the compiler can warn about unhandled cases. In C, enum values are just ints underneath — they interconvert freely with integers (unlike C++ where the rules are stricter). The interview answer: an enumeration of named integer constants for readability and type-organization.
5. What does the union structure do in C?
Answer: All members share the same memory location, sized to fit the largest member — only one member is meaningful at a time.
A union overlays all its members at the same starting address:
union Value {
int i;
float f;
char bytes[4];
};
// sizeof(union Value) == 4 (largest member)
Writing to one member overwrites the shared storage — reading a different member reinterprets those same bytes. The union is big enough for its largest member (plus alignment padding).
Use cases:
- Type punning — inspect the bytes of a
floatas anint(with care; strict aliasing rules apply, and C23’s typeof punning via unions became legal). - Memory savings — when a variable is one-of-several types, a union uses max-size instead of the sum.
- Variant/tagged structures — a union plus a discriminant
enumfield telling which member is active.
The responsibility: track which member is currently valid — there’s no automatic check. The interview answer: a single shared memory region sized for the largest member; only one field can safely hold a value at a time.
Answer:
All members share the same memory location, sized to fit the largest member — only one member is meaningful at a time.
A union overlays all its members at the same starting address:
union Value {
int i;
float f;
char bytes[4];
};
// sizeof(union Value) == 4 (largest member)
Writing to one member overwrites the shared storage — reading a different member reinterprets those same bytes. The union is big enough for its largest member (plus alignment padding).
Use cases:
- Type punning — inspect the bytes of a
floatas anint(with care; strict aliasing rules apply, and C23’s typeof punning via unions became legal). - Memory savings — when a variable is one-of-several types, a union uses max-size instead of the sum.
- Variant/tagged structures — a union plus a discriminant
enumfield telling which member is active.
The responsibility: track which member is currently valid — there’s no automatic check. The interview answer: a single shared memory region sized for the largest member; only one field can safely hold a value at a time.
6. What is the behavior of reading a union member different from the one most recently written to?
Answer: It reinterprets the raw bit pattern as the new member’s type — type-punning, which C explicitly permits.
Unlike C++, C allows reading a union member other than the one last written — a feature called type punning. The stored bytes are reinterpreted as the target member’s type. This is only meaningful when the members are the same size (and alignment-compatible):
union { float f; uint32_t i; } u;
u.f = 1.5f;
printf("%08x", u.i); // raw IEEE-754 bits of 1.5f, as an unsigned int
This is the classic low-level idiom for inspecting the binary representation of a value (e.g., floating-point bit manipulation) without memcpy or pointer-cast aliasing games. (C23 formalized and strengthened these guarantees.) Caveat: the interpretation depends on the representation — it’s a deliberate bit-level view, not a “safe conversion.” The interview answer: the stored bit pattern is read as the new member’s type (type-punning), supported when sizes/alignment match.
Answer:
It reinterprets the raw bit pattern as the new member’s type — type-punning, which C explicitly permits.
Unlike C++, C allows reading a union member other than the one last written — a feature called type punning. The stored bytes are reinterpreted as the target member’s type. This is only meaningful when the members are the same size (and alignment-compatible):
union { float f; uint32_t i; } u;
u.f = 1.5f;
printf("%08x", u.i); // raw IEEE-754 bits of 1.5f, as an unsigned int
This is the classic low-level idiom for inspecting the binary representation of a value (e.g., floating-point bit manipulation) without memcpy or pointer-cast aliasing games. (C23 formalized and strengthened these guarantees.) Caveat: the interpretation depends on the representation — it’s a deliberate bit-level view, not a “safe conversion.” The interview answer: the stored bit pattern is read as the new member’s type (type-punning), supported when sizes/alignment match.
7. What is a Flexible Array Member in C structs introduced in C99?
Answer: An unsized array as the last member of a struct (e.g., int data[];) that lets you allocate a variable-length payload contiguous with the struct header.
A flexible array member is declared as the last struct member without a size:
struct Packet {
int length;
char data[]; // flexible array member
};
You allocate the struct and its payload in one contiguous block:
struct Packet *p = malloc(sizeof(struct Packet) + payload_bytes);
p->length = payload_bytes;
p->data[0] = ...; // reach the inline payload
Rules: it must be the last member; there must be at least one other named member; the struct is sized as if the array were absent (with trailing padding for alignment). This is the standard way to build header+payload messages with a single allocation and good locality. The interview answer: a trailing unsized array (data[]) enabling contiguous struct-header + variable-payload allocation.
Answer:
An unsized array as the last member of a struct (e.g., int data[];) that lets you allocate a variable-length payload contiguous with the struct header.
A flexible array member is declared as the last struct member without a size:
struct Packet {
int length;
char data[]; // flexible array member
};
You allocate the struct and its payload in one contiguous block:
struct Packet *p = malloc(sizeof(struct Packet) + payload_bytes);
p->length = payload_bytes;
p->data[0] = ...; // reach the inline payload
Rules: it must be the last member; there must be at least one other named member; the struct is sized as if the array were absent (with trailing padding for alignment). This is the standard way to build header+payload messages with a single allocation and good locality. The interview answer: a trailing unsized array (data[]) enabling contiguous struct-header + variable-payload allocation.
8. What is the difference between structure field access operators . and ->?
Answer: . accesses a member directly on a struct instance; -> accesses a member through a pointer to a struct — and ptr->member is shorthand for (*ptr).member.
struct Point p; // instance
p.x = 5; // . on the instance
struct Point *pp = &p;
pp->x = 7; // -> dereferences the pointer
(*pp).x = 7; // equivalent, more verbose
So . needs the struct itself (or a reference to it); -> dereferences the pointer first, then accesses the member. Using . where you have a pointer (or -> where you have an instance) is a compile error. The arrow is just the idiomatic, more readable version of (*ptr).member. The interview answer: . on instances, -> on pointers (dereference + access).
Answer:
. accesses a member directly on a struct instance; -> accesses a member through a pointer to a struct — and ptr->member is shorthand for (*ptr).member.
struct Point p; // instance
p.x = 5; // . on the instance
struct Point *pp = &p;
pp->x = 7; // -> dereferences the pointer
(*pp).x = 7; // equivalent, more verbose
So . needs the struct itself (or a reference to it); -> dereferences the pointer first, then accesses the member. Using . where you have a pointer (or -> where you have an instance) is a compile error. The arrow is just the idiomatic, more readable version of (*ptr).member. The interview answer: . on instances, -> on pointers (dereference + access).
9. What is the purpose of alignment macro alignof / _Alignof introduced in C11?
Answer: It queries the alignment requirement (in bytes) of a specified type.
alignof(type) (or its spelling _Alignof; <stdalign.h> provides the alignof macro) returns the byte alignment that objects of that type must have:
alignof(char) // typically 1
alignof(int) // typically 4
alignof(double) // typically 8
This is the natural alignment the compiler enforces when placing the type in memory (e.g., a double at offset multiple of 8). C11 also added _Alignas (declaration specifier to request alignment) and aligned_alloc (allocate with a given alignment). These matter for hardware, vector types, and ABI-compatible struct layouts. The interview answer: alignof(type) returns the type’s required byte alignment.
Answer:
It queries the alignment requirement (in bytes) of a specified type.
alignof(type) (or its spelling _Alignof; <stdalign.h> provides the alignof macro) returns the byte alignment that objects of that type must have:
alignof(char) // typically 1
alignof(int) // typically 4
alignof(double) // typically 8
This is the natural alignment the compiler enforces when placing the type in memory (e.g., a double at offset multiple of 8). C11 also added _Alignas (declaration specifier to request alignment) and aligned_alloc (allocate with a given alignment). These matter for hardware, vector types, and ABI-compatible struct layouts. The interview answer: alignof(type) returns the type’s required byte alignment.
10. What does offsetof(type, member) in <stddef.h> calculate?
Answer: The byte offset of a structure member from the start of the struct, accounting for padding.
offsetof(struct_type, member) returns the number of bytes from the beginning of the struct to that member, including any padding the compiler inserted for alignment:
struct Data { char a; double b; int c; };
offsetof(struct Data, b) // 8 (7 padding bytes after a)
offsetof(struct Data, c) // 16
Uses: manual serialization, building generic reflection/field tables, allocating flexible layouts. It’s a compile-time constant (works in static contexts and constant expressions). The interview answer: the padded byte offset of a member within its struct.
Answer:
The byte offset of a structure member from the start of the struct, accounting for padding.
offsetof(struct_type, member) returns the number of bytes from the beginning of the struct to that member, including any padding the compiler inserted for alignment:
struct Data { char a; double b; int c; };
offsetof(struct Data, b) // 8 (7 padding bytes after a)
offsetof(struct Data, c) // 16
Uses: manual serialization, building generic reflection/field tables, allocating flexible layouts. It’s a compile-time constant (works in static contexts and constant expressions). The interview answer: the padded byte offset of a member within its struct.
Premium Content
Unlock Structs, Unions & Undefined Behavior and all premium lessons with a subscription.
From ₹199.99/year — See plans