# Module 5 : Data Types (Struct, Enum, TypeDef) & File I/O

<span>By the end of this module, students will be able to:</span>

<span>-</span><span> Understand and implement user-defined data types using </span><span>`</span><span>struct</span><span>`</span>

<span>-</span><span> Utilize </span><span>`</span><span>enum</span><span>`</span><span> for creating readable constant sets</span>

<span>-</span><span> Apply </span><span>`</span><span>typedef</span><span>`</span><span> to create type aliases for better code readability</span>

<span>-</span><span> Perform file input/output operations in C</span>

<span>-</span><span> Handle text and binary files effectively</span>

<span>-</span><span> Design programs that persist data using files</span>

<span>-</span><span> Combine structs with file I/O for data management systems</span>

# 1. Introduction to User-Defined Data Types

### 1.1 Why User-Defined Types?

In previous modules, we learned about basic data types like `int`, `float`, `char`, etc. These are sufficient for simple programs, but real-world applications often require more complex data structures.

**Example Problem:**
Suppose you want to store information about a student:
```c
// Without user-defined types - difficult to manage
int student_id = 12345;
char student_name[50] = "Alice Johnson";
float student_gpa = 3.75;
int student_age = 20;
char student_major[30] = "Electrical Engineering";

// If you have 100 students, you need 500 variables!
```

**User-defined types solve this problem** by allowing us to group related data together.

# 2. Structures (struct)

### 2.1 What is a Structure?

A **structure** is a user-defined data type that groups variables of different types under a single name. Think of it as creating your own custom data type.

**Python vs C Comparison:**

| Python | C |
|--------|---|
| Uses classes or dictionaries | Uses `struct` |
| `student = {"name": "Alice", "age": 20}` | `struct Student student;` |
| Dynamic typing | Static typing |

### 2.2 Declaring a Structure

**Basic Syntax:**
```c
struct structure_name {
    data_type member1;
    data_type member2;
    // ... more members
};
```

**Example - Student Structure:**
```c
struct Student {
    int id;
    char name[50];
    float gpa;
    int age;
    char major[30];
};
```

**Important Notes:**
- Structure declaration ends with a semicolon `;`
- Members can be of any data type (including other structures)
- The structure declaration itself doesn't allocate memory

### 2.3 Creating Structure Variables

**Method 1: After Structure Declaration**
```c
struct Student {
    int id;
    char name[50];
    float gpa;
};

// Create variables
struct Student student1;
struct Student student2, student3;
```

**Method 2: During Structure Declaration**
```c
struct Student {
    int id;
    char name[50];
    float gpa;
} student1, student2;
```

**Method 3: Anonymous Structure (less common)**
```c
struct {
    int id;
    char name[50];
    float gpa;
} student1, student2;
```

### 2.4 Initializing Structure Variables

**Method 1: Member-by-Member Assignment**
```c
struct Student s1;
s1.id = 12345;
strcpy(s1.name, "Alice Johnson");  // Note: Use strcpy for strings
s1.gpa = 3.75;
```

**Method 2: Initialization at Declaration**
```c
struct Student s1 = {12345, "Alice Johnson", 3.75};
```

**Method 3: Designated Initializers (C99 and later)**
```c
struct Student s1 = {
    .id = 12345,
    .name = "Alice Johnson",
    .gpa = 3.75
};
```

**Method 4: Partial Initialization**
```c
struct Student s1 = {12345};  // Only id is initialized, others are 0/NULL
```

### 2.5 Accessing Structure Members

Use the **dot operator (`.`)** to access structure members:

```c
struct Student s1;

// Writing to members
s1.id = 12345;
s1.gpa = 3.75;
strcpy(s1.name, "Alice Johnson");

// Reading from members
printf("Student ID: %d\n", s1.id);
printf("Student Name: %s\n", s1.name);
printf("Student GPA: %.2f\n", s1.gpa);
```

### 2.6 Nested Structures

Structures can contain other structures as members:

