0% found this document useful (0 votes)
31 views24 pages

Capstone Project For Lab1

This capstone project transitions students from basic coding to system building by focusing on system design, problem decomposition, and professional development habits. Students will create a Grade Book System that incorporates data structures, user interfaces, and real-world software engineering principles, while also preparing them for advanced topics in computer science. The project emphasizes practical skills such as memory management, error handling, and user empathy, ultimately fostering confidence and professional readiness in software development.

Uploaded by

iniademola21
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
31 views24 pages

Capstone Project For Lab1

This capstone project transitions students from basic coding to system building by focusing on system design, problem decomposition, and professional development habits. Students will create a Grade Book System that incorporates data structures, user interfaces, and real-world software engineering principles, while also preparing them for advanced topics in computer science. The project emphasizes practical skills such as memory management, error handling, and user empathy, ultimately fostering confidence and professional readiness in software development.

Uploaded by

iniademola21
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

This capstone project transforms students from "code writers" into "system builders" - they're not

just learning syntax anymore, they're architecting solutions!

Advanced Learning Outcomes:


System Design Thinking

Students learn to think about:

 Data relationships (how Student connects to GradeBook)


 Program flow (initialization → operation → cleanup)
 User interaction patterns (menu-driven interfaces)
 Resource management (memory allocation lifecycle)

Problem Decomposition

The project teaches students to break complex problems into manageable pieces:

Grade Book System


├── Data Structures (Student, GradeBook)
├── Core Operations (add, search, display)
├── Calculations (averages, statistics)
├── User Interface (menus, input validation)
└── Memory Management (allocation, cleanup)

Professional Development Habits

 Documentation mindset (comments explain the "why," not just "what")


 Testing through use (interactive menu allows thorough testing)
 Error anticipation (what could go wrong at each step?)
 User empathy (helpful error messages, clear interfaces)

Extension Opportunities for Advanced Students:


Level 1: Enhanced Features
// Add grade weighting
typedef struct {
float* scores;
float* weights; // Each test can have different importance
char** test_names; // "Midterm", "Final", "Quiz 1", etc.
} WeightedGrades;

// Add grade history tracking


typedef struct {
Student* previous_versions;
int version_count;
time_t last_modified;
} StudentHistory;

Level 2: File Persistence


// Save gradebook to file
void save_gradebook(const GradeBook* gb, const char* filename);

// Load gradebook from file


int load_gradebook(GradeBook* gb, const char* filename);

// Export to CSV for spreadsheet programs


void export_to_csv(const GradeBook* gb, const char* filename);

Level 3: Advanced Data Structures


// Binary search tree for faster student lookup
typedef struct StudentNode {
Student data;
struct StudentNode* left;
struct StudentNode* right;
} StudentNode;

// Hash table for O(1) student lookup


typedef struct {
Student** buckets;
int bucket_count;
int (*hash_function)(const char* name);
} StudentHashTable;

Real-World Industry Connections:


Database Concepts

This project introduces fundamental database operations:

 CREATE (add_student)
 READ (display_student, print_gradebook)
 UPDATE (modify scores - potential extension)
 DELETE (remove student - potential extension)

Software Engineering Principles

 Modularity: Each function has a single, clear purpose


 Encapsulation: Data and operations are grouped logically
 Abstraction: Complex operations hidden behind simple interfaces
 Maintainability: Code is organized and documented for future changes

User Interface Design


 Consistency: All menu options follow the same pattern
 Feedback: User always knows what happened and what to do next
 Error Prevention: Validation prevents invalid states
 Discoverability: Help text guides users to valid options

Assessment and Learning Verification:


Formative Assessment During Development
// Students can add debug prints to verify their understanding
void debug_print_student(const Student* s) {
printf("DEBUG: Student at %p\n", (void*)s);
printf(" Name: '%s'\n", s->name);
printf(" Scores pointer: %p\n", (void*)s->scores);
printf(" Number of scores: %d\n", s->num_scores);
// This helps students visualize memory and pointers
}

Comprehensive Testing Through Use

The interactive menu system serves as a built-in testing framework:

 Students can test edge cases (empty gradebook, invalid input)


 Immediate feedback reveals logic errors
 Memory leaks become apparent through repeated operations

