Before starting the coursework, check your feedback for the grade assignment, by looking in the folder where you submitted the work. The feedback doesn't yet include extra work done. If you didn't get 50%, try to make sure you don't make the same mistakes this week.
The coursework this week counts for 25% of your credit for the unit. The main purpose is to continue to practice writing simple programs, and particularly to understand how to achieve precision. The first half of the assignment is to write a triangle classifier, and the second half is open ended. You may need information from the lecture notes up to the statements chapter.
You are asked to write a program which reads in three integers representing the lengths of the sides of a triangle, and then prints out the type of triangle.
The program should take its input from the command line, and print its output on the standard output, e.g.
./triangle 3 4 6 Scalene
The possible responses are:
Equilateral (all sides equal) Isosceles (two sides equal) Right (has a right angle) Scalene (sides unequal, but no right angle) Flat (lengths add up exactly, so no area) Impossible (lengths don't add up) Illegal (lengths are invalid)
You are given this skeleton as a starting point:
triangle.c (old triangle.c)
Makefile
Here are some notes about its design:
Last week, some people, though not all, had problems with the terminal
window freezing after a call to assert
. We have failed to find
out why that is. So, this week, the skeleton has been changed to use a custom
version of the assert
function. The original version is still
available, and can be used or studied if you want. The changes are that the
inclusion of assert.h
has been deleted, a definition of
assert
has been written, and each call to assert
has
had an extra argument added to pass in the line number of the test.
Try compiling it and running it like this:
$ clang -std=c11 -Wall triangle.c -o triangle $ ./triangle 5 5 5 Equilateral $ ./triangle ... assertion fails on line ...
or preferably like this:
$ make $ ./triangle 5 5 5 Equilateral $ ./triangle ... assertion fails on line ...
At the moment, if you run it with three integer arguments, the program prints
out Equilateral
all the time.
If you run the program without arguments, it carries out the tests. That is what
you should be doing most of the time while you are developing.
At the moment, only
the first couple of tests pass.
it.
The skeleton seems long, because of all the tests. There are lots of them, because there are surprisingly many quirky details, and because they are designed to catch every mistake that any student is ever likely to make. In a 'real' project, there would probably not be so many.
You are unlikely to need to write more than about 20 or 30 lines of code.
The first part of the program is the part you are supposed to work on.
That's the convert
and triangle
functions, and any
supporting functions you choose to add. The rest is the tests and user
interface, which you should not change.
triangle
returns an integerThe triangle
function returns an integer constant
representing the type of triangle. Named constants are used rather than strings
because (a) the compiler will tell you if you miss-spell them (b) it separates
the symbolic issue of classification from the textual issue of printing, e.g.
making it easy to change to a language other than English (c) it
makes testing marginally easier and (d) it avoids pointer notation, which would
be needed if a string was returned.
Note that C doesn't allow you to define a 'safe'
enumerated type for constants. Any type name you use (e.g. enum
type
) is just a synonym for int
The skeleton provides two functions convert
and
triangle
which will be tested. If either of those expands beyond a
very few lines, it is strongly recommended that you define
one or two support functions, e.g. a
valid
function for checking if a
string length is valid, or a
separate function to handle each type of
triangle. That isn't necessary if you have a compact programming style, because
each of the types can be checked in one line of code, but it may be a good
idea if your style is more verbose. Either way, your aim should be to keep each
of your functions very short.
Your initial aim should be to make at least one more test pass. When that works, tackle the next test that fails until you can get it to pass, and so on. As it says in Alice in Wonderland: "Begin at the beginning, go on till you come to the end: then stop." Here are some notes on development:
The tests form the specification of the program, filling in the gaps in the quick description above, and illustrating all the nitty gritty details of what your program is supposed to do. So you should study them carefully, especially the one that currently fails.
The first thing to do is, for example, add a couple of lines to
triangle
to test for the isosceles case.
There's a good chance the program won't compile immediately, but you must work at it, solving any problems, until it compiles and runs again, before trying to achieve more.
The program should now pass at least one more test.
The number of tests your program passes before failing is a rough measure of progress. Your program will be compiled and run for marking (using a clean copy of the tests) and the number of tests passed out of the 50 before it fails will be your mark for the first half of the assignment.
The general approach to software deveopment we are trying to promote is agile development. There is more to it than you've experienced so far, so you are an apprentice-level agile developer. The specific technique for this assignment is test driven development, and is a very powerful technique for confident development of robust programs. Of course, you would normally have to design the program yourself so that it supports testing, and create your own tests.
The triangle
function needs to do various checks on the three integer lengths. These have
to work no matter what order the lengths are in. You can either do several
checks, or you can sort the lengths into order first (just by doing a couple of
swaps, not necessarily using a full sorting algorithm). The two approaches are
about equally good. If you are careful about the order of the checks for
the different types, that can make the checks much simpler.
The convert
function needs to check if a string is valid, and in range, and convert it into an
integer.
There are at least three approaches to validity chacking. One is to do it yourself, with a loop, before conversion. A second is to use a conversion function which provides enough extra information, beyond just the result, to help with validity checking. The third is to use a clever trick: convert the string to an integer using a simple conversion function, and then convert back to a string, and compare with the original string, catching all validity issues in one go.
To check if the integer is in range, you could either do suitable checks on
the string before conversion, or convert to an integer type bigger than
int
and check the range before putting it into an int
variable.
To find the length of a string (if you need it) use strlen
. To convert a string to an integer, you can either use a simple function
like atoi
or atol
, or a more complex function
like strtol
if you want to get validity information from it.
To convert an integer back to a string, use sprintf
, and to
compare two strings, use strcmp
. Type C atoi
into
Google, for example, to find the documentation for a function.
To avoid a 'magic number' for the maximum allowable length, you can use
INT_MAX
, which is defined in limits.h
.
The last few tests are designed to catch overflow problems. This is when
integers exceed the limit of the int
type. You might consider
switching to the long
type in parts of the program where you think
overflow might occur. It is OK for this assignment to assume
that int
s have 32 bits and long
s have 64 bits.
If you have time, and if you are interested or you want more than 50% for the assignment, you can do some extra open-ended work. Write any program you want in C (of the same sort of scope as the triangle program) which involves simple classification or calculation.
Submit the source file, and a file readme.txt
(or a pdf file)
which describes your aims for the program and how far you got with it. There
are no marks for report writing, but the report may be necessary for us to make
sense of the program.
A mark out of 50 for the extra work will be awarded by swiftly reading the report, checking whether your program matches what you claim, judging the sophistication of what has been done, and checking whether the program follows the conventions and advice in the lectures. In particular, writing tests as part of the program, in the same way as the skeletons, is very much recommended (though you only need enough tests to make you confident). Also recommended is working in very small steps, one test at a time, keeping your program in a working state.
The mark will aim to make your total for the assignment meet the university scale. So assuming you get full marks for the triangle program, 10/50 means "this raises your total result from average to good", 20/50 means "overall first class", 30/50 means "overall above and beyond what was expected" and 40/50 means "publishable in a research journal".
Submit your program triangle.c
(not Triangle.c
or
any other name, unless you want to lose marks, and not the compiled
program). Make sure your program compiles without warnings, runs, and doesn't
still contain
debugging print statements. Feel free to resubmit it if you improve it before
the deadline (using the same filename).
Submit your extra program, if any, and a readme.txt
file
with any comments you might want to make.