```c
struct Date {
    int day;
    int month;
    int year;
};

struct Student {
    int id;
    char name[50];
    float gpa;
    struct Date birthDate;  // Nested structure
};

// Usage
struct Student s1;
s1.id = 12345;
s1.birthDate.day = 15;
s1.birthDate.month = 8;
s1.birthDate.year = 2003;

printf("Birth Date: %d/%d/%d\n", 
       s1.birthDate.day, 
       s1.birthDate.month, 
       s1.birthDate.year);
```

### 2.7 Array of Structures

You can create arrays of structures to handle multiple records:

```c
struct Student {
    int id;
    char name[50];
    float gpa;
};

// Array of 100 students
struct Student students[100];

// Accessing elements
students[0].id = 12345;
strcpy(students[0].name, "Alice");
students[0].gpa = 3.75;

// Loop through all students
for (int i = 0; i < 100; i++) {
    printf("Student %d: %s (GPA: %.2f)\n", 
           students[i].id, 
           students[i].name, 
           students[i].gpa);
}
```

### 2.8 Pointers to Structures

You can use pointers with structures:

```c
struct Student s1 = {12345, "Alice", 3.75};
struct Student *ptr = &s1;

// Method 1: Using (*ptr).member
printf("ID: %d\n", (*ptr).id);

// Method 2: Using ptr->member (preferred)
printf("ID: %d\n", ptr->id);
printf("Name: %s\n", ptr->name);
printf("GPA: %.2f\n", ptr->gpa);
```

**The Arrow Operator (`->`):**
- `ptr->member` is equivalent to `(*ptr).member`
- Much cleaner and more readable
- Commonly used when passing structures to functions

### 2.9 Structures and Functions

**Passing by Value:**
```c
void printStudent(struct Student s) {
    printf("ID: %d\n", s.id);
    printf("Name: %s\n", s.name);
    printf("GPA: %.2f\n", s.gpa);
}

// Usage
struct Student s1 = {12345, "Alice", 3.75};
printStudent(s1);  // Entire structure is copied
```

**Passing by Reference (Pointer):**
```c
void updateGPA(struct Student *s, float newGPA) {
    s->gpa = newGPA;
}

// Usage
struct Student s1 = {12345, "Alice", 3.75};
updateGPA(&s1, 3.85);  // Pass address of structure
printf("Updated GPA: %.2f\n", s1.gpa);  // Output: 3.85
```

**Returning Structures from Functions:**
```c
struct Student createStudent(int id, char *name, float gpa) {
    struct Student s;
    s.id = id;
    strcpy(s.name, name);
    s.gpa = gpa;
    return s;
}

// Usage
struct Student s1 = createStudent(12345, "Alice", 3.75);
```

### 2.10 Practical Example: Student Database

```c
#include <stdio.h>
#include <string.h>

struct Student {
    int id;
    char name[50];
    float gpa;
    int age;
};

// Function to input student data
void inputStudent(struct Student *s) {
    printf("Enter Student ID: ");
    scanf("%d", &s->id);
    
    printf("Enter Student Name: ");
    scanf(" %[^\n]", s->name);
    
    printf("Enter Student GPA: ");
    scanf("%f", &s->gpa);
    
    printf("Enter Student Age: ");
    scanf("%d", &s->age);
}

// Function to display student data
void displayStudent(struct Student s) {
    printf("\n--- Student Information ---\n");
    printf("ID: %d\n", s.id);
    printf("Name: %s\n", s.name);
    printf("GPA: %.2f\n", s.gpa);
    printf("Age: %d\n", s.age);
}

int main() {
    struct Student students[3];
    
    // Input data for 3 students
    for (int i = 0; i < 3; i++) {
        printf("\nEnter details for student %d:\n", i + 1);
        inputStudent(&students[i]);
    }
    
    // Display all students
    printf("\n\n=== All Students ===\n");
    for (int i = 0; i < 3; i++) {
        displayStudent(students[i]);
    }
    
    return 0;
}
```

# 3. Enumerations (enum)

### 3.1 What is an Enumeration?

An **enumeration** is a user-defined data type consisting of a set of named integer constants. Enums make code more readable by replacing "magic numbers" with meaningful names.

**Python vs C Comparison:**

| Python | C |
|--------|---|
| No built-in enum (uses constants) | Has `enum` keyword |
| `RED = 0; GREEN = 1; BLUE = 2` | `enum Color {RED, GREEN, BLUE};` |

### 3.2 Declaring an Enum

**Basic Syntax:**
```c
enum enum_name {
    constant1,
    constant2,
    constant3
};
```

**Example:**
```c
enum Day {
    SUNDAY,     // 0
    MONDAY,     // 1
    TUESDAY,    // 2
    WEDNESDAY,  // 3
    THURSDAY,   // 4
    FRIDAY,     // 5
    SATURDAY    // 6
};
```

**Key Points:**
- By default, the first constant is assigned value 0
- Each subsequent constant is incremented by 1
- You can explicitly assign values

### 3.3 Custom Values in Enums

```c
enum Status {
    SUCCESS = 1,
    FAILURE = 0,
    PENDING = -1
};

enum Month {
    JANUARY = 1,
    FEBRUARY,    // 2
    MARCH,       // 3
    APRIL,       // 4
    MAY,         // 5
    JUNE,        // 6
    JULY,        // 7
    AUGUST,      // 8
    SEPTEMBER,   // 9
    OCTOBER,     // 10
    NOVEMBER,    // 11
    DECEMBER     // 12
};
```

### 3.4 Using Enums

```c
#include <stdio.h>

enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, 
    THURSDAY, FRIDAY, SATURDAY
};

int main() {
    enum Day today = WEDNESDAY;
    
    printf("Today is day number: %d\n", today);  // Output: 3
    
    if (today == WEDNESDAY) {
        printf("It's the middle of the week!\n");
    }
    
    // Using enum in switch statement
    switch (today) {
        case MONDAY:
            printf("Start of work week\n");
            break;
        case FRIDAY:
            printf("TGIF!\n");
            break;
        case SATURDAY:
        case SUNDAY:
            printf("Weekend!\n");
            break;
        default:
            printf("Regular work day\n");
    }
    
    return 0;
}
```

### 3.5 Enums with Structures

Combining enums with structures creates powerful data models:

```c
enum Grade {
    GRADE_A = 90,
    GRADE_B = 80,
    GRADE_C = 70,
    GRADE_D = 60,
    GRADE_F = 0
};

enum StudentStatus {
    ACTIVE,
    GRADUATED,
    SUSPENDED,
    WITHDRAWN
};

struct Student {
    int id;
    char name[50];
    enum Grade grade;
    enum StudentStatus status;
};

int main() {
    struct Student s1 = {
        .id = 12345,
        .name = "Alice",
        .grade = GRADE_A,
        .status = ACTIVE
    };
    
    printf("Student: %s\n", s1.name);
    
    if (s1.status == ACTIVE) {
        printf("Status: Active Student\n");
    }
    
    if (s1.grade >= GRADE_B) {
        printf("Good performance!\n");
    }
    
    return 0;
}
```

### 3.6 Practical Example: Traffic Light System

```c
#include <stdio.h>

enum TrafficLight {
    RED,
    YELLOW,
    GREEN
};

void displayLightAction(enum TrafficLight light) {
    switch (light) {
        case RED:
            printf("STOP! Red light is on.\n");
            break;
        case YELLOW:
            printf("CAUTION! Yellow light is on.\n");
            break;
        case GREEN:
            printf("GO! Green light is on.\n");
            break;
        default:
            printf("Invalid light state.\n");
    }
}

int main() {
    enum TrafficLight currentLight = RED;
    
    printf("Traffic Light Simulation:\n\n");
    
    for (int i = 0; i < 3; i++) {
        displayLightAction(currentLight);
        
        // Cycle through lights
        if (currentLight == RED) {
            currentLight = GREEN;
        } else if (currentLight == GREEN) {
            currentLight = YELLOW;
        } else {
            currentLight = RED;
        }
        
        printf("Waiting...\n\n");
    }
    
    return 0;
}
```

