代写COMP 206: Introduction to Software Systems Assignment 4: files and pointers Winter 2024代写留学生Java程序
- 首页 >> C/C++编程COMP 206: Introduction to Software Systems
Assignment 4: files and pointers
Winter 2024
Before you start, please read the following instructions:
• Individual assignment
This is an individual assignment. Collaboration with your peers is permitted (and encouraged!) provided that no code is shared; discuss the ideas.
• Use Discord and OH for questions
If you have questions, check if they were answered in the #clarifications or #q-and-a channels on Discord. If there is no answer, post your question on the forum. Donotpost your code. If your question cannot be answered without sharing significant amounts of code, please use the TA/Instructors office hours. Do not email the TAs and Instructors with assignment questions. TAs should only be contacted by emails if you have questions about a grade you received.
• Late submission policy
Late penalty is -10% per day. Maximum of 2 late days are allowed.
• Must be completed on mimi server
You must use mimi.cs.mcgill.ca to create the solution to this assignment. An important objective of the course is to make students practice working completely on a remote system. You cannot use your Mac/Win- dows/Linux terminal/command-line prompt directly without accessing the mimi server. You can access mimi.cs.mcgill.ca from your personal computer using ssh or putty as seen in class and in Lab A. If we find evidence that you have been doing parts of your assignment work elsewhere than the mimi server, you might lose all of the assignment points. All of your solutions should be composed of commands that are executable in mimi.cs.mcgill.ca.
• Must be completed with vim
A goal of the class is to get you to be comfortable in a command-line text editor. This wouldn’t happen just from knowing the vim commands from slides: You become comfortable by using it a lot. Assignments are a good opportunity for that.
• You must use commands from class
In this assignment, anything in the C standard library is allowed. However, the emphasis in the assessment is on clarity and readability of the code. Do not do anything unnecessarily generalized, abstract, or complex, when simple, straightforward code suffices.
• Your code must run
Your code must run as-is and nearly instantly. TAs WILL NOT modify your code in any way to make it work.
• Please read through the entire assignment before you start working on it
You can lose up to 3 points for not following the instructions in addition to the points lost per questions.
1 A CSV-backed database written in C
In this assignment, your task will be to implement a command-line program called igdb in C for managing a persistent database stored as a CSV file. This is a simplified example of what C is actually used for in practice: writing fast, low-level data management software. The popular, high-performance, open-source relational database management system PostgreSQL is written in C, for instance.
Learning goals assessed:
1. Write robust system interactions in C.
2. Create custom data structures and algorithms in C.
3. Organize code in C for readability.
1.1 What’s in the database?
The database in this assignment is for tracking Instagram accounts. One record in the database stores the following information.
• Handle, e.g. @spottedmcgill
• Follower count, e.g. 14900
• Comment, e.g. a bit cringe tbh
• Date last modified, e.g. 1710521259
This record would be represented in CSV form as
@spottedmcgill ,14900 ,a bit cringe tbh ,1710521259
To accommodate the CSV file format, the characters '\0' (null) '\n' (line feed) and ',' (comma) are forbidden from appearing in the comment field.
1.2 Representing dates and times
You might have noticed that the “date last modified” above doesn’t look like a date at all...
Representing dates and times robustly can be a challenge in software engineering. A very common and straight- forward solution is to represent an absolute moment in time in so-called UNIX Epoch format. This is thenumber of secondselapsedsincemidnighton 1 January 1970. These are also called (UNIX) timestamps. This format is independent of timezones, which makes it great for storage in a database. User-facing applications convert these timestamps into human-readable “local time” strings, accounting for timezomes, when displaying the time to a user.
Your database will store UNIX timestamps, and your application must present these times in human-readable strings in the local timezone. The C standard library contains functions for working with UNIX timestamps and dates and times in general.
• You will need to #include <time.h>
• See man 2 time (get current timestamp)
• See man 3 localtime (convert timestamp into time structure in current timezone)
• See man 3 strftime (format time structure into string)
1.3 Representing database records in C
You must define a struct Record to represent a single line (record) from the CSV file (database). It must have one member for each of the fields of the record described above.
• The “handle” and “comment” fields must be character arrays (not pointers) with sizes 32 and 64 respectively.
• The “follower count” and “date last modified” fields must be of type long unsigned int
1.4 Representing the database itself in C
You must define a struct Database to represent a whole database. This will be an implementation of dynamic arrays, i.e. arrays that can “grow” during runtime, similar to the ArrayList class in Java or Python’s built-in list.
A dynamic array has three attributes: a pointer to an underlying (fixed-size) array, an integer called the capacity, and an integer called the size. The capacity is the length of the underlying array, and the size is the count of elements actually stored inside that array.
When we want to add an item to the end of a dynamic array, we have to check if there’s space left in the underlying array by comparing the size and the capacity. If the size is less than the capacity, then we can treat the size as the index at which to write the new item, then increment the size. Else, when the size has reached the capacity, a new underlying array with double thecapacity is allocated, the elements from the old array are copied to the new array, and the old array’s memory is freed, before proceeding as before.
You must implement the following functions for handling the dynamic array.
typedef struct Database { /* fill this in */ } Database ;
Database db _ create ();
// ^ The database must have initial size 0 and capacity 4 .
void db _ append ( Database * db , Record const * item );
// ^ Copies the record pointed to by item to the end of the database .
// This is where you need to implement the resizing logic described above .
Record * db _ index ( Database * db , int index );
// ^ Returns a pointer to the item in the database at the given index . // You need to check the bounds of the index .
Record * db _ lookup ( Database * db , char const * handle );
// ^ Returns a pointer to the first item in the database whose handle // field equals the given value .
void db _free ( Database * db );
// ^ Releases the memory held by the underlying array .
// After calling this , the database can no longer be used .
To implement these functions, you will need to use some of the standard library functions for memory management: check out malloc, calloc, realloc, and free.
As usual, you can check the documentation for these with, e.g. man 3 malloc.
1.5 Reading and writing CSV files
When the database application starts, it will load the file database.csv into memory, populating a Database object. When the application runs, the user will be able to command it to write the database. You will implement the following functions that accomplish reading and writing the whole database.
void db _ load _ csv ( Database * db , char const * path );
// ^ Appends the records read from the file at `path `
// into the already initialized database `db ` .
// (The given database does not have to be empty .)
void db _write _ csv ( Database * db , char const * path );
// ^ Overwrites the file located at `path ` with the
// contents of the database , represented in CSV format .
Of course, reading the database can be decomposed into two subproblems: parsing a single line of the CSV file into a Record structure versus looping over all the lines in the file to populate the whole database. Your code must reflect this separation of concerns by implementing and using the following function.
Record parse _record ( char const * line );
// ^ Parses a single line of CSV data into one Record
You must use the following standard library functions to implement the functions in this section.
• fopen to open files for reading or writing. You must call fclose on these when you finish reading or writing.
• getline reads a line from a stream. You must be careful to properly free any buffers that this function might allocate for you.
• fprintf writes formatted data to a given stream.
• strtok is used to break up a string according to a delimiter, such as ','.
As always, check the documentation in the man pages, e.g. man 3 getline.
1.6 User interactions with the database
The user manipulates the data in the database via interactive prompt. The below example session illustrates how this should work. Each line beginning with > is a prompt, and my input is given after it.
jerrin@teach -node -04:~ $ ./ igdb
Loaded 5 records .
> list
HANDLE | FOLLOWERS | LAST MODIFIED | COMMENT
----------------|-----------|------------------| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@spottedmcgill | 14900 | 2024 -03 -15 17:03 | a bit cringe tbh
@foo | 420 | 2024 -03 -13 13:37 | foo is foo
@bar | 8008135 | 2024 -03 -14 20:03 | go to bar
@foobar | 8008555 | 2024 -03 -15 17:01 | foo + bar = foobar
@quux | 1234567 | 2024 -03 -16 16:06 | how to pronounce quux?
> add @zzzz 98765
Comment > sleeping in is great zzzz
> list
HANDLE | FOLLOWERS | LAST MODIFIED | COMMENT
----------------|-----------|------------------| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@spottedmcgill | 14900 | 2024 -03 -15 17:03 | a bit cringe tbh
@foo | 420 | 2024 -03 -13 13:37 | foo is foo
@bar | 8008135 | 2024 -03 -14 20:03 | go to bar
@foobar | 8008555 | 2024 -03 -15 17:01 | foo + bar = foobar
@quux | 1234567 | 2024 -03 -15 17:03 | how to pronounce quux?
@zzzz | 98765 | 2024 -03 -15 17:08 | sleeping in is great zzzz
> update @bar 0
Comment > !!! account deleted !!!
> add
Error : usage : add HANDLE FOLLOWERS
> add @loo ooo ooo ooo ooo ooo ooo ooo ooo ong . name 12345
Error : handle too long .
> add @short . name 12345
Comment > ummm , this is a comment
Error : comment cannot contain commas .
> add @short . name lmao
Error : follower count must be an integer
> list
HANDLE | FOLLOWERS | LAST MODIFIED | COMMENT
----------------|-----------|------------------| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@spottedmcgill |
| 14900 |
| 2024 -03 -15 |
17:03 | a bit cringe tbh |
@foo |
| 420 |
| 2024 -03 -13 |
13:37 | foo is foo |
@bar |
| 0 |
| 2024 -03 -15 |
17:09 | !!! account deleted !!! |
@foobar |
| 8008555 |
| 2024 -03 -15 |
17:01 | foo + bar = foobar |
@quux | 1234567 |
| 2024 -03 -15 17:03 | how to pronounce quux? |
@zzzz | 98765 |
| 2024 -03 -15 17:08 | sleeping in is great zzzz |
> update @wow 12345 |
|
Error : no entry with handle > add @spottedmcgill 12345 |
@wow |
Error : handle @spottedmcgill > exit |
already exists . |
Error : you did not save your > save |
changes . Use `exit fr ` to force exiting anyway . |
Wrote 6 records . |
|
> exit |
|
jerrin@teach -node -04:~ $ |
|
Here is a detailed description of the commands that your interactive mode must support.
• list – print out the whole database formatted as a table. For the widths of the columns, you can choose a fixed width, but make sure that the output always looks like a decent table. For instance, if you choose a fixed width of 20 characters for the handle, but the handle is 25 characters long, you should truncate the remaining extra characters from the handle to make it fit in the column. The same applies to the comment. This can be accomplished using the “width” and “precision” modifiers for the %s directive of printf.
• add HANDLE FOLLOWERS – adds a new entry to the end of the database. That handle must not already exist in the database. A follow-up prompt is generated to ask the user for the value of the comment field.
• update HANDLE FOLLOWERS – updates an existing entry for the given handle. An entry for that handle must be present. A follow-up prompt is generated to ask the user for the value of the comment field.
• save – writes the database out to the file database.csv
• exit – quits the program, but warns the user about unsaved changes if any.
As in the previous assignment, your implementation must be robust in the face of userinput. Therefore, for things such as integers written by the user in prompts, you will need to use strtol as in the previous assignment to ensure that valid input is given.
However, you may assume that the CSV file is well-formed, so you do not need to validate, for instance, that the value stored in the follower count column contains only digits.
2 What to hand in
This assignment comes with starter code.
You should modify the files database.c, database.h, and igdb.c from the starter code, providing the implemen- tations for all the functions described above.
The starter code contains a Makefile, which you can run via the command make. This will compile each C file separately and then link them together into an executable igdb.
On MyCourses, you must submit a zip file containing database.c, database.h, igdb.c, and the Makefile.