Assignment 2 - Getting Started With C, Part 2
Due: Friday, September 20, at 10:00pm
Starter code: a2.c
Upload solutions via Gradescope as: a2.c
Goals
This assignment is designed to help you with the following:
- thinking of files as a sequence of bytes (
chars) - building familiarity with C structs and arrays
- getting used to using some simple program testing automation
Collaboration policy
For this assignment, you may work alone or with a partner, but you must type up all of the code yourself. (It is therefore unexpected for two code submissions to be completely identical.)
You may also discuss the assignment at a high level with other students.
You should list any student with whom you discussed the assignment, and the manner of discussion (high level, partner, etc.) in comments at the top of your C source file(s).
If you work alone, you should say so instead.
Assessment
To demonstrate proficiency, your submission needs to:
- pass the simple autograder tests for Parts A and B (these have names starting with
"_P") - use
fgetcto process the file one character at a time - be somewhat well-styled
To demonstrate mastery, your submission needs to:
- demonstrate proficiency
- pass all autograder tests
- be quite well-styled, particularly with well-chosen variable names, naming all magic numbers, good identation, and closing the file after reading it
- have a well-chosen algorithm (i.e., don’t over-complicate this task!)
- have thorough error-handling
- include your name and collaboration statement at the top of your C source file(s)
Assignment overview
For this second assignment, you will get some practice working with file I/O in C, as well as with structs and arrays of structs. You are given a struct that stores a few statistics:
/*
* Stats for a given line in a file will be stored together in a struct.
*/
typedef struct
{
char first;
char last;
int length;
} line_stats_t;Your program will be divided into two functions (as before, you shouldn’t modify main() at all!):
-
parse_stats: reads in a file and parses interesting statistics into an array ofline_stats_t, with one entry per line -
print_results: reads through the stats and prints out information for each line
Note that error handling, especially around working with the file, is not required for demonstrating proficiency, but it is for mastery.
Assumptions: You may assume that a file has at most 100 lines (see the #define MAX_LINES 100 in your code), and that the file is not completely empty (i.e., it has at least one line with at least one character in it).
Getting started
For this second assignment, you should download the a2.c file from the top of this page. It has two functions marked // TODO that you’ll need to fill in.
Look back at the instructions from Assignment 1 for how to get the code.
You should also grab two text files you can use for testing: a2_data_simple.txt and a2_data.txt.
Check at the top of a2.c for the command to compile the code. I encourage you to type it, not just copy it, to start building some muscle memory.
You can run the code by giving the filename as a command-line argument. Here’s what that may look like (keep in mind that $ is my shell prompt—don’t type that):
$ ./a2 a2_data_simple.txt
The file to parse is: "a2_data_simple.txt"
Found 0 lines.Your assignment
This assignment is broken into three parts, which span the two functions. You must complete Parts A and B to demonstrate proficiency; for mastery, you must also complete Part C.
Part A
The first part of this assignment is to be able to print out the first character and the length of each line in the file. To do this, you should fill in parse_stats with enough functionality to store the first and length statistics for each line in the appropriate line_stats_t entry in stats (this array is passed into the function parse_stats) and return the number of lines parsed.
Here are some suggested steps:
- Take a look at the Samples page. At least one of them will be super useful to you for this assignment!
- Add some code and debugging print statements to just read through the file and print out the length of each line.
- Now store those lengths in the structs.
- Add some code at the end of
parse_statsto iterate through thestatsarray and print the lengths, instead of doing it all inside the character-parsingwhileloop. - Add code to find the first character of each line.
- Don’t forget to return the number of lines parsed!
For proficiency, you don’t need to find the last character in each array. You can also assume that each line has at least one character.
For mastery, you’ll need to come back and add the last character in each array—that’s Part C.
Part B
Now that you can find the length and first character of each line, you should move those print statements into the print_results function. You’ll need to change their format to match the expected output.
For example, if line 7 starts with A and has length 10, you need to print out the A both as a character and in hexadecimal (0x41), and the 10 as a decimal integer and in hex (0xa). The string you would print for this line, including some tab characters for aligning results, would look like this: "Line 7:\tfirst=A (0x41),\tlength=10 (0xa)\n". (Of course, you need to plug in the relevant parts of the line with the appropriate format specifiers, e.g., %d, %c, %x.)
This line would display as:
Line 7: first=A (0x41), length=10 (0xa)You can use a2_data_simple.txt to test your code now. Here is what the file looks like:
Good morning!
How are you
doing
today??Note that the second line contains a single space (ASCII codepoint 0x20), the third line has a single tab (ASCII codepoint 0x9), and the fourth line has some trailing spaces. (If you highlight the above text in your browser, you should see this whitespace.)
Here is what you should see now when you run your code with a2_data_simple.txt as an input (keep in mind that $ is the prompt at my terminal):
$ ./a2 a2_data_simple.txt
Line 0: first=G (0x47), length=13 (0xd)
Line 1: first= (0x20), length=1 (0x1)
Line 2: first= (0x9), length=1 (0x1)
Line 3: first=H (0x48), length=13 (0xd)
Line 4: first= (0x20), length=7 (0x7)
Line 5: first= (0x20), length=11 (0xb)You should now be able to pass the tests on Gradescope to demonstrate proficiency. Note that your program must be able to match the above outputs exactly for the last couple of tests to pass.
Part C
To demonstrate mastery, you must also complete Part C. For this part, you should modify your code from Parts A and B to add the following functionality:
- Store the last character from each line in the
line_stats_tstructs. - Modify the print statements to be able to include the last character on each line.
- Be able to handle empty lines (reporting first and last characters as
'\0'(which has decimal value0)). - Add error handling for cases where the file doesn’t exist or there is an error while reading.
For the last character, you should again use a tab character to align the printed results. From the example above, if the last character on the line were *, the string to print would be "Line 7:\tfirst=A (0x41),\tlast=* (0x2a),\tlength=10 (0xa)\n".
Note: Check the list at the top of this page to make sure you have everything you need (e.g., collaboration statement, good code style, etc.).
Your code should now give this output for a2_data_simple.txt:
$ ./a2 a2_data_simple.txt
Line 0: first=G (0x47), last=! (0x21), length=13 (0xd)
Line 1: first= (0x20), last= (0x20), length=1 (0x1)
Line 2: first= (0x9), last= (0x9), length=1 (0x1)
Line 3: first=H (0x48), last= (0x20), length=13 (0xd)
Line 4: first= (0x20), last=g (0x67), length=7 (0x7)
Line 5: first= (0x20), last=? (0x3f), length=11 (0xb)You can also use a2_data.txt, which adds an empty line:
$ ./a2 a2_data.txt
Line 0: first=G (0x47), last=! (0x21), length=13 (0xd)
Line 1: first= (0x20), last= (0x20), length=1 (0x1)
Line 2: first= (0x9), last= (0x9), length=1 (0x1)
Line 3: first=H (0x48), last= (0x20), length=13 (0xd)
Line 4: first= (0x0), last= (0x0), length=0 (0x0)
Line 5: first= (0x20), last=g (0x67), length=7 (0x7)
Line 6: first= (0x20), last=? (0x3f), length=11 (0xb)You should now be able to pass all tests on Gradescope, thereby demonstrating mastery. Again, your program must match these outputs exactly for the last couple of tests to pass.
Submitting your work
You’ll need to follow these steps to submit your work:
-
Upload your
a2.cfile to Gradescope. -
Wait for the autograder to run.
-
Feel free to resubmit if the autograder points out an issue.
Advice
-
There are some really helpful examples on the Sample Programs page. Make sure to take a look and check your notes for any we specifically referenced in class!
-
Think ahead of time about error handling. What could go wrong? What should your program do if something bad happens? (For example, what if the input array is empty?)
-
This assignment is meant to help acclimate you to the process you’ll follow when submitting assignments in this course, and help you get familiar with C. If you are struggling, please reach out! Also, don’t be shy about experimenting and asking lots of questions!