# 4. Type Definitions (typedef)

### 4.1 What is typedef?

**`typedef`** creates aliases (alternative names) for existing data types. It makes code more readable and easier to maintain.

**Basic Syntax:**
```c
typedef existing_type new_name;
```

### 4.2 typedef with Basic Types

```c
// Create aliases for basic types
typedef int Integer;
typedef float Real;
typedef char Character;

// Usage
Integer age = 25;
Real temperature = 36.5;
Character grade = 'A';
```

### 4.3 typedef with Structures

**Without typedef:**
```c
struct Student {
    int id;
    char name[50];
    float gpa;
};

// Must always use "struct Student"
struct Student s1;
struct Student students[100];
```

**With typedef - Method 1:**
```c
struct Student {
    int id;
    char name[50];
    float gpa;
};

typedef struct Student Student;

// Now can use just "Student"
Student s1;
Student students[100];
```

**With typedef - Method 2 (Combined):**
```c
typedef struct Student {
    int id;
    char name[50];
    float gpa;
} Student;

// Usage
Student s1;
Student students[100];
```

**With typedef - Method 3 (Anonymous struct):**
```c
typedef struct {
    int id;
    char name[50];
    float gpa;
} Student;

// Usage
Student s1;
```

### 4.4 typedef with Enums

```c
typedef enum {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
} Day;

// Usage
Day today = WEDNESDAY;
Day weekend[2] = {SATURDAY, SUNDAY};
```

### 4.5 typedef with Pointers

```c
typedef int* IntPtr;
typedef struct Student* StudentPtr;

// Usage
IntPtr p1, p2;  // Both are int pointers
StudentPtr sptr;  // Student pointer
```

### 4.6 typedef with Arrays

```c
typedef int IntArray[10];
typedef char String[100];

// Usage
IntArray numbers;  // Same as: int numbers[10];
String name;       // Same as: char name[100];
```

### 4.7 Practical Example: Complex Data Types

```c
#include <stdio.h>
#include <string.h>

// Define enumeration for course grades
typedef enum {
    GRADE_A = 4,
    GRADE_B = 3,
    GRADE_C = 2,
    GRADE_D = 1,
    GRADE_F = 0
} Grade;

// Define structure for a course
typedef struct {
    char code[10];
    char name[50];
    int credits;
    Grade grade;
} Course;

// Define structure for a student
typedef struct {
    int id;
    char name[50];
    Course courses[5];
    int numCourses;
    float gpa;
} Student;

// Function to calculate GPA
float calculateGPA(Student *s) {
    int totalCredits = 0;
    float totalPoints = 0.0;
    
    for (int i = 0; i < s->numCourses; i++) {
        totalCredits += s->courses[i].credits;
        totalPoints += s->courses[i].credits * s->courses[i].grade;
    }
    
    if (totalCredits == 0) return 0.0;
    return totalPoints / totalCredits;
}

int main() {
    Student student = {
        .id = 12345,
        .name = "Alice Johnson",
        .numCourses = 3
    };
    
    // Add courses
    strcpy(student.courses[0].code, "EE101");
    strcpy(student.courses[0].name, "Circuit Analysis");
    student.courses[0].credits = 3;
    student.courses[0].grade = GRADE_A;
    
    strcpy(student.courses[1].code, "MATH201");
    strcpy(student.courses[1].name, "Calculus II");
    student.courses[1].credits = 4;
    student.courses[1].grade = GRADE_B;
    
    strcpy(student.courses[2].code, "CS101");
    strcpy(student.courses[2].name, "Programming");
    student.courses[2].credits = 3;
    student.courses[2].grade = GRADE_A;
    
    // Calculate and display GPA
    student.gpa = calculateGPA(&student);
    
    printf("Student: %s (ID: %d)\n", student.name, student.id);
    printf("GPA: %.2f\n\n", student.gpa);
    
    printf("Courses:\n");
    for (int i = 0; i < student.numCourses; i++) {
        printf("  %s - %s (%d credits): Grade %d\n",
               student.courses[i].code,
               student.courses[i].name,
               student.courses[i].credits,
               student.courses[i].grade);
    }
    
    return 0;
}
```

