Nearby lessons

101 of 124

C - Structure Variable

A structure variable is an actual instance of a structure type with real memory. Learn the ways to create one, how to read and write its members, how assignment copies every member, and why sizeof is often larger than you expect.

Three Ways to Create One

Declare after the definition, alongside it, or through a typedef name:

Example01
CCode Cell
1#include <stdio.h>
2 
3struct Point { int x, y; } origin = {0, 0}; /* 2: with the definition */
4 
5typedef struct { int x, y; } Vec; /* 3: via typedef */
6 
7int main()
8{
9 struct Point p; /* 1: after the definition */
10 Vec v;
11 
12 p.x = 10; p.y = 20;
13 v.x = 3; v.y = 4;
14 
15 printf("p = (%d, %d)\n", p.x, p.y);
16 printf("origin = (%d, %d)\n", origin.x, origin.y);
17 printf("v = (%d, %d)\n", v.x, v.y);
18 return 0;
19}
Output
p      = (10, 20)
origin = (0, 0)
v      = (3, 4)

Reading and Writing Members

The dot operator names a member. Each member behaves exactly like an ordinary variable of its type:

Example02
CCode Cell
1#include <stdio.h>
2#include <string.h>
3 
4struct Student {
5 char name[30];
6 int roll;
7 float marks;
8};
9 
10int main()
11{
12 struct Student s;
13 
14 strcpy(s.name, "Rahul"); /* an array member needs strcpy */
15 s.roll = 101;
16 s.marks = 85.5f;
17 
18 printf("%s, roll %d, %.1f marks\n", s.name, s.roll, s.marks);
19 
20 s.marks += 5.0f; /* members work in expressions */
21 s.roll++;
22 printf("After update: roll %d, %.1f marks\n", s.roll, s.marks);
23 return 0;
24}
Output
Rahul, roll 101, 85.5 marks
After update: roll 102, 90.5 marks

An Array Member Is Not Assignable

s.name = "Rahul"; does not compile. A char array member is still an array, so it cannot be assigned after declaration — use strcpy. Curiously, copying the whole structure with b = a; does copy the array, because that is a single struct assignment rather than an array assignment.
Example03
CCode Cell
1#include <stdio.h>
2#include <string.h>
3 
4struct Student { char name[30]; int roll; };
5 
6int main()
7{
8 struct Student a = {"Rahul", 101}; /* initialisation is fine */
9 struct Student b;
10 
11 /* b.name = "Priya"; ERROR: assignment to expression with array type */
12 strcpy(b.name, "Priya"); /* this works */
13 b.roll = 102;
14 
15 struct Student c = a; /* whole-struct copy: name included */
16 
17 printf("a: %s %d\n", a.name, a.roll);
18 printf("b: %s %d\n", b.name, b.roll);
19 printf("c: %s %d (array copied with the struct)\n", c.name, c.roll);
20 return 0;
21}
Output
a: Rahul 101
b: Priya 102
c: Rahul 101  (array copied with the struct)

Assignment Copies Everything

In simple words: b = a; makes an independent copy of every member. Change b afterwards and a is untouched — the two variables share nothing.
Example04
CCode Cell
1#include <stdio.h>
2#include <string.h>
3 
4struct Student { char name[30]; int roll; float marks; };
5 
6int main()
7{
8 struct Student a = {"Rahul", 101, 85.5f};
9 struct Student b = a; /* one statement, all members */
10 
11 strcpy(b.name, "Priya"); /* modify the copy */
12 b.roll = 102;
13 
14 printf("a: %s %d %.1f\n", a.name, a.roll, a.marks);
15 printf("b: %s %d %.1f\n", b.name, b.roll, b.marks);
16 printf("Independent copies - a is unchanged\n");
17 return 0;
18}
Output
a: Rahul 101 85.5
b: Priya 102 85.5
Independent copies - a is unchanged

The Shallow-Copy Trap

The copy is byte-for-byte. If a member is a pointer, both structures end up pointing at the same memory:

Example05
CCode Cell
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4 
5struct Holder { char *text; };
6 
7int main()
8{
9 struct Holder a;
10 a.text = malloc(20);
11 if (a.text == NULL) return 1;
12 strcpy(a.text, "original");
13 
14 struct Holder b = a; /* copies the POINTER, not the text */
15 
16 strcpy(b.text, "changed"); /* writes through the shared block */
17 
18 printf("a.text = %s\n", a.text);
19 printf("b.text = %s\n", b.text);
20 printf("Same address: %s\n", a.text == b.text ? "yes" : "no");
21 
22 free(a.text); /* free once, not twice */
23 return 0;
24}
Output
a.text = changed
b.text = changed
Same address: yes

Pointers to Structure Variables

Take the address with & and use -> to reach members. p->x is shorthand for (*p).x:

