CS 43 — Lab 0: C Warm Up
Due: Thursday, January 27 @ 11:59 PM
To incentivize completion, students who successfully complete all aspects of this lab will receive one additional "late day" for use on labs later in the semester.
For these exercises, you may either work alone or work with up to one partner.
If you work with a partner: add a comment to the top of your .c
files
indicating who you worked with. You must both submit your solutions to
GitHub.
Overview
This lab is a gentle refresher for C programming. It has two exercises:
-
Haiku: a C string warm up. Completing this exercise will help you construct the messages you’ll need to send in lab 1.
-
Filling an integer array: working with a function that will give you data in pieces. Completing this exercise will familiarize you with the behavior of the
recv
function, which you’ll use in lab 1 to receive data from the network.
For these programs (and all future C programming assignments), you should get into
the habit of always running them with valgrind
. If you have memory issues
(e.g., segfaults), valgrind
will tell you where they’re coming from. Even if
you don’t have segfaults, valgrind
will tell you if you’re doing something
that might be a problem.
Lab 0 Goals:
-
Recall how to program in C
-
Practice with strings in
haiku
-
Simulate
send
/recv
buffer management behavior infill_int_array
1. Haiku
You probably haven’t done much C programming recently. Even if you have, you probably haven’t used string functions much. We’ll be using strings for the protocols we implement in labs 1 and 2, and students often struggle more with the strings than the networking function calls.
This warm up exercise will get you reacquainted with C string functions. You’ll use a short template to generate digital haiku poetry. Since this program is essentially a Mad Lib, it’ll be up to the user to ensure the proper number of syllables (your program should not try to enforce syllables)!
The template is (note the spaces):
a new NOUN arrives the ADJECTIVE air begins to blow NOUN will come next
Your job is to fill in the template based on user input to construct a full
haiku. Actually, you’ll do it twice, using two different methods. For the
first, you’ll use a strcpy
and strcat
. For the second, you’ll use
sprintf
.
At a terminal, use the man
command to access the manual page for these
functions to get the details of how they work.
1.1. Requirements
-
I’ve provided a
main
function for you. You should NOT changemain
— it’s already set up. You only need to implement the other two functions. -
The
build_haiku_strcat
function should allocate enough memory to store the full haiku in theresult
variable using malloc. It should then make a sequence ofstrcpy
andstrcat
calls to fill inresult
according to the template and the passed-in user values. It should ultimately returnresult
(a pointer to the fully-constructed haiku). -
The
build_haiku_sprintf
function should allocate enough memory to store the full haiku in theresult
variable using malloc. It should then make just one call tosprintf
to fill inresult
according to the template and the passed-in user values. It should ultimately returnresult
(a pointer to the fully-constructed haiku). -
Your program should generate no warnings from
valgrind
. Ifvalgrind
ever tells you something is wrong DON’T IGNORE IT! Fix it before moving on. Note that the providedmain
function is freeing the memory you allocated in your twobuild_haiku_
functions. -
Any time you call a function that can fail (e.g.,
malloc
or any system call), you MUST check the function’s return value for failure. If a critical function fails, you can just terminate your program with a call toexit
.
1.2. Examples
User input shown in bold.
$ valgrind ./haiku ==2538227== Memcheck, a memory error detector ==2538227== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==2538227== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info ==2538227== Command: ./haiku ==2538227== Enter a noun: fall Enter an adjective: cool Enter a noun: homework strcat version: a new fall arrives the cool air begins to blow homework will come next sprintf version: a new fall arrives the cool air begins to blow homework will come next ==2538227== ==2538227== HEAP SUMMARY: ==2538227== in use at exit: 0 bytes in 0 blocks ==2538227== total heap usage: 4 allocs, 4 frees, 2,848 bytes allocated ==2538227== ==2538227== All heap blocks were freed -- no leaks are possible ==2538227== ==2538227== For lists of detected and suppressed errors, rerun with: -s ==2538227== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
$ valgrind ./haiku ==2538855== Memcheck, a memory error detector ==2538855== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==2538855== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info ==2538855== Command: ./haiku ==2538855== Enter a noun: doge Enter an adjective: much Enter a noun: wow strcat version: a new doge arrives the much air begins to blow wow will come next sprintf version: a new doge arrives the much air begins to blow wow will come next ==2538855== ==2538855== HEAP SUMMARY: ==2538855== in use at exit: 0 bytes in 0 blocks ==2538855== total heap usage: 4 allocs, 4 frees, 2,848 bytes allocated ==2538855== ==2538855== All heap blocks were freed -- no leaks are possible ==2538855== ==2538855== For lists of detected and suppressed errors, rerun with: -s ==2538855== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
2. Filling an integer array
When you receive data from the network, you often don’t know in advance how
much data the other side is going to send you. To simulate this, I’ve written
a function for you, called get_ints
, which you’ll repeatedly call until it
tells you (via its return value) that no more data is coming. (This is very
similar to the way that we’ll use the recv
function in lab 1.)
When you call get_ints
, you pass in a pointer to the location where you want
it to store integers for you. It will randomly chose how many integers to
store at that location (up to some max that you can choose), and its return
value will tell you how many it stored. If it returns 0
, that means it has
no more integers for you, and you should stop calling it.
The function’s prototype is:
int get_ints(int *destination, int at_most);
When you call get_ints
, you provide it with:
-
destination (integer pointer):
get_ints
will fill in integers starting at the location this pointer points to. Note that you (the caller) are responsible for ensuring that the memorydestination
points to has enough space to store the integers — theget_ints
function does not allocate memory for you. -
at_most (integer):
get_ints
will fill in no more than this many integers into the destination. It might (and often will) fill in fewer than this many though!
get_ints
returns the number of integers it copied to the destination. If it
copies no integers (and returns 0
), that means it’s done, and you don’t need
to call it again.
The number of integers it will ultimately copy is randomized to prevent you
from hard coding a stopping point, but you may assume that it will be no more
than GET_INT_MAX
, which is #define
d to be 200.
The integers it produces just count by 10’s, starting from 0. That is, when your program is done, your integer array should contain:
Index | Value |
---|---|
0 |
0 |
1 |
10 |
2 |
20 |
3 |
30 |
… |
… |
I recorded a short YouTube video to help visualize how this function behaves and how you want to call it. You need to be logged into your @swarthmore.edu Google account to view it. |
As you repeatedly call get_ints
, you should store the integers consecutively.
For example, lets say you start with an empty array and you call get_ints
,
which returns 7
. That means the first 7 positions of the array (indices 0-6)
have now been filled in. The next time you call get_ints
, you should tell it
to start filling in at the address of position 7, to pick up where you left off
(and to preserve the first 7 items that you already copied). Thus, you’ll need
to keep a running sum of how many integers it has filled in so that you can
keep resuming where you left off.
Each time you call get_ints
, you should pass in at_most
to indicate how
many integers you’re willing to accept (based on the amount of remaining memory
you have allocated at the destination). Using the example above, the first time
you call get_ints
, you’d pass in GET_INT_MAX
, since you haven’t yet filled
anything in. After it returns 7
, the next you call get_ints
, you’d want to
pass in at_most
as GET_INT_MAX - 7
, since you’ve already filled in 7
values. Adjusting at_most
downward each time will ensure that you don’t
overflow your array.
2.1. Requirements
-
For this exercise, the code in
get_ints.c
is provided for you, and you shouldn’t modify it. You’re welcome to look at it, although you don’t need to understand how it works to complete the lab. -
You should only edit
fill_int_array.c
, and in that file, you only need to fill in themain
function. Yourmain
must:-
Allocate enough memory to store all the integers you might ever need to store.
-
Call the provided
setup
function to randomizeget_ints
's behavior. -
Repeatedly call
get_ints
, storing the integers consecutively, until it returns 0. -
Call
check_ints
on your integer array to verify that they’re stored correctly. -
Free any memory you dynamically allocated (if you dynamically allocated any).
-
-
Your program should generate no warnings from
valgrind
. Ifvalgrind
ever tells you something is wrong DON’T IGNORE IT! Fix it before moving on. -
Any time you call a function that can fail (e.g.,
malloc
or any system call), you MUST check the function’s return value for failure. If a critical function fails, you can just terminate your program with a call toexit
.
2.2. Examples
The output here isn’t particularly interesting:
$ valgrind ./fill_int_array ==2549853== Memcheck, a memory error detector ==2549853== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==2549853== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info ==2549853== Command: ./fill_int_array ==2549853== Looks good! ==2549853== ==2549853== HEAP SUMMARY: ==2549853== in use at exit: 0 bytes in 0 blocks ==2549853== total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated ==2549853== ==2549853== All heap blocks were freed -- no leaks are possible ==2549853== ==2549853== For lists of detected and suppressed errors, rerun with: -s ==2549853== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
The Looks good! comes from check_ints
. It will complain if the integers in
your array aren’t consecutively counting by tens.
Submitting
Please remove any excessive debugging output prior to submitting.
To submit your code, commit your changes locally using git add
and git
commit
. Then run git push
while in your lab directory.