# 5. File Input/Output

### 5.1 Why File I/O?

So far, all our programs lose their data when they terminate. **File I/O** allows programs to:
- Save data permanently
- Read data from external sources
- Create logs and reports
- Share data between programs

**Python vs C File Operations:**

| Python | C |
|--------|---|
| `f = open("file.txt", "r")` | `FILE *f = fopen("file.txt", "r");` |
| `f.write("text")` | `fprintf(f, "text");` |
| `content = f.read()` | `fscanf(f, "%s", buffer);` |
| `f.close()` | `fclose(f);` |

### 5.2 File Pointer

In C, files are accessed through **file pointers** of type `FILE*`:

```c
FILE *filePointer;
```

The `FILE` type is defined in `<stdio.h>`.

### 5.3 Opening Files - fopen()

**Function Signature:**
```c
FILE *fopen(const char *filename, const char *mode);
```

**File Opening Modes:**

| Mode | Description | If File Exists | If File Doesn't Exist |
|------|-------------|----------------|----------------------|
| `"r"` | Read only | Opens file | Returns NULL |
| `"w"` | Write only | Overwrites content | Creates new file |
| `"a"` | Append | Appends to end | Creates new file |
| `"r+"` | Read and write | Opens file | Returns NULL |
| `"w+"` | Read and write | Overwrites content | Creates new file |
| `"a+"` | Read and append | Opens file | Creates new file |
| `"rb"` | Read binary | Opens file | Returns NULL |
| `"wb"` | Write binary | Overwrites content | Creates new file |
| `"ab"` | Append binary | Appends to end | Creates new file |

**Example:**
```c
FILE *file;

// Open file for reading
file = fopen("data.txt", "r");

// Always check if file opened successfully
if (file == NULL) {
    printf("Error: Could not open file!\n");
    return 1;
}

// ... file operations ...

fclose(file);
```

### 5.4 Closing Files - fclose()

**Always close files after use** to:
- Free system resources
- Ensure all data is written to disk
- Prevent data corruption

```c
int fclose(FILE *filePointer);
```

**Returns:**
- `0` on success
- `EOF` on error

**Example:**
```c
FILE *file = fopen("data.txt", "r");
if (file != NULL) {
    // ... operations ...
    fclose(file);
}
```

### 5.5 Reading from Text Files

#### 5.5.1 fscanf() - Formatted Input

Similar to `scanf()`, but reads from a file:

```c
int fscanf(FILE *stream, const char *format, ...);
```

**Example:**
```c
FILE *file = fopen("numbers.txt", "r");
if (file == NULL) {
    printf("Error opening file!\n");
    return 1;
}

int num;
while (fscanf(file, "%d", &num) == 1) {
    printf("Read: %d\n", num);
}

fclose(file);
```

#### 5.5.2 fgets() - Line Input

Reads a line from a file:

```c
char *fgets(char *str, int n, FILE *stream);
```

**Example:**
```c
FILE *file = fopen("text.txt", "r");
if (file == NULL) {
    printf("Error opening file!\n");
    return 1;
}

char line[256];
while (fgets(line, sizeof(line), file) != NULL) {
    printf("%s", line);
}

fclose(file);
```

#### 5.5.3 fgetc() - Character Input

Reads a single character:

```c
int fgetc(FILE *stream);
```

**Example:**
```c
FILE *file = fopen("text.txt", "r");
if (file == NULL) {
    printf("Error opening file!\n");
    return 1;
}

int ch;
while ((ch = fgetc(file)) != EOF) {
    putchar(ch);
}

fclose(file);
```

### 5.6 Writing to Text Files

#### 5.6.1 fprintf() - Formatted Output

Similar to `printf()`, but writes to a file:

```c
int fprintf(FILE *stream, const char *format, ...);
```

**Example:**
```c
FILE *file = fopen("output.txt", "w");
if (file == NULL) {
    printf("Error opening file!\n");
    return 1;
}

fprintf(file, "Student ID: %d\n", 12345);
fprintf(file, "Name: %s\n", "Alice Johnson");
fprintf(file, "GPA: %.2f\n", 3.75);

fclose(file);
```

