1. Introduction
A structure (struct) in C is a user-defined data type that groups together variables of different types under a single name. Unlike arrays, which hold multiple values of the same type, structures let you model real-world entities that have multiple distinct attributes, such as a Student with a name, roll number, and marks, or a Point with x and y coordinates. Structures are foundational for building more complex data structures like linked lists, trees, and hash tables, and they are used extensively wherever related data needs to travel together, such as function arguments, return values, and array elements.
Cricket analogy: A player's scorecard entry groups distinct data types together, name (string), runs (int), strike rate (float), just as a struct groups a Student's name, roll number, and marks under one type.
2. Syntax
A structure is defined with the struct keyword: struct StructName { dataType member1; dataType member2; ... }; Variables of this type are then declared as struct StructName varName;, or a typedef can be used to create a shorter alias, e.g. typedef struct { int x; int y; } Point; allowing Point p; directly. Members are accessed using the dot operator (.) for a plain struct variable, e.g. p.x, and using the arrow operator (->) when accessing members through a pointer to a structure, e.g. ptr->x, which is shorthand for (*ptr).x.
Cricket analogy: Defining a Batsman template with name and average is like struct StructName {...}; giving it the shorthand Batsman via typedef is like a scorer using a nickname; accessing batsman.average directly is the dot operator, while a coach checking stats through a roster pointer uses ptr->average.
3. Explanation
Internally, a structure's members are stored in memory in the order they are declared, and each member is accessed at a fixed offset from the start of the structure. The dot operator (.) is used when you have a direct struct instance in hand, while the arrow operator (->) exists purely for convenience when working with a pointer to a struct, since writing (*ptr).member repeatedly is cumbersome; ptr->member is exactly equivalent to (*ptr).member. Structures can be nested (a struct containing another struct as a member), passed to functions either by value (copying the entire struct, which can be costly for large structs) or by pointer (passing only an address, which is efficient and also allows the function to modify the original), and returned from functions directly. Arrays of structures are a common pattern for representing collections of records, such as an array of Student structs.
Cricket analogy: A scorecard's runs field always sits at the same offset on the printed sheet; using scorer->runs is shorthand for (*scorer).runs; a team roster nested inside a match struct mirrors nested structs; handing a photocopy of a player's card to the analyst (by value) is costly, while handing the original card (by pointer) lets them update it directly; a full squad list is an array of Player structs.
sizeof(struct) is often larger than the simple sum of its members' sizes because the compiler inserts padding bytes between members (and sometimes at the end of the struct) to satisfy alignment requirements: most CPUs read multi-byte data types like int or double fastest when they start at addresses that are multiples of their own size. For example, a struct with a char followed by an int typically has 3 padding bytes inserted after the char so the int starts at a 4-byte-aligned offset, making the struct's actual size larger than char + int. This padding is compiler- and platform-dependent, so never assume an exact byte count — always use sizeof() to check, and reorder members from largest to smallest to minimize padding if memory layout matters.
Tip: When memory efficiency matters (e.g., large arrays of structs), declare structure members roughly in decreasing order of size (largest types first, smallest like char last). This typically reduces the amount of padding the compiler needs to insert between members, shrinking the overall structure size.
4. Example
#include <stdio.h>
#include <string.h>
struct Student {
char name[20];
int rollNumber;
float marks;
};
void printStudent(const struct Student *s) {
/* arrow operator used because s is a pointer */
printf("Name: %s, Roll: %d, Marks: %.2f\n", s->name, s->rollNumber, s->marks);
}
int main(void) {
struct Student s1; /* plain struct instance */
strcpy(s1.name, "Asha"); /* dot operator for direct access */
s1.rollNumber = 101;
s1.marks = 91.5f;
printStudent(&s1); /* pass address, avoid copying the struct */
printf("sizeof(struct Student) = %zu bytes\n", sizeof(struct Student));
printf("sizeof members added = %zu bytes\n",
sizeof(s1.name) + sizeof(s1.rollNumber) + sizeof(s1.marks));
return 0;
}5. Output
Name: Asha, Roll: 101, Marks: 91.50
sizeof(struct Student) = 28 bytes
sizeof members added = 28 bytes
/* Note: exact numbers are compiler/platform dependent; padding may
make sizeof(struct Student) larger than the sum of member sizes
on some systems, especially when char/short members are mixed
with int/double members. */6. Key Takeaways
- A structure groups variables of different types under one name using the struct keyword.
- Use the dot operator (.) for direct struct instances and the arrow operator (->) for pointers to structs.
- Passing structs by pointer avoids expensive copying and allows functions to modify the original data.
- sizeof(struct) can exceed the sum of member sizes due to compiler-inserted alignment padding.
- Ordering members from largest to smallest type can reduce padding and shrink structure size.
Practice what you learned
1. Which operator is used to access a structure member through a pointer to that structure?
2. Why might sizeof(struct X) be greater than the sum of sizeof() of its individual members?
3. What is the most efficient way to pass a large structure to a function if the function only needs to read its values?
4. Given struct Point { int x; int y; }; struct Point p = {3, 4}; struct Point *ptr = &p;, which expression correctly accesses x?
5. What technique can reduce padding in a structure with mixed-size members?
Was this page helpful?
You May Also Like
Unions in C
Learn C unions: syntax, how members share the same memory, sizeof(union) rules, and the type-punning pitfall of reading a member you did not last write.
typedef in C
Understand C's typedef keyword to create readable type aliases for structs, pointers, and primitive types.
Arrays in C
Learn C arrays: 1D and 2D declarations, initialization, passing to functions, pointer decay, and out-of-bounds pitfalls with examples.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics