5.1.22 · D5C Programming
Question bank — Structures — declaration, accessing members (. and - - )
Before the traps, one shared vocabulary reminder so nothing below is a surprise:
True or false — justify
Two struct variables of the same type can be assigned with b = a;.
True. Struct assignment copies every member byte-for-byte (a shallow copy); it is one of the few whole-aggregate operations C allows, unlike arrays which cannot be assigned.
Two struct variables can be compared with if (a == b).
False. C has no built-in
== for structs; padding bytes between members are uninitialised garbage, so even identical-looking structs may differ. You must compare member by member.sizeof(struct Student) always equals the sum of its members' sizes.
False. The compiler inserts padding so each member sits at an aligned address, so the total can be larger. See Memory Alignment & Padding.
Declaring struct Point { int x, y; }; also creates a variable you can use.
False. That line defines a type (a blueprint) only; it reserves no memory. You still need
struct Point a; to get an actual object.p->m and (*p).m produce identical results in every case.
True.
-> is defined to mean exactly (*p).m; it is pure shorthand with no behavioural difference — only fewer parentheses.A structure can contain a member that is a pointer to its own type.
True.
struct Node { int v; struct Node *next; }; is legal because a pointer has a known fixed size; this is the backbone of Linked Lists.A structure can contain a member that is a full (non-pointer) copy of its own type.
False. That would need infinite size — the struct would contain itself, containing itself, forever. Only a pointer to the same type is allowed.
Passing a struct to a function by value lets the function modify the caller's original.
False. By-value passing copies the whole struct; edits touch the copy and vanish on return. Pass a pointer (
&a) to modify the caller's object — see Passing Structures to Functions.The order you write members in the declaration is irrelevant to memory layout.
False. Members are stored in declaration order; reordering them can change the amount of padding and hence
sizeof.Spot the error
struct Student { char name[20]; int roll; } — what's missing?
The semicolon after the closing
}. A struct definition is a declaration statement, not a code block, so it must end in ;.s.name = "Asha"; where name is char name[20] — why does this fail?
name is an array, and arrays are not assignable. Use strcpy(s.name, "Asha"); to copy characters into the existing slot.struct Point *p = &a; p.x = 5; — what's wrong?
p is a pointer (an address), so . is illegal; you need p->x = 5. The compiler complains that p is "not a structure".printf("%d", *p.roll); (p is a struct pointer) — why is this a bug?
. binds tighter than *, so this parses as *(p.roll) — nonsense. You meant (*p).roll or simply p->roll.struct Student s; printf("%s", s.name); before any assignment — what's the danger?
s is uninitialised, so name holds garbage bytes with no guaranteed '\0'; printf may read past the array and crash or print junk.struct Node { struct Node next; }; — why won't this compile?
It embeds a full copy of itself, requiring infinite size. Change
next to a pointer struct Node *next;.e.when->d = 25; where when is a plain struct Date member (not a pointer) — the error?
when is a value, not a pointer, so you follow it with ., giving e.when.d. -> here dereferences a non-pointer.Why questions
Why does C provide -> at all, when (*p).m already works?
Pointers-to-structs are everywhere (function args, linked lists), and
(*p).m is verbose and easy to misparenthesise; -> is a clean, unambiguous shorthand.Why do the parentheses in (*p).m actually matter?
Operator precedence:
. binds tighter than *. Without parentheses, *p.m means *(p.m), which tries to take member m of the pointer itself and dereference the result.Why can a structure hold members of different types when an array cannot?
A struct addresses each member by a named offset, so mixed sizes are fine; an array addresses by uniform index
base + i*size, which demands one element type. Contrast in Arrays vs Structures.Why is passing &a needed for a function to mutate the caller's struct?
Passing
a hands over a copy; the function edits the copy. Passing the address &a lets the function reach back through the pointer to the original object.Why does typedef get used with structs so often?
It lets you name the type without repeating the word
struct on every declaration, so you can write Student s; instead of struct Student s;. See typedef.Why is the member name described as "just a label for a byte offset"?
At runtime there are no names — the compiler translates
s.roll into "start address of s plus the fixed offset of roll", so the name exists only for humans. This connects to Pointers in C.Why can two identical-looking structs compare unequal in raw memory?
The padding bytes between members are not initialised to any defined value, so a byte-wise comparison can see stale garbage even when every real member matches.
Edge cases
What does sizeof report for a struct with a single char member?
Usually just
1 (a lone char needs no alignment padding), but if that struct is placed in an array or another struct, alignment rules of the context can still add trailing padding.Is struct Empty { }; (no members) valid in C?
In standard C it is not valid — a struct must have at least one member. (Some compilers allow it as an extension with
sizeof of 0 or 1, but don't rely on it.)Does assigning b = a; copy an array member inside the struct?
Yes. Struct assignment copies all members, including array members element-by-element — even though a bare array outside a struct cannot be assigned. The struct "wraps" the array to make it copyable.
If two members share the same value, do they share memory?
No. Every member occupies its own distinct offset; equal values are stored in two separate places. Structs never overlap members (that would be a
union, a different construct).What happens to p->roll if p is a valid-looking pointer set to NULL?
Undefined behaviour / crash.
-> dereferences p first; dereferencing NULL reads address 0, which the OS forbids, typically causing a segmentation fault.Can you take the address of an individual member, like &s.roll?
Yes. A member has a real memory location (base of
s plus its offset), so &s.roll is a valid pointer to that int — handy when passing a single field by reference.Recall One-line rule that resolves most traps
Ask: "Do I hold the object or its address?" — object → ., address (pointer) → ->. Almost every ./-> error is answering that question wrongly.
Connections
- Pointers in C — every
->trap is ultimately a pointer question. - Arrays vs Structures — clarifies why structs allow mixed types and copying.
- Linked Lists — the classic home of self-referential structs and
->. - typedef — removes the repeated
structkeyword. - Memory Alignment & Padding — explains the
sizeofand comparison traps. - Passing Structures to Functions — by value (copy) vs by pointer (mutable).