#### 5.6.2 fputs() - String Output

Writes a string to a file:

```c
int fputs(const char *str, FILE *stream);
```

**Example:**
```c
FILE *file = fopen("output.txt", "w");
if (file == NULL) {
    printf("Error opening file!\n");
    return 1;
}

fputs("Hello, World!\n", file);
fputs("This is a test.\n", file);

fclose(file);
```

#### 5.6.3 fputc() - Character Output

Writes a single character:

```c
int fputc(int char, FILE *stream);
```

**Example:**
```c
FILE *file = fopen("output.txt", "w");
if (file == NULL) {
    printf("Error opening file!\n");
    return 1;
}

for (char ch = 'A'; ch <= 'Z'; ch++) {
    fputc(ch, file);
}

fclose(file);
```

### 5.7 File Position Functions

#### 5.7.1 fseek() - Move File Pointer

```c
int fseek(FILE *stream, long offset, int origin);
```

**Origin values:**
- `SEEK_SET` - Beginning of file
- `SEEK_CUR` - Current position
- `SEEK_END` - End of file

**Example:**
```c
FILE *file = fopen("data.txt", "r");

// Move to beginning
fseek(file, 0, SEEK_SET);

// Move 10 bytes from current position
fseek(file, 10, SEEK_CUR);

// Move to end of file
fseek(file, 0, SEEK_END);
```

#### 5.7.2 ftell() - Get Current Position

```c
long ftell(FILE *stream);
```

**Example:**
```c
FILE *file = fopen("data.txt", "r");
long position = ftell(file);
printf("Current position: %ld\n", position);
```

#### 5.7.3 rewind() - Reset to Beginning

```c
void rewind(FILE *stream);
```

**Example:**
```c
FILE *file = fopen("data.txt", "r");

// Read some data...

rewind(file);  // Go back to beginning
```

### 5.8 Checking End of File - feof()

```c
int feof(FILE *stream);
```

**Returns non-zero if end of file is reached.**

**Example:**
```c
FILE *file = fopen("data.txt", "r");
char ch;

while (!feof(file)) {
    ch = fgetc(file);
    if (ch != EOF) {
        putchar(ch);
    }
}

fclose(file);
```

### 5.9 Practical Example: Student Records Manager

```c
#include <stdio.h>
#include <string.h>

typedef struct {
    int id;
    char name[50];
    float gpa;
    int age;
} Student;

// Save student to file
void saveStudent(const char *filename, Student s) {
    FILE *file = fopen(filename, "a");  // Append mode
    if (file == NULL) {
        printf("Error opening file!\n");
        return;
    }
    
    fprintf(file, "%d,%s,%.2f,%d\n", s.id, s.name, s.gpa, s.age);
    fclose(file);
    
    printf("Student record saved successfully!\n");
}

// Load all students from file
void loadStudents(const char *filename) {
    FILE *file = fopen(filename, "r");
    if (file == NULL) {
        printf("No records found!\n");
        return;
    }
    
    Student s;
    printf("\n=== Student Records ===\n");
    
    while (fscanf(file, "%d,%49[^,],%f,%d\n", 
                  &s.id, s.name, &s.gpa, &s.age) == 4) {
        printf("ID: %d | Name: %s | GPA: %.2f | Age: %d\n",
               s.id, s.name, s.gpa, s.age);
    }
    
    fclose(file);
}

// Search for student by ID
int searchStudent(const char *filename, int searchID) {
    FILE *file = fopen(filename, "r");
    if (file == NULL) {
        printf("Error opening file!\n");
        return 0;
    }
    
    Student s;
    while (fscanf(file, "%d,%49[^,],%f,%d\n", 
                  &s.id, s.name, &s.gpa, &s.age) == 4) {
        if (s.id == searchID) {
            printf("\n--- Student Found ---\n");
            printf("ID: %d\n", s.id);
            printf("Name: %s\n", s.name);
            printf("GPA: %.2f\n", s.gpa);
            printf("Age: %d\n", s.age);
            fclose(file);
            return 1;
        }
    }
    
    fclose(file);
    printf("Student not found!\n");
    return 0;
}

int main() {
    int choice;
    Student s;
    
    do {
        printf("\n=== Student Management System ===\n");
        printf("1. Add Student\n");
        printf("2. View All Students\n");
        printf("3. Search Student by ID\n");
        printf("4. Exit\n");
        printf("Enter choice: ");
        scanf("%d", &choice);
        
        switch (choice) {
            case 1:
                printf("\nEnter Student ID: ");
                scanf("%d", &s.id);
                
                printf("Enter Student Name: ");
                scanf(" %[^\n]", s.name);
                
                printf("Enter Student GPA: ");
                scanf("%f", &s.gpa);
                
                printf("Enter Student Age: ");
                scanf("%d", &s.age);
                
                saveStudent("students.txt", s);
                break;
                
            case 2:
                loadStudents("students.txt");
                break;
                
            case 3: {
                int searchID;
                printf("\nEnter Student ID to search: ");
                scanf("%d", &searchID);
                searchStudent("students.txt", searchID);
                break;
            }
                
            case 4:
                printf("Exiting program...\n");
                break;
                
            default:
                printf("Invalid choice!\n");
        }
    } while (choice != 4);
    
    return 0;
}
```

