The goal of this lab is to learn basic C structs.
You are writing software for a Twitter knock-off called Chatter. In the Chatter system, users send messages whose text is at most 140 characters long. Additionally, each message has the user id of the user who sent the message (at most 16 characters long), a time stamp indicating the time the message was sent (a long int indicating the number of milliseconds since midnight, Jan 1, 1970), and up to 5 hash tags indicating categories or topics the message falls under (each hash tag is at most 10 characters long).
I have provided some code for producing "random" text components and "random" user names. Your tasks will include designing and implementing a struct to represent messages, writing functions for displaying and sorting messages, and completing drivers to test these messages.
Set up a new directory for this lab and move into it.
mkdir lab3 cd lab3
Copy starter code from the course directory.
cp /homes/tvandrun/Public/cs245/lab3/* .
This will give you the following files:
chatter_util.h
, the header file for a library
of content-creating functions for you to use.
chatter_util.c
, the implementation file of that library.
message.h
, the header file for the message struct
(which you will have to complete) and the prototypes for
the functions that operate on messages.
message.c
containing function stubs.
makefile
test_message_def.c
,
test_new_message.c
,
test_display.c
,
test_count_user.c
,
and test_hashtag_filter.c
,
files to test your code at different stages.
You don't need to look at these (but go ahead if you're curious).
The chatter_util
library provides the following
functions:
randomInt()
: produce a uniformly-distributed random int
between 0 (inclusive) and a given int (exclusive).
For example randomInt(4)
will return 0, 1, 2, or 3,
with equal probability.
getTimeMillis()
: return the current time
fillRandomText()
: fill the given char
array with a string containing a randomly chosen text
for a chatter message
fillRandomUserName()
: fill the given
char array with a string containing a randomly chosen
text for a user name
fillRandomHashCode()
fill the given
char array with a string containing a randomly chosen
hash tag
You need to complete the following tasks:
The first thing is to design and implement a struct to
represent chatter messages.
This is kind of like writing a class in Java, but simpler.
I have already set up a dummy
struct for a message
type
in message.h
.
Write the message
struct.
Think about the components to a message and how one would
store that information.
Recall from the in-class examples that you can
declare static arrays inside a struct type.
Since you haven't written any functions yet,
there isn't much to test.
However, you can make sure you didn't make any syntax errors
by compiling something that uses the message
type.
The test case test_message_def
will also
catch a few possible mistakes.
Make and run this test case:
make test_message_def ./test_message_def
If you get Test passes
, then you're still not
guaranteed you have the struct exactly right, but you can move on.
If you get an error message, then first figure out what's wrong.
Now we need to produce a new message, that is, a value
of our new message
type.
The header file message.h
gives the prototype for the function newRandomMessage()
which is used by the two driver programs.
Write a definition for this function in the
implementation file message.c
for the message library.
Use the functions from chatter_util
to
produce the text, user name, and hash tags:
getTimeMillis()
to make a timestamp for
this message.
fillRandomText()
to populate the part
of the message struct that contains the message itself.
fillRandomUserName()
to populate the
part with the user name.
randomInt()
to determine the number of
hash tags.
fillRandomHashCode()
to fill
in each of the hash tags.
Recall that a message can have at most 5 hashtags, but
the message you're making will have however many you determined there
to be by calling randomInt()
You can test this using test_new_message
.
Of course, in all this you may discover problems with how you made
the struct in the previous step.
make test_new_message ./test_new_message
Since there is more than one way to design the message
struct, this test case can't test what you've done precisely.
If you've written this correctly, this test might still
generate a warning.
Try again, and (again, if you've written correctly) it should pass.
I think I have written this is such a way that if you have
left out something big, then it will not pass.
The headerfile message.h
gives the prototype for the function display()
which displays a message to the screen, nicely formatted,
showing all the information stored about that
message.
The display of a message should look something like this:
----------------------- Sent by Verna at 1315499047608 Q: How can you tell if an elephant is in the refrigerator? A: The door won't shut. #mischief #concert #admiration #concert
If you want the date to appear as something nice looking instead of a number of milliseconds, instructions for that are found in the optional section at the end of this lab description..
Write the implementation of display()
in
your message.c
.
Test this using test_display
make test_display ./test_display
This will not report whether there was an error or not, it
will simply show you the results.
You need to inspect them to make sure they are right.
(Of course there could be an error from having your program crash.)
There are three tests- displaying one message, displaying three
messages, and displaying an array of 10 messages.
This will be a fair amount of output.
You'll have to scroll up to see it all, or you could send the output to a
file.
To send the output of this program to a file called results
,
do this:
./test_display > results
You then can open results
in the text editor,
which might make it easier to read.
Remember, this is testing everything you've done so far, so if it's not right, you may need to go back to an earlier step.
Our next task is to write a function that will take an array of messages and the name of a user of the system and count how many of the given messages were sent by the indicated user. Essentially you will need to loop over the array, checking the userid of each message and seeing if it matches the userid given as a parameter, counting the number of matches.
To compare strings in C, use the function strcmp()
.
This takes two strings (that is, character arrays)
and returns 0 if they are equal.
(This function can also be used to put strings in alphabetical order;
it will return a negative number if the first string comes first
alphabetically and a positive number if the second string comes first.)
Write the function countForUser()
.
Test it using the program test_count_user
:
make test_count_user ./test_count_user > results
This program will display 50 messages and then indicate how many
occurrences of a chosen userid there are.
Notice that I'm suggesting sending the output to a file named
results
(which will overwrite any older file of the same name---you can name it
something else if you want.).
Verify that your function works by counting the number of
messages sent by that user and seeing if it matches
the results returned by your function.
(You can search for a string in emacs or xemacs using ctrl-s ("s" for "search)
or in gedit using ctrl-f ("f" for "find").)
Test and verify several times.
The final task is to take an array of messages and search
for ones that have a given hashtag.
The function filterByHashTag()
.
This function is given two arrays: one contains a sequence of
chatter messages (original
),
and the other can be regarded as "blank" (filtered
).
It also takes parameters indicating the number of messages
in the array and a hashtag.
This function should iterate over the array of messages
and check each message to see if it has the hashtag.
If it does, that message is copied into filtered
.
The function also returns the number of messages
that have the hashtag (and thus have been copied into
filtered
).
One thing that makes this task harder than the previous
is that a message may have up to five hashtags.
For each message, we need to see how many hashtags
the message has and check each one against the given
hashtag (again using strcmp()
).
Write the function filterByHashTag()
.
Test it using test_hashtag_filter
:
make test_hashtag_filter ./test_hashtag_filter > results
This test program will print the original list, the hash tag it's looking for, and the filtered list returned by your function. Check the results to make sure that all (and only) the messages that contain that hashtag are found in the filtered list.
If you want to make a readable formatting of the time stamp, do the following things to your code:
sys/time.h
in message.h
time.h
in message.c
time_t
instead of long int
newRandomMessage()
,
don't use the getTimeMillis()
function that I provided but instead
use the function time()
.
Pass it the timestamp portion of the struct preceded by an ampersand.
For example, time(& (toReturn.timestamp));
display()
, use the function ctime()
to convert time to a string.
For example, if you named the field containing the userid uid
,
then you could print the first line of the message as
printf("Sent by %s at %s\n", msg.uid, ctime(& (msg.timestamp)));
Then the display of a message would look something like
----------------------- Sent by Willis at Thu Sep 8 12:32:37 2011 Q: Why do elephants stomp on people? A: They like the squishy feeling between their toes. #surplus #moisture