Unit 4: Structures and Unions

Table of Contents

1. Structures (struct)

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.

Basics and Processing

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;
}

User Defined Data Types (typedef)

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;
}

2. Structures with Pointers and Functions

Structures and Pointers

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);

Structures and Functions

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;
}

3. Advanced Structures

Arrays of Structures

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

Self-referential Structures

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

"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";
}

4. Unions (union)

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
}
Struct vs. Union:
  • Struct: All members exist simultaneously. Size is (at least) the *sum* of member sizes.
  • Union: Only *one* member can be used at a time. Size is the size of the *largest* member.