A structure is a user-defined data type that groups together variables of different data types under a single name. While an array holds many elements of the *same* type, a structure can hold an int, a float, and a char array all in one unit.
You define a structure using the struct keyword. To access its "members" (the variables inside), you use the dot operator (.).
// 1. Definition of the structure
struct Student {
int rollNo;
char name[50];
float marks;
};
int main() {
// 2. Declaration of a structure variable
struct Student s1;
// 3. Processing: Accessing and assigning members
s1.rollNo = 101;
strcpy(s1.name, "Rohan"); // Use strcpy for strings
s1.marks = 92.5;
// Accessing and printing
printf("Roll No: %d\n", s1.rollNo);
printf("Name: %s\n", s1.name);
return 0;
}
The typedef keyword creates an alias or a new name for an existing data type. It's most often used with structures to avoid writing struct Student every time.
// Define the struct AND create a typedef
typedef struct Student {
int rollNo;
char name[50];
float marks;
} Student_t; // 'Student_t' is now an alias
int main() {
// Now you can just write 'Student_t'
Student_t s1;
s1.rollNo = 101;
return 0;
}
You can create a pointer to a structure just like any other variable.
To access members using a structure variable, use the dot operator (.).
To access members using a structure pointer, use the arrow operator (->).
Student_t s1;
Student_t *ptr; // 'ptr' is a pointer to a Student_t
ptr = &s1; // 'ptr' holds the address of 's1'
// These two lines are now equivalent:
s1.rollNo = 101;
ptr->rollNo = 101; // (*ptr).rollNo is the same
printf("Roll No: %d\n", ptr->rollNo);
Passing large structures to functions by value (making a copy) is inefficient. It's almost always better to pass a pointer to the structure.
// This function takes a POINTER to a Student_t
void displayStudent(Student_t *s) {
printf("Roll: %d\n", s->rollNo); // Use ->
printf("Name: %s\n", s->name);
}
int main() {
Student_t s1 = {101, "Rohan", 92.5};
// Pass the ADDRESS of s1
displayStudent(&s1);
return 0;
}
You can create an array where each element is a complete structure. This is perfect for storing records, like a class full of students.
// Creates an array to hold 60 students Student_t cseClass[60]; // Access student at index 5 cseClass[5].rollNo = 106; strcpy(cseClass[5].name, "Anita"); // Access with pointers Student_t *ptr = cseClass; // Points to cseClass[0] (ptr + 5)->rollNo = 106; // Same as above
A self-referential structure is a structure that contains a pointer to itself (i.e., a pointer to another structure of the same type).
This concept is the fundamental building block for all dynamic data structures like Linked Lists and Trees.
// A node in a linked list
typedef struct Node {
int data;
struct Node *next; // Pointer to another 'Node'
} Node_t;
"Table lookup" is a programming technique, not a C feature. It involves searching for a value in a table (often an array of structures) to find its corresponding data.
// Example: A table to look up error codes
struct ErrorCode {
int code;
char *message;
};
struct ErrorCode errorTable[] = {
{100, "File Not Found"},
{200, "Access Denied"},
{300, "Disk Full"}
};
// Function to "look up" a code
char* lookup(int code) {
for (int i = 0; i < 3; i++) {
if (errorTable[i].code == code) {
return errorTable[i].message;
}
}
return "Unknown Error";
}
A union is like a structure, but all its members share the same memory location.
The size of a union is the size of its largest member. You can only use *one* member at a time. This is used to save memory when you know you will only need one of several possible values at any given time.
typedef union Data {
int i;
float f;
char c;
} Data_t;
int main() {
Data_t val;
// Size of 'val' will be 4 bytes (size of largest: float)
val.i = 10;
printf("Int: %d\n", val.i); // Prints 10
val.f = 3.14;
printf("Float: %f\n", val.f); // Prints 3.14
// The integer value is now GONE (corrupted)
printf("Int: %d\n", val.i); // Prints garbage
}