Code Review Learning

Students can peer-review each other's implementations:

 "How did you handle the case where malloc() fails?"


 "What happens if a user enters a negative number of scores?"
 "Did you remember to free all allocated memory?"

Transition to Advanced Topics:


Preparing for Data Structures Course

This project provides concrete experience with:

 Dynamic memory management (foundation for linked lists, trees)


 Structure composition (preparation for complex data structures)
 Algorithm analysis (search efficiency, space-time tradeoffs)

Preparing for Software Engineering


Students gain experience with:

 Requirements analysis (what should a gradebook do?)


 Design patterns (menu-driven interface, data validation)
 Testing strategies (boundary conditions, error cases)
 Documentation practices (code comments, user instructions)

Preparing for Database Systems

Concepts directly transferable to databases:

 Entity modeling (Student entity with attributes)


 Relationships (Student belongs to GradeBook)
 Queries (find student by name, calculate statistics)
 Integrity constraints (valid score ranges, non-null names)

Industry Skills Development:


Technical Skills

 Memory management (critical for systems programming)


 Data validation (essential for secure applications)
 Error handling (required for production software)
 Modular design (foundation of maintainable code)

Soft Skills

 Problem decomposition (breaking complex problems into parts)


 User empathy (designing interfaces that make sense)
 Attention to detail (catching edge cases and potential failures)
 Documentation (explaining complex systems clearly)

Long-Term Educational Impact:


Confidence Building

Students who complete this project successfully gain confidence that they can:

 Build complete, working systems (not just isolated functions)


 Handle complex data relationships
 Create user-friendly interfaces
 Manage system resources responsibly

Professional Readiness
This project bridges the gap between academic exercises and professional development:

 Scale: Substantial enough to require planning and organization


 Complexity: Multiple interacting components require systems thinking
 Quality: Professional-level error handling and user experience
 Maintenance: Code is organized for future modification and extension

The Ultimate Learning Outcome:


By the end of this project, students have transformed from beginners who think "programming is
about syntax" to developers who understand that programming is about solving problems
systematically, safely, and user-effectively.

They've experienced the full software development lifecycle in miniature:

1. Requirements gathering (what should a gradebook do?)


2. System design (how to structure the data and operations?)
3. Implementation (writing the actual code)
4. Testing (using the interactive interface to verify functionality)
5. Documentation (comments and user instructions)
6. Maintenance preparation (clean, modular code for future changes)

This foundation prepares them not just for advanced computer science courses, but for thinking
like professional software developers who build reliable, maintainable, user-focused systems.

The grade book system isn't just a programming exercise—it's a gateway to professional
software development thinking!

Grade Book System - Complete Project


Explained for Beginners
Project Overview - What We're Building
Imagine you're a teacher who needs to:

 Keep track of student names and test scores


 Calculate averages automatically
 Assign letter grades
 Generate reports
 Search for specific students

This program does all of that! It's like building a digital gradebook from scratch.
Setting Up Our Project Foundation
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

Our toolkit:

 stdio.h = Input/output (printf, scanf)


 stdlib.h = Memory management (malloc, free)
 string.h = String functions (strcpy, strcmp)

Project Constants - Setting the Rules


#define MAX_STUDENTS 50
#define MAX_NAME_LENGTH 50
#define MAX_SCORES 10

What #define means:

 Creates a constant that never changes


 Wherever we write MAX_STUDENTS, compiler replaces it with 50
 Like making a rule: "This class can have maximum 50 students"

Why use constants instead of numbers?

// ❌ BAD - Magic numbers scattered everywhere


char names[50][50];
if(student_count >= 50) { ... }
for(int i = 0; i < 50; i++) { ... }

// ✅ GOOD - One place to change the limit


char names[MAX_STUDENTS][MAX_NAME_LENGTH];
if(student_count >= MAX_STUDENTS) { ... }
for(int i = 0; i < MAX_STUDENTS; i++) { ... }

Benefits:

 Easy to change limits (just change one number)


 Code is more readable
 Less chance of errors

Building Our Data Structures


