Introduction
Sunny Snacks needs a receipt that keeps every purchase, including a customer returning for the same snack a second time. You will first run a one-item sample, then complete a C program that stores separate purchase records and prints every line, its unit price, its subtotal and the complete total.
You need C variables, conditions, loops, arrays, functions and basic terminal input and paths. This lab introduces the required struct and text-output details. The prepared browser environment includes a C compiler, a WebIDE file editor and the Workspace terminal. You will navigate the supplied files and save local edits before compiling. The amounts are synthetic integer cents, not a payment or accounting system. Reading and practice time is an author estimate; beginner timing has not been measured.
Read a One-Item Receipt
In this step, you will run a complete receipt before editing, then use the real file editor to change one quantity and recover from an ordinary C syntax mistake.
Open the Workspace Tab. This is the shell used for compiling and entering purchases. Its directory is /home/labex/project/receipts; cd enters that directory, pwd prints the current directory and ls lists files. The separate WebIDE Tab is the file editor, not another snack counter. Both entries work with the same files.
cd /home/labex/project/receipts
pwd
ls
sample.c is a complete one-item example; till.c has the unfinished multi-purchase work for the next step. Keep the supplied catalog.h, parse.h, driver.h and read-line.h unchanged in this lab. First see the normal example. gcc compiles C, -std=c11 selects C11, -Wall -Wextra enable warnings, and -o sample names the executable. ./sample runs that executable from this directory.
gcc -std=c11 -Wall -Wextra sample.c -o sample
./sample
The completed one-item result is:
SUNNY SNACKS
ID | ITEM | QTY | UNIT | SUBTOTAL
101 | Oat bar | 1 | 1.25 | 1.25
TOTAL | 1.25
ID is the product identifier: 101 selects this catalog entry. UNIT is one item's price; SUBTOTAL is this purchase's quantity times its unit price. Vertical bars separate columns. The final TOTAL adds every purchase subtotal; here there is one.
Before editing, make a local recovery copy. mkdir creates a directory. In this cp command, the last argument is the destination directory and the preceding arguments are files to copy. This does not change the originals or complete the unfinished program.
mkdir before-edit
cp sample.c till.c catalog.h parse.h driver.h read-line.h before-edit/
Switch to WebIDE. In its application menu at the upper left, choose File > Open Folder..., enter /home/labex/project/receipts, and confirm the folder. Use the editor's Explorer file list, not a browser download or a local folder on your computer. Before the first edit in this independent lab, open File and inspect Auto Save. If it has a check mark, click Auto Save to turn it off. Open File again and confirm Auto Save is not checked, then press Escape. This makes saving and abandoning edits explicit; do not rely on the setting from another lab. After File > Save, wait until the unsaved dot on the file tab disappears before switching to Workspace. Open sample.c from that list. If the Explorer is hidden, choose View > Explorer. The open file's tab must say sample.c.
Read the small program alongside its real result. quantity starts at 1. unit_cents is 125: one currency unit and 25 cents. Multiplication calculates an integer-cent subtotal. Keep cents throughout the calculation. Integer division by 100 gives the whole part; % 100 gives the remainder. A C string ends with the zero-valued character \0, called the NUL terminator; it is not the visible digit zero. puts prints a terminated string and adds a newline. In printf, %d prints an integer, %s prints a NUL-terminated C string, %02d pads the fractional part to two digits, and \n ends a line. Thus 250 cents displays as 2.50 without floating-point arithmetic.
Practice finding and abandoning an edit before making the real change. Focus the editor, use Edit > Find, search for int quantity = 1;, press Enter to move to the match, then press Escape to leave the search box. Check the selection: it must cover exactly int quantity = 1;, not the whole file. If the search match is not selected after Escape, drag across just that declaration text to select it. Type int quantity = 9; to replace this one declaration, leaving the surrounding lines unchanged. Do not save. Close the sample.c editor tab and choose Don't Save when asked about the changed file. Reopen sample.c from Explorer: the saved quantity is still 1. Closing an editor tab is different from closing the browser Tab.
Now make the real quantity change, with one deliberate punctuation mistake to learn the recovery path. Find int quantity = 1; again, press Enter then Escape, and select exactly that declaration as above. Type int quantity = 2 without its final semicolon to replace the selected text. Leave all other lines alone. Choose File > Save in WebIDE and wait until the unsaved dot on the file tab disappears. Saving source does not rebuild an existing executable.
Return to Workspace and compile:
gcc -std=c11 -Wall -Wextra sample.c -o sample
This compilation is expected to fail. GCC names sample.c, a line and a column, and reports missing punctuation, often at the following declaration where it notices the problem. Do not run the old sample: it still represents the earlier source. A command's exit status is a small integer; 0 means success here, while this compiler failure returns 1. Immediately print the last status with echo $?; another command in between would replace it.
echo $?
The expected output is 1. Switch back to WebIDE. Use Go > Go to Line/Column..., enter the first line number GCC reported, and inspect that line and the preceding declaration. After identifying the missing semicolon, use Edit > Find for int quantity = 2, press Enter then Escape and select exactly that declaration text. Replace it with the following declaration, including its semicolon:
int quantity = 2;
Choose File > Save and wait for the unsaved dot to disappear. Return to Workspace. cat displays the saved file without editing it, so you can distinguish disk contents from an unsaved editor buffer:
cat sample.c
gcc -std=c11 -Wall -Wextra sample.c -o sample
The compile should now succeed. The shell operator > redirects standard output into a file. It opens or truncates that file before C runs, so use the new output name below.
./sample > sample-receipt.txt
cat sample-receipt.txt
Quantity is now 2, subtotal and total are 2.50, and the unit price remains 1.25. Check by hand: 125 × 2 = 250 cents. Keep sample.c, executable sample and sample-receipt.txt.
For an unwanted saved edit, use Edit > Undo in the still-open file and File > Save, then inspect the saved text again. If you have lost the intended text, before-edit holds the supplied versions. For example, cat before-edit/catalog.h lets you compare a mistakenly edited catalog; cp before-edit/catalog.h catalog.h restores only that file. Close its editor tab first, restore only the affected file, then reopen it so an old editor buffer cannot overwrite the restored disk file. Use the matching backup name for another supplied file. Restoring sample.c or till.c also discards your edits to that one file, so prefer correcting the small mistake when possible. Never rerun setup to recover a local edit.
If a path or file name is wrong, use the taught cd and ls. If another compiler error appears, follow its file name and first line number in WebIDE, save the correction and recompile before running. The same rule applies when GCC points into an included header rather than the file named on the compile command.
Keep and Print Every Purchase
In this step, you will trace one purchase through the prepared records, implement the two missing function bodies locally, and save every purchase line rather than only the last total.
Start in Workspace, in /home/labex/project/receipts. The editor's saved files and this terminal's files are the same. Read the catalog without changing it:
cd /home/labex/project/receipts
cat catalog.h
Switch to WebIDE and open catalog.h in Explorer. This supplied header gives the shop title, maximum six purchase lines, maximum quantity 20, and four catalog rows. #include "catalog.h" includes its definitions at compilation. #define gives a name to a constant or initializer; CATALOG_ROWS supplies the rows used to initialize the product array. A backslash (\) at the end of a definition line continues the same #define on the next physical line. Read this file but do not edit it.
Open till.c. A struct groups related fields in one record. Product groups an integer id, a 32-character name array and an integer price cents. typedef lets us use Product as the short name of that record type. A C string ends with the zero-valued character \0, called NUL, so its array needs room for that terminator as well as visible characters. The supplied names fit; parsing arbitrary names is outside this task.
Purchase is a different record: it stores a product's position in the product array and the quantity of this particular purchase. Square brackets select an array entry and the dot selects its field. In basket[line_count].quantity, you select a purchase, then its quantity. Array positions start at zero. The global static basket and line_count initialize to zero. sizeof products / sizeof products[0] counts complete product records.
Use Edit > Find to locate find_product, press Enter to move to the match, then leave Find with Escape and read its loop. It matches a product ID, returning the array position or -1 if absent. Ask yourself what a purchase of ID 101 and quantity 2 must store: position 0 and quantity 2, not a copy of the displayed name. A later purchase of ID 101 needs another basket entry. The two products named Water have different IDs and prices: 103 is 75 cents and 104 is free. Looking up by name would lose this identity. The catalog has four products, IDs 1..999 and prices 0..9999 cents; the same program must work when recompiled with another supplied four-row catalog in those bounds.
Open driver.h from Explorer and read it without editing. Its main asks for a product ID, then a quantity, calls approve_purchase, and uses print_receipt when it receives exact lowercase done at Product ID. An invalid candidate returns to Product ID before approval. parse.h and read-line.h supply the input boundary; you will implement that boundary in the next lab. Keep all four supplied headers unchanged here. The existing function names and signatures connect your code to the driver; internal record and local variable names are not the grading target.
Return to the till.c editor tab and find approve_purchase with Edit > Find, Enter and Escape. Leave the function signature, outer braces, record definitions, lookup and final #include "driver.h" in place. Select only the placeholder statements inside this function, from (void)id; through return 0;, and replace them with the logic below. You can drag from the start of the first placeholder line through the final semicolon. Check the highlighted text before typing: neither outer brace may be selected. For this four-line placeholder, an alternative is to Find (void)id;, press Enter then Escape, press Left to collapse to its beginning, then Home to reach the start of the line. Hold Shift while pressing Down three times and then End. The selection must contain exactly the four placeholder lines and no closing brace.
First find the product position. Reject an absent product, quantity outside 1..20 or a full basket before writing. || means any listed condition is enough for rejection. Only an approved purchase writes its product position and quantity, increases the count and returns 1. A price of zero is valid; a quantity of zero is not. Do not merge repeated IDs. Writing even once at position 6 would already be outside the six-entry array; rejecting afterward cannot undo that invalid access.
int index = find_product(id);
if (index < 0 || quantity < 1 || quantity > MAX_QUANTITY || line_count >= MAX_LINES)
return 0;
basket[line_count].product_index = index;
basket[line_count].quantity = quantity;
line_count++;
return 1;
Choose File > Save, switch to Workspace, and compile this intermediate source. Warnings are enabled so ordinary mistakes are visible. A successful compile at this point does not mean the still-incomplete printer is finished.
gcc -std=c11 -Wall -Wextra till.c -o till
Return to WebIDE, find print_receipt in till.c, and read its existing shop-title and column-header output. puts prints a terminated string and adds a newline. printf uses format markers such as %s for a NUL-terminated string and %d for an integer. You must calculate and print the purchase details, not replace them with a plausible total.
Keep the function signature and outer braces. Inside it, remove (void)basket;, the placeholder comment and the fixed puts("TOTAL | 0.00");. Add int total = 0; before the two existing title/header puts statements. Then add this loop after those two statements. Product product = ... copies the referenced catalog record into a local variable. For each saved purchase, read its quantity, calculate the integer-cent subtotal, add it to the total and print all five fields. The loop stops at the number of approved purchases, not the catalog size or array capacity.
for (int i = 0; i < line_count; i++) {
Product product = products[basket[i].product_index];
int quantity = basket[i].quantity;
int subtotal = product.cents * quantity;
total += subtotal;
printf("%d | %s | %d | %d.%02d | %d.%02d\n",
product.id, product.name, quantity,
product.cents / 100, product.cents % 100,
subtotal / 100, subtotal % 100);
}
After the loop but still inside print_receipt, print exactly one final total:
printf("TOTAL | %d.%02d\n", total / 100, total % 100);
Before saving, trace both possible paths: an empty basket skips the loop and prints 0.00; three approved purchases execute the loop three times. Six purchases at the largest allowed quantity and price total at most 6 × 20 × 9999 = 1,199,880 cents, within a signed 32-bit integer. Save the file, return to Workspace and compile:
gcc -std=c11 -Wall -Wextra till.c -o till
If compilation fails, use the file and first line number to return to the affected code in WebIDE. Check the preceding line for a missing semicolon or brace. Save and compile again; do not run the old executable after a failed compile.
The driver writes prompts and messages to standard error, which stays visible in the terminal. Only a completed receipt goes to standard output. First test the empty-basket path with a new file:
./till > empty-receipt.txt
At Product ID, type done and press Enter. When the shell prompt returns, read the result:
cat empty-receipt.txt
It contains the shop title and column header followed by TOTAL | 0.00, with no purchase rows. Now test one normal purchase in another new run:
./till > one-purchase.txt
At Product ID enter 101, then at Quantity enter 1, pressing Enter after each. You should see Added line 1. Enter done at the next Product ID. Read the completed file:
cat one-purchase.txt
It has one Oat bar purchase with quantity 1, unit price 1.25, subtotal 1.25 and total 1.25, matching the original sample. This confirms the saved reference and quantity reach the printer. Each execution begins with an empty basket; none of these runs loads an old receipt.
Now save the required three-purchase transaction in its own file:
./till > receipt.txt
The program is waiting for input. Type each table value at its prompt, pressing Enter after each. Do not enter purchase values as shell commands. done is exact and lowercase and works only at Product ID.
| Product ID input | Quantity input | Result |
|---|---|---|
101 |
2 |
Added line 1 |
102 |
1 |
Added line 2 |
101 |
1 |
Added line 3, preserving the earlier purchase of 101 |
done |
Not requested | Complete the receipt and return to the shell |
Prompts and Added line remain visible on standard error. Only the completed receipt goes to standard output, redirected by > to receipt.txt. After the shell prompt returns, inspect the actual saved file:
cat receipt.txt
Expected contents:
SUNNY SNACKS
ID | ITEM | QTY | UNIT | SUBTOTAL
101 | Oat bar | 2 | 1.25 | 2.50
102 | Fruit cup | 1 | 2.30 | 2.30
101 | Oat bar | 1 | 1.25 | 1.25
TOTAL | 6.05
The two Oat bar purchases remain separate. Add their subtotals with Fruit cup: 250 + 230 + 125 = 605 cents. A correct-looking total without all these rows would lose the customer's transaction detail. The completed receipt requires title, header, every ordered purchase and exactly one final TOTAL. Field-surrounding spaces and blank lines may vary; missing fields, extra records or rows after the total are invalid.
Numbers use decimal digits, an optional sign and optional leading/trailing ASCII spaces or Tabs; leading zeros are allowed. IDs must exist in the catalog, quantities must be 1..20 and each input line permits at most 63 bytes before Enter. Rejecting an ID or quantity discards the pending candidate and returns to Product ID without changing approved purchases. The supplied reader consumes an overlong line instead of splitting leftovers into later answers. At most six purchases are approved.
To cancel instead of checking out, press Ctrl+D at an empty input prompt. This end-of-file signal, or EOF during an unfinished line, cancels with status 2 and no completed receipt. It does not export or preserve an unfinished transaction. Redirection has already opened its output file, so use a different name for an intentional cancellation. done entered as a quantity is invalid quantity text, not checkout.
If only the last purchase appears, inspect the array position and count in approve_purchase; if fields or totals are wrong, inspect the loop and integer-cent output in print_receipt. Correct that local code in WebIDE, save, recompile, then replay the required purchases in a new transaction. Do not edit receipt text to disguise a program error. Keep till.c, executable till, supplied files and the complete receipt.txt. The course check also runs unchanged source copies with runtime bounds detection in a disposable directory. It detects errors exercised by its inputs, not complete memory safety, and does not repair your files.
Summary
You turned a one-item sample into a complete multi-line receipt. You used structs, an array of separate purchases, stable catalog IDs and integer-cent arithmetic, then saved and read the real text result. The next lab focuses on the input boundary before a purchase can enter that array.