Example06
CCode Cell
1#include <stdio.h>
2 
3struct Point { int x, y; };
4 
5int main()
6{
7 struct Point p = {10, 20};
8 struct Point *ptr = &p;
9 
10 printf("p.x = %d\n", p.x);
11 printf("ptr->x = %d\n", ptr->x);
12 printf("(*ptr).x = %d\n", (*ptr).x);
13 
14 ptr->y = 99; /* writes into p */
15 printf("p.y after ptr->y = 99 : %d\n", p.y);
16 return 0;
17}
Output
p.x       = 10
ptr->x    = 10
(*ptr).x  = 10
p.y after ptr->y = 99 : 99

Why *p.x Does Not Work

The dot binds tighter than *, so *p.x parses as *(p.x) — it tries to dereference the member. The parentheses in (*p).x are mandatory, which is exactly why -> exists:

Example07
CCode Cell
1#include <stdio.h>
2 
3struct Point { int x, y; };
4 
5int main()
6{
7 struct Point p = {10, 20};
8 struct Point *ptr = &p;
9 
10 /* printf("%d", *ptr.x); ERROR: ptr is not a struct */
11 
12 printf("(*ptr).x = %d <- parentheses required\n", (*ptr).x);
13 printf("ptr->x = %d <- the readable form\n", ptr->x);
14 return 0;
15}
Output
(*ptr).x = 10   <- parentheses required
ptr->x   = 10   <- the readable form

No == for Structures

Structures cannot be compared as wholes, because padding bytes hold unspecified values. Compare the members you care about:

Example08
CCode Cell
1#include <stdio.h>
2#include <string.h>
3 
4struct Point { int x, y; };
5 
6int samePoint(struct Point a, struct Point b)
7{
8 return a.x == b.x && a.y == b.y;
9}
10 
11int main()
12{
13 struct Point p = {10, 20}, q = {10, 20};
14 
15 /* if (p == q) ERROR: invalid operands to binary == */
16 
17 printf("Member compare : %s\n", samePoint(p, q) ? "equal" : "different");
18 
19 /* memcmp works only if you are certain there is no padding */
20 printf("memcmp : %s\n",
21 memcmp(&p, &q, sizeof p) == 0 ? "equal" : "different");
22 return 0;
23}
Output
Member compare : equal
memcmp         : equal

sizeof and Padding

The compiler inserts unused bytes so each member starts at an address its type likes. That is why the total exceeds the sum:

Example09
CCode Cell
1#include <stdio.h>
2 
3struct Wasteful { char c; int i; char d; }; /* 1 + 4 + 1 = 6 bytes? */
4struct Packed { int i; char c; char d; }; /* same members, reordered */
5 
6int main()
7{
8 printf("Members total : %zu bytes\n",
9 sizeof(char) + sizeof(int) + sizeof(char));
10 printf("struct Wasteful : %zu bytes\n", sizeof(struct Wasteful));
11 printf("struct Packed : %zu bytes\n", sizeof(struct Packed));
12 printf("\nSame data, less padding when large members come first.\n");
13 return 0;
14}
Output
Members total     : 6 bytes
struct Wasteful   : 12 bytes
struct Packed     : 8 bytes

Arrays of Structure Variables

An array of structures is the standard way to hold many records. Index first, then pick the member:

Example10
CCode Cell
1#include <stdio.h>
2 
3struct Student { char name[20]; int roll; float marks; };
4 
5int main()
6{
7 struct Student list[3] = {
8 {"Rahul", 101, 85.5f},
9 {"Priya", 102, 91.0f},
10 {"Amit", 103, 78.0f}
11 };
12 float total = 0.0f;
13 int i;
14 
15 for (i = 0; i < 3; i++)
16 {
17 printf("%-8s %d %.1f\n", list[i].name, list[i].roll,
18 list[i].marks);
19 total += list[i].marks;
20 }
21 
22 printf("Average: %.2f\n", total / 3);
23 printf("Array size: %zu bytes for 3 records\n", sizeof(list));
24 return 0;
25}
Output
Rahul    101  85.5
Priya    102  91.0
Amit     103  78.0
Average: 84.83
Array size: 84 bytes for 3 records

Common Mistakes

  • Using an uninitialised structure — its members hold garbage, exactly like loose local variables.
  • s.name = "text" — use strcpy for array members.
  • p == q — compare member by member instead.
  • *ptr.x — write ptr->x or (*ptr).x.
  • Using . on a pointer — the compiler will tell you to use ->.
  • Assuming sizeof equals the sum of members — padding makes it larger.
  • Copying a structure with a pointer member — both copies then share one block.
Trainer's Note: two questions settle the operator every time. "Do I have the thing itself?" → dot. "Do I have its address?" → arrow. And a whole-structure assignment is a genuine copy — unlike an array, which you must copy element by element.
📝 Key Takeaways
  • A definition is the blueprint; a variable is the building.
  • Use . on a structure and -> on a pointer to one.
  • b = a copies every member, including arrays.
  • Structures cannot be compared with == .
  • sizeof is usually more than the sum of the members, because of padding.

🧠 Test Your Knowledge

4 Questions
Progress: 0 / 4