Student Structure - The Individual Record
typedef struct {
char name[MAX_NAME_LENGTH];
int num_scores;
float* scores; // Dynamic array for flexibility
float average;
char letter_grade;
} Student;

Breaking down typedef struct:

 typedef = "Type definition" - creates a new data type


 struct = Bundle multiple variables together
 Student = Our new type name (like int or float)

What each field stores:

char name[MAX_NAME_LENGTH];

 Array to store student's name


 50 characters maximum (including null terminator)
 Like a name tag with space for 49 letters

int num_scores;

 How many test scores this student has


 Different students might have different numbers of tests

float* scores;

 Pointer to dynamic array of test scores


 Why pointer? We don't know how many scores each student will have
 We'll allocate memory based on num_scores

float average;

 Calculated average of all scores


 We compute this automatically

char letter_grade;

 Letter grade ('A', 'B', 'C', 'D', 'F')


 Based on the numerical average

Visual representation of a Student:

Student: John Smith


┌─────────────────┬─────────────┬──────────────┬─────────┬──────────────┐
│ name[50] │ num_scores │ scores* │ average │ letter_grade │
│ "John Smith" │ 3 │ ──→[85,92,78]│ 85.0 │ 'B' │
└─────────────────┴─────────────┴──────────────┴─────────┴──────────────┘

GradeBook Structure - The Container


typedef struct {
Student students[MAX_STUDENTS];
int num_students;
char class_name[100];
} GradeBook;

What this creates:

 students[MAX_STUDENTS] = Array of 50 Student records


 num_students = How many students we actually have (0-50)
 class_name[100] = Name of the class ("Math 101", "English", etc.)

Visual representation:

GradeBook: Math 101


┌─────────────────────────────────────┬─────────────┬─────────────────┐
│ students[50] │ num_students│ class_name[100] │
│ [Student0][Student1]...[Student49] │ 3 │ "Math 101" │
│ (only first 3 are used) │ │ │
└─────────────────────────────────────┴─────────────┴─────────────────┘

Initializing Our Grade Book