### 5.10 Binary File Operations

Binary files store data in raw binary format, which is more efficient for storing structures.

#### 5.10.1 Writing Binary Data - fwrite()

```c
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
```

**Parameters:**
- `ptr` - Pointer to data to write
- `size` - Size of each element
- `nmemb` - Number of elements
- `stream` - File pointer

**Example:**
```c
typedef struct {
    int id;
    char name[50];
    float gpa;
} Student;

Student s = {12345, "Alice Johnson", 3.75};

FILE *file = fopen("students.dat", "wb");
if (file != NULL) {
    fwrite(&s, sizeof(Student), 1, file);
    fclose(file);
}
```

#### 5.10.2 Reading Binary Data - fread()

```c
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
```

**Parameters:**
- `ptr` - Pointer to memory where data will be stored
- `size` - Size of each element
- `nmemb` - Number of elements
- `stream` - File pointer

**Example:**
```c
Student s;

FILE *file = fopen("students.dat", "rb");
if (file != NULL) {
    while (fread(&s, sizeof(Student), 1, file) == 1) {
        printf("ID: %d, Name: %s, GPA: %.2f\n", 
               s.id, s.name, s.gpa);
    }
    fclose(file);
}
```

#### 5.10.3 Binary vs Text Files

| Aspect | Text Files | Binary Files |
|--------|-----------|--------------|
| **Human Readable** | Yes | No |
| **Size** | Larger | Smaller |
| **Speed** | Slower | Faster |
| **Portability** | More portable | Less portable |
| **Precision** | May lose precision | Full precision |
| **Best for** | Configuration files, logs | Large data, structures |

### 5.11 Complete Binary File Example

