Practice Lab 1 — Student profile records, without classes¶
Difficulty: Beginner · Estimated time: 2–3 hours · Module 1: C++ and the OOP Mindset
This lab is deliberately clumsy. You are going to build a working program with no classes at all, feel where it hurts, and write down why — which is the reason object orientation exists.
At a glance¶
| Difficulty | Beginner |
| Estimated time | 2–3 hours |
| Module | Module 1 — C++ and the OOP Mindset |
| Concepts practised | Parallel arrays, free functions, long parameter lists, global state, identifying objects from a problem statement |
| Prerequisite | Set Up Your Toolchain, Your First Program |
| Class design | none — deliberately |
Scenario¶
A department office keeps a list of student profiles for a small programme. Each profile has a roll number, a name, a programme, a year of study, and a set of marks. The office needs to print the list, look a student up by roll number, add marks, and produce a class average.
You have been asked for a quick program. It is a throwaway: the real system will be written later, and what matters now is that you feel exactly which parts of this version will not survive.
Problem statement¶
Write a single-file program that stores up to 100 student profiles and offers these operations:
- Add a profile (roll number, name, programme, year).
- Look a student up by roll number, printing their details and marks.
- Add a mark to a student.
- Print every profile, in ascending roll-number order.
- Print the average mark across all students.
Store the profiles in parallel arrays — one array of roll numbers, one of names, one of programmes, one of years, one of mark counts, and a two-dimensional array of marks. Implement each operation as a free function that takes the arrays and the count.
This is not a strawman. Parallel arrays are what a great deal of real C code does, and they work.
Learning objectives¶
By the end of this lab you will be able to:
- Write a working multi-operation program using parallel arrays and free functions.
- Identify, in your own code, the three symptoms of a missing abstraction: a count threaded everywhere, a set of arrays that must be kept in step, and a function signature that grows with every new field.
- Name the objects a problem contains, from the problem statement rather than from the code.
- State, in one sentence each, what a class would group in this program and why the grouping is not merely cosmetic.
Functional requirements¶
- At most 100 profiles; a full list refuses the addition with a message.
- A roll number is unique; a duplicate is refused with a message.
- An unknown roll number in a lookup prints
not foundand does not crash. - At most 10 marks per student; the eleventh is refused with a message.
- Marks are integers in
0..100; anything else is refused. - Printing is in ascending roll-number order, whatever order the profiles were added in.
- The average is computed over all marks of all students, printed to one decimal place; with no marks it
prints
no marks recordedrather than dividing by zero. - Every operation is a free function;
mainis a menu loop.
Constraints¶
- No classes and no
structin this lab. That is the point of it. - One source file, compiled exactly as the course teaches:
g++ -std=c++17 -Wall -Wextra -Werror main.cpp -o roster - No
std::vector, nostd::stringarrays beyond what you choose for names and programmes — arrays ofcharare acceptable and instructive. - Global arrays, so that the free functions do not need eight parameters. (Notice how this trades one problem for another; you will be asked about that in the reflection.)
- No warnings.
Starter task¶
Before writing any of the five operations, write the function signatures only, with empty bodies, and
answer these two questions in a file called design-notes.md:
- How many parameters does the widest function need, and which of them are really the same object split into pieces?
- Which pieces of data must always change together? Name one pair, and say what happens when a caller updates one and forgets the other.
Hint: adding a field of study field later means touching the array declarations, the add function, the
print function and the lookup function. Count them in your notes before you add it — you will add it as
part of the extension challenge.
Implementation tasks¶
- Declare the parallel arrays and the count at file scope, and write
add_profile. - Write
find_index(roll_number)— every other operation uses it. Notice that it returns anintindex and the special value-1for "not found", and write one sentence on why that is a fragile contract. - Write
add_mark,print_profile,print_all_sortedandaverage_mark. - Write the menu loop.
- Run the test cases below and record the output.
- Write
reflection.md: the three symptoms you actually felt, each with a line reference from your own code.
Test cases¶
| # | Action | Expected result |
|---|---|---|
| 1 | Add three profiles, print all | Three lines in ascending roll-number order |
| 2 | Add a duplicate roll number | Refused, with the roll number in the message |
| 3 | Look up a roll number that exists | Details and marks printed |
| 4 | Look up a roll number that does not exist | not found, exit status still 0 |
| 5 | Add a mark to the last profile, print it | The mark appears |
| 6 | Add eleven marks to one student | The eleventh is refused, the first ten remain |
| 7 | Add a mark of 101 and of −1 | Both refused |
| 8 | Average with no marks at all | no marks recorded, no division by zero |
| 9 | Average of marks 70, 80, 90 | 80.0 |
| 10 | Fill the list to 100, then add one more | Refused with a message, no out-of-bounds write |
Boundary cases to run deliberately: zero profiles; one profile; a full list; the tenth mark.
Expected behaviour¶
$ ./roster
1) add profile 2) find 3) add mark 4) list 5) average 6) quit
> 1
roll number: 2024003
name: Ayesha Khan
programme: BS Data Science
year: 2
added.
> 4
2024003 Ayesha Khan BS Data Science year 2 marks:
> 3
roll number: 2024003
mark: 91
added.
> 3
roll number: 2024999
mark: 91
not found
> 5
average: 91.0 (over 1 mark)
> 6
Extension challenge¶
Add a field of study to every profile.
Then, in reflection.md, record:
- Every place you had to edit, as a list.
- The number of files — which is one, and is the reason this exercise is not yet about files.
- What a class would have changed about that list.
Debugging challenge¶
This function is meant to add a mark. It compiles, and it sometimes prints the wrong student's marks:
void add_mark(int roll, int mark) {
const int index = find_index(roll);
if (index >= 0) {
marks[index][mark_count[index]] = mark;
++mark_count[index];
}
}
Reproduce it — add marks to two students in an order that makes the bug visible — then answer:
- Which invariant did the code violate, and what is the invariant in one sentence?
- Why did the compiler not notice?
- Which single line would you change to make the failure loud instead of silent?
Do not fix the function until you have written the answers down.
Reflection questions¶
- Which of your functions had the longest parameter list, and which parameters were really one thing?
- Where in your program can two pieces of data get out of step, and what would prevent it?
find_indexreturns-1for "not found". Name one caller that could ignore that and what would happen.- Which three names in your program — the arrays and the functions — would you keep as an object's operations if you were allowed classes?
- Global state removed the parameter lists. What did it cost you instead?
- Write the objects you think this problem contains, as a list of nouns with one responsibility each.
Completion checklist¶
- [ ] It compiles with
-Wall -Wextra -Werrorand no warnings - [ ] All ten test cases were run, and the results are in
reflection.md - [ ] Boundary cases were run: zero profiles, one profile, a full list, the tenth mark
- [ ] The debugging challenge was reproduced, explained, and only then fixed
- [ ]
design-notes.mdrecords the widest signature and one pair of values that must change together - [ ] The extension challenge was done and its edit list recorded
- [ ] I can name the objects in this problem without looking at the code
- [ ] I can say, in one sentence each, what three symptoms of missing abstraction appeared in my own work
Related: Lab index · Module 1 — C++ and the OOP Mindset · Next: Practice Lab 2 — Library catalogue in plain structs