void initialize_gradebook(GradeBook* gb, const char* class_name) {

Function signature breakdown:

 void = Doesn't return anything


 GradeBook* gb = Pointer to a GradeBook (so we can modify it)
 const char* class_name = Pointer to class name string (const = won't be changed)

Safety First - Input Validation


if(gb == NULL || class_name == NULL) {
printf("Error: Invalid parameters for gradebook initialization!\n");
return;
}

Defensive programming:

 Always check if pointers are NULL before using them


 || means "OR" - if either condition is true, show error
 return; exits the function early if there's a problem

Setting Up Basic Information


gb->num_students = 0;
strcpy(gb->class_name, class_name);

Line 1: gb->num_students = 0;

 Start with zero students


 gb-> means "access the field inside the structure that gb points to"

Line 2: strcpy(gb->class_name, class_name);

 Copy the class name into our gradebook


 strcpy = "string copy" (from string.h)
 Copies characters from class_name to gb->class_name

Initializing All Student Records


for(int i = 0; i < MAX_STUDENTS; i++) {
strcpy(gb->students[i].name, "");
gb->students[i].num_scores = 0;
gb->students[i].scores = NULL;
gb->students[i].average = 0.0;
gb->students[i].letter_grade = 'F';
}

Why initialize everything?

 Uninitialized memory contains garbage values


 Better to start with known, safe values
 Prevents bugs from unexpected data

What each line does:

1. strcpy(gb->students[i].name, ""); = Set name to empty string


2. gb->students[i].num_scores = 0; = No scores yet
3. gb->students[i].scores = NULL; = No memory allocated yet
4. gb->students[i].average = 0.0; = Start with zero average
5. gb->students[i].letter_grade = 'F'; = Default to F grade

Helper Functions - The Building Blocks


Converting Numbers to Letter Grades
char calculate_letter_grade(float average) {
if(average >= 90.0) return 'A';
else if(average >= 80.0) return 'B';
else if(average >= 70.0) return 'C';
else if(average >= 60.0) return 'D';
else return 'F';
}

Standard grading scale:

 A: 90-100
 B: 80-89
 C: 70-79
 D: 60-69
 F: Below 60

How the logic works:

 Checks conditions from highest to lowest


 First condition that's true determines the grade
 Example: 85.5 → Not ≥90, but ≥80, so returns 'B'

Calculating Averages
float calculate_average(float* scores, int num_scores) {
if(scores == NULL || num_scores <= 0) {
return 0.0;
}

float sum = 0.0;


for(int i = 0; i < num_scores; i++) {
sum += scores[i];
}

return sum / num_scores;


}

Safety checking:

if(scores == NULL || num_scores <= 0) {


return 0.0;
}

 Check if pointer is NULL (no scores array)


 Check if number of scores is invalid (zero or negative)
 Return 0.0 as safe default

The calculation:
float sum = 0.0;
for(int i = 0; i < num_scores; i++) {
sum += scores[i];
}
return sum / num_scores;

Example with scores [85, 92, 78]:

1. sum = 0.0
2. i=0: sum = 0.0 + 85 = 85.0
3. i=1: sum = 85.0 + 92 = 177.0
4. i=2: sum = 177.0 + 78 = 255.0
5. Return 255.0 / 3 = 85.0

Adding Students - The Core Function


void add_student(GradeBook* gb, const char* name, int num_scores) {

This is our most complex function - it does everything needed to add a new student!

Comprehensive Input Validation


// Input validation
if(gb == NULL || name == NULL) {
printf("Error: Invalid parameters!\n");
return;
}

if(gb->num_students >= MAX_STUDENTS) {


printf("Error: Grade book is full! Cannot add more students.\n");
printf("Maximum capacity: %d students\n", MAX_STUDENTS);
return;
}

if(num_scores <= 0 || num_scores > MAX_SCORES) {


printf("Error: Invalid number of scores! Must be 1-%d\n", MAX_SCORES);
return;
}

if(strlen(name) >= MAX_NAME_LENGTH) {


printf("Error: Name too long! Maximum length: %d characters\n",
MAX_NAME_LENGTH - 1);
return;
}

Each validation check:

Check 1: Null pointers


 Prevents crashes from invalid pointers

Check 2: Grade book capacity

 gb->num_students >= MAX_STUDENTS means we're at the limit


 Can't add more students without overflowing our array

Check 3: Valid score count

 Must have at least 1 score, maximum 10 scores


 Prevents allocating invalid amounts of memory

Check 4: Name length

 strlen(name) counts characters in the name


 Must fit in our MAX_NAME_LENGTH array with room for null terminator

Getting a Reference to the New Student


Student* student = &gb->students[gb->num_students];

What this does:

 gb->students[gb->num_students] = The next available student slot


 & = "Address of" - gives us a pointer to that slot
 student = Our convenient pointer to work with

Example: If we have 2 students already:

 gb->num_students = 2
 gb->students[2] = The third slot (index 2)
 student points to that empty slot

Setting Basic Student Information


strcpy(student->name, name);
student->num_scores = num_scores;

Copy the name safely:

 strcpy copies the string character by character


 Safe because we already validated the length

Dynamic Memory Allocation for Scores


student->scores = malloc(num_scores * sizeof(float));
if(student->scores == NULL) {
printf("Error: Memory allocation failed for student scores!\n");
return;
}

Why dynamic allocation?

 Different students might have different numbers of tests


 Static array would waste space for students with fewer scores
 Dynamic allocation gives us exactly what we need

The allocation:

 num_scores * sizeof(float) = Total bytes needed


 Example: 3 scores × 4 bytes = 12 bytes
 malloc() returns pointer to that memory

Always check for failure:

 malloc() returns NULL if it can't allocate memory


 Always check and handle this gracefully

Interactive Score Input


printf("\nEntering scores for %s:\n", name);
float sum = 0.0;

for(int i = 0; i < num_scores; i++) {


float score;
do {
printf("Enter score %d (0-100): ", i + 1);
scanf("%f", &score);

if(score < 0.0 || score > 100.0) {


printf("⚠️ Invalid score! Please enter a value between 0 and
100.\n");
}
} while(score < 0.0 || score > 100.0);

student->scores[i] = score;
sum += score;
}

The input validation loop:

do {
// Get input
scanf("%f", &score);

// Validate input
if(score < 0.0 || score > 100.0) {
printf("Warning message");
}
} while(score < 0.0 || score > 100.0);

How do-while works:

1. Execute the code inside do { } at least once


2. Check the condition in while()
3. If condition is true, repeat the loop
4. If condition is false, exit the loop

Why this pattern?

 We always ask for input at least once


 Keep asking until user gives valid input (0-100)
 User can't "break" our program with invalid data

Calculating Final Results


// Calculate average and letter grade
student->average = sum / num_scores;
student->letter_grade = calculate_letter_grade(student->average);

// Increment student count


gb->num_students++;

printf("✓ Student '%s' added successfully!\n", name);


printf(" Average: %.2f (%c)\n", student->average, student->letter_grade);

Final steps:

1. Calculate average from the sum we kept track of


2. Convert average to letter grade using our helper function
3. Important: Increment the student count
4. Give user feedback about what was calculated

Finding Students by Name


int find_student(const GradeBook* gb, const char* name) {
if(gb == NULL || name == NULL) {
return -1;
}

for(int i = 0; i < gb->num_students; i++) {


if(strcmp(gb->students[i].name, name) == 0) {
return i; // Found student
}
}

return -1; // Student not found


}

Linear search algorithm:

 Look through each student one by one


 Use strcmp() to compare strings (returns 0 if strings are equal)
 Return the index if found, -1 if not found

Why return index instead of pointer?

 Index tells us the position in the array


 Caller can use index to access the student
 -1 is clearly "not found" (impossible array index)

Displaying Student Information


void display_student(const Student* student) {
if(student == NULL || student->scores == NULL) {
printf("Error: Invalid student data!\n");
return;
}

printf("\n--- Student Report ---\n");


printf("Name: %s\n", student->name);
printf("Number of scores: %d\n", student->num_scores);

printf("Scores: ");
for(int i = 0; i < student->num_scores; i++) {
printf("%.1f", student->scores[i]);
if(i < student->num_scores - 1) {
printf(", ");
}
}
printf("\n");

printf("Average: %.2f\n", student->average);


printf("Letter Grade: %c\n", student->letter_grade);
printf("---------------------\n");
}

Safety checking:

 Check if student pointer is NULL


 Check if scores pointer is NULL (student might not have scores allocated)

Formatting the scores list:


for(int i = 0; i < student->num_scores; i++) {
printf("%.1f", student->scores[i]);
if(i < student->num_scores - 1) {
printf(", ");
}
}

The comma logic:

 Print each score with one decimal place


 Add comma after each score EXCEPT the last one
 i < student->num_scores - 1 means "not the last item"

Example output:

--- Student Report ---


Name: Alice Johnson
Number of scores: 3
Scores: 92.0, 87.5, 95.0
Average: 91.50
Letter Grade: A
---------------------

Comprehensive Grade Book Report


void print_gradebook(const GradeBook* gb) {
if(gb == NULL) {
printf("Error: Invalid grade book!\n");
return;
}

printf("\n");
printf("========================================\n");
printf(" GRADE BOOK REPORT\n");
printf(" Class: %s\n", gb->class_name);
printf(" Total Students: %d\n", gb->num_students);
printf("========================================\n");

if(gb->num_students == 0) {
printf("No students in grade book.\n");
return;
}

// Display each student


for(int i = 0; i < gb->num_students; i++) {
const Student* student = &gb->students[i];

printf("\n%d. %-20s | ", i + 1, student->name);

// Display scores
printf("Scores: ");
for(int j = 0; j < student->num_scores; j++) {
printf("%5.1f", student->scores[j]);
}

printf(" | Avg: %6.2f | Grade: %c\n",


student->average, student->letter_grade);
}

printf("\n========================================\n");
}

Formatted output explanation:

%-20s in printf("%d. %-20s | ", i + 1, student->name)

 %s = String format
 -20 = Left-aligned, 20 characters wide
 Creates a nice column of names

%5.1f in printf("%5.1f", student->scores[j])

 %f = Float format
 5 = Total width of 5 characters
 .1 = One decimal place
 Right-aligned numbers in columns

Example output:

========================================
GRADE BOOK REPORT
Class: Math 101
Total Students: 2
========================================

1. Alice Johnson | Scores: 92.0 87.5 95.0 | Avg: 91.50 | Grade: A


2. Bob Smith | Scores: 78.0 82.0 | Avg: 80.00 | Grade: B

========================================

Class Statistics - Data Analysis


void calculate_class_statistics(const GradeBook* gb) {
if(gb == NULL || gb->num_students == 0) {
printf("No students to calculate statistics for.\n");
return;
}

printf("\n=== CLASS STATISTICS ===\n");

float sum = 0.0;


float highest = gb->students[0].average;
float lowest = gb->students[0].average;

int grade_counts[5] = {0, 0, 0, 0, 0}; // A, B, C, D, F

Setting up variables:

 sum = Total of all averages (for class average)


 highest/lowest = Start with first student's average
 grade_counts[5] = Count of each letter grade (A=0, B=1, C=2, D=3, F=4)

Analyzing Each Student


for(int i = 0; i < gb->num_students; i++) {
float avg = gb->students[i].average;
sum += avg;

if(avg > highest) highest = avg;


if(avg < lowest) lowest = avg;

// Count letter grades


char grade = gb->students[i].letter_grade;
switch(grade) {
case 'A': grade_counts[0]++; break;
case 'B': grade_counts[1]++; break;
case 'C': grade_counts[2]++; break;
case 'D': grade_counts[3]++; break;
case 'F': grade_counts[4]++; break;
}
}

What happens in each iteration:

1. Add student's average to running sum


2. Update highest average if this one is bigger
3. Update lowest average if this one is smaller
4. Count the letter grade using switch statement

The switch statement:

 More efficient than multiple if-else for exact matches


 Each case handles one letter grade
 break prevents "falling through" to next case
 grade_counts[0]++ means "increment count of A grades"

Displaying Results
float class_average = sum / gb->num_students;

printf("Class Average: %.2f\n", class_average);


printf("Highest Average: %.2f\n", highest);
printf("Lowest Average: %.2f\n", lowest);

printf("\nGrade Distribution:\n");
char grades[] = {'A', 'B', 'C', 'D', 'F'};
for(int i = 0; i < 5; i++) {
float percentage = (float)grade_counts[i] / gb->num_students * 100;
printf(" %c: %2d students (%.1f%%)\n",
grades[i], grade_counts[i], percentage);
}

Calculating percentages:

 (float)grade_counts[i] = Cast to float for decimal division


 / gb->num_students * 100 = Convert to percentage
 Example: 2 A's out of 10 students = 2/10 * 100 = 20.0%

Interactive Search Feature


void search_student_menu(const GradeBook* gb) {
if(gb->num_students == 0) {
printf("No students in grade book to search.\n");
return;
}

char search_name[MAX_NAME_LENGTH];
printf("Enter student name to search: ");
scanf("%s", search_name);

int index = find_student(gb, search_name);

if(index != -1) {
printf("✓ Student found!\n");
display_student(&gb->students[index]);
} else {
printf("⚠️ Student '%s' not found in grade book.\n", search_name);

printf("\nAvailable students:\n");
for(int i = 0; i < gb->num_students; i++) {
printf(" %d. %s\n", i + 1, gb->students[i].name);
}
}
}

User-friendly search:

1. Check if there are any students to search


2. Get search name from user
3. Use our find_student() function
4. If found: show detailed student info
5. If not found: show helpful list of available students

Great user experience design:

 Don't just say "not found"


 Show what names ARE available
 Help user correct their spelling

Memory Cleanup - Critical for No Leaks


void cleanup_gradebook(GradeBook* gb) {
if(gb == NULL) return;

printf("Cleaning up grade book memory...\n");

for(int i = 0; i < gb->num_students; i++) {


if(gb->students[i].scores != NULL) {
free(gb->students[i].scores);
gb->students[i].scores = NULL;
}
}

gb->num_students = 0;
printf("✓ All memory cleaned up successfully\n");
}

Why cleanup is essential:

 Each student has dynamically allocated scores array


 We must free() each one to prevent memory leaks
 Set pointers to NULL for safety

The cleanup process:

1. Loop through all students


2. Check if scores pointer is not NULL
3. Free the scores array
4. Set pointer to NULL
5. Reset student count

The Interactive Menu System


void gradebook_demo() {
printf("\n=== GRADE BOOK SYSTEM ===\n");
GradeBook gb;
char class_name[100];

printf("Enter class name: ");


scanf("%s", class_name);

initialize_gradebook(&gb, class_name);

Setup phase:

 Create a GradeBook variable (not pointer!)


 Get class name from user
 Initialize the gradebook

The Main Menu Loop


int choice;
do {
printf("\n--- Grade Book Menu ---\n");
printf("1. Add Student\n");
printf("2. View All Students\n");
printf("3. Search for Student\n");
printf("4. Class Statistics\n");
printf("5. Exit\n");
printf("Enter choice: ");
scanf("%d", &choice);

switch(choice) {
case 1: {
// Add student code...
break;
}
case 2:
print_gradebook(&gb);
break;
case 3:
search_student_menu(&gb);
break;
case 4:
calculate_class_statistics(&gb);
break;
case 5:
printf("Exiting grade book system...\n");
break;
default:
printf("Invalid choice! Please try again.\n");
}

} while(choice != 5);

Menu-driven interface pattern:

1. Show options to user


2. Get user's choice
3. Use switch to handle each option
4. Repeat until user chooses to exit

Why do-while?

 Always show menu at least once


 Keep showing until user chooses to exit
 Classic pattern for interactive programs

Adding a Student (Menu Option 1)


case 1: {
char name[MAX_NAME_LENGTH];
int num_scores;

printf("Enter student name: ");


scanf("%s", name);

printf("Enter number of test scores (1-%d): ", MAX_SCORES);


scanf("%d", &num_scores);

add_student(&gb, name, num_scores);


break;
}

Why the curly braces?

 case 1: { starts a new scope


 Allows us to declare variables inside the case
 Without braces, we can't declare variables in switch cases

Flow:

1. Declare local variables for name and score count


2. Get input from user
3. Call our add_student() function
4. All input validation happens inside add_student()

Key Programming Concepts Demonstrated


1. Structures for Data Organization
typedef struct {
char name[MAX_NAME_LENGTH];
int num_scores;
float* scores;
float average;
char letter_grade;
} Student;

Lesson: Group related data together for better organization.

2. Dynamic Memory Management


student->scores = malloc(num_scores * sizeof(float));
// Use the memory...
free(student->scores);
student->scores = NULL;

Lesson: Allocate exactly what you need, clean up when done.

3. Input Validation
do {
printf("Enter score %d (0-100): ", i + 1);
scanf("%f", &score);
if(score < 0.0 || score > 100.0) {
printf("Invalid score! Try again.\n");
}
} while(score < 0.0 || score > 100.0);

Lesson: Never trust user input - always validate.

4. Error Handling
if(gb == NULL || name == NULL) {
printf("Error: Invalid parameters!\n");
return;
}

Lesson: Check for problems and handle them gracefully.

5. Menu-Driven Interface
do {
// Show menu
// Get choice
// Handle choice with switch
} while(choice != exit_option);

Lesson: Standard pattern for interactive programs.


Real-World Applications
This grade book system demonstrates patterns used in:

 Database applications (CRUD operations: Create, Read, Update, Delete)


 Management systems (student records, employee data, inventory)
 Interactive software (menu systems, user interfaces)
 Data analysis tools (statistics, reporting)

Professional Features Included:

 ✅ Input validation and error handling


 ✅ Dynamic memory management
 ✅ Modular function design
 ✅ User-friendly interface
 ✅ Memory leak prevention
 ✅ Comprehensive testing through interactive menu

Exercise Challenges for Students


1. Add grade editing: Allow users to modify existing student scores
2. Add file I/O: Save/load gradebook to/from files
3. Add sorting: Sort students by name or average
4. Add more statistics: Standard deviation, median scores
5. Add grade curves: Adjust all scores by a percentage

This project brings together everything you've learned about C programming into a real, useful
application!

You might also like