```c
#include <stdio.h>
#include <string.h>

typedef struct {
    int id;
    char name[50];
    float gpa;
    int age;
} Student;

// Save student to binary file
void saveStudentBinary(const char *filename, Student s) {
    FILE *file = fopen(filename, "ab");  // Append binary
    if (file == NULL) {
        printf("Error opening file!\n");
        return;
    }
    
    fwrite(&s, sizeof(Student), 1, file);
    fclose(file);
    
    printf("Student saved to binary file!\n");
}

// Load all students from binary file
void loadStudentsBinary(const char *filename) {
    FILE *file = fopen(filename, "rb");  // Read binary
    if (file == NULL) {
        printf("No records found!\n");
        return;
    }
    
    Student s;
    printf("\n=== Student Records (Binary) ===\n");
    
    while (fread(&s, sizeof(Student), 1, file) == 1) {
        printf("ID: %d | Name: %s | GPA: %.2f | Age: %d\n",
               s.id, s.name, s.gpa, s.age);
    }
    
    fclose(file);
}

// Count number of records in binary file
int countRecords(const char *filename) {
    FILE *file = fopen(filename, "rb");
    if (file == NULL) {
        return 0;
    }
    
    // Seek to end of file
    fseek(file, 0, SEEK_END);
    
    // Get file size
    long fileSize = ftell(file);
    
    fclose(file);
    
    // Calculate number of records
    return fileSize / sizeof(Student);
}

// Update student record by ID
int updateStudent(const char *filename, int id, Student newData) {
    FILE *file = fopen(filename, "rb+");  // Read and write binary
    if (file == NULL) {
        printf("Error opening file!\n");
        return 0;
    }
    
    Student s;
    int found = 0;
    long position = 0;
    
    // Search for student
    while (fread(&s, sizeof(Student), 1, file) == 1) {
        if (s.id == id) {
            // Move back to the position of this record
            fseek(file, position, SEEK_SET);
            
            // Write updated data
            fwrite(&newData, sizeof(Student), 1, file);
            
            found = 1;
            printf("Student record updated!\n");
            break;
        }
        position = ftell(file);
    }
    
    fclose(file);
    
    if (!found) {
        printf("Student ID %d not found!\n", id);
    }
    
    return found;
}

// Delete student record by ID
int deleteStudent(const char *filename, int id) {
    FILE *file = fopen(filename, "rb");
    FILE *temp = fopen("temp.dat", "wb");
    
    if (file == NULL || temp == NULL) {
        printf("Error opening files!\n");
        return 0;
    }
    
    Student s;
    int found = 0;
    
    // Copy all records except the one to delete
    while (fread(&s, sizeof(Student), 1, file) == 1) {
        if (s.id == id) {
            found = 1;
            continue;  // Skip this record
        }
        fwrite(&s, sizeof(Student), 1, temp);
    }
    
    fclose(file);
    fclose(temp);
    
    // Replace original file with temp file
    remove(filename);
    rename("temp.dat", filename);
    
    if (found) {
        printf("Student record deleted!\n");
    } else {
        printf("Student ID %d not found!\n", id);
    }
    
    return found;
}

int main() {
    int choice;
    Student s;
    
    do {
        printf("\n=== Student Management System (Binary Files) ===\n");
        printf("1. Add Student\n");
        printf("2. View All Students\n");
        printf("3. Count Records\n");
        printf("4. Update Student\n");
        printf("5. Delete Student\n");
        printf("6. Exit\n");
        printf("Enter choice: ");
        scanf("%d", &choice);
        
        switch (choice) {
            case 1:
                printf("\nEnter Student ID: ");
                scanf("%d", &s.id);
                
                printf("Enter Student Name: ");
                scanf(" %[^\n]", s.name);
                
                printf("Enter Student GPA: ");
                scanf("%f", &s.gpa);
                
                printf("Enter Student Age: ");
                scanf("%d", &s.age);
                
                saveStudentBinary("students.dat", s);
                break;
                
            case 2:
                loadStudentsBinary("students.dat");
                break;
                
            case 3: {
                int count = countRecords("students.dat");
                printf("\nTotal records: %d\n", count);
                break;
            }
                
            case 4: {
                int updateID;
                printf("\nEnter Student ID to update: ");
                scanf("%d", &updateID);
                
                printf("Enter new Student Name: ");
                scanf(" %[^\n]", s.name);
                
                printf("Enter new Student GPA: ");
                scanf("%f", &s.gpa);
                
                printf("Enter new Student Age: ");
                scanf("%d", &s.age);
                
                s.id = updateID;
                updateStudent("students.dat", updateID, s);
                break;
            }
                
            case 5: {
                int deleteID;
                printf("\nEnter Student ID to delete: ");
                scanf("%d", &deleteID);
                deleteStudent("students.dat", deleteID);
                break;
            }
                
            case 6:
                printf("Exiting program...\n");
                break;
                
            default:
                printf("Invalid choice!\n");
        }
    } while (choice != 6);
    
    return 0;
}
```