The coursework this week will not count towards your credit for the unit. The main purpose is for you to make sure everything is set up properly for the unit.
If you don't want to sort your own computer out now, skip this step and carry on using the lab computers.
You will probably want to do some of the work for this unit on your own computer. If so, there may be some installation work to do. See the aside on computers for details.
Atom: Read the aside on editors to see why we recommend Atom. If you choose to use it, go to https://atom.io/ and download and install the version of Atom for your computer.
Whether you are using a lab workstation, or a Linux or Mac computer, or Windows with Cygwin for example, you will need to get used to running Unix commands in a terminal window.
Read the aside on Unix commands and try some of them out on a lab workstation or your own computer.
Warning: typing commands is more powerful than using a
graphical interface, but also more dangerous, e.g. if you type
rm file
to delete a file, it has permanently gone - there is no
'recycle bin'.
Try out the Atom editor, or sort out which editor you want to use (gedit, for example).
To make sure everything is set up properly, edit, compile and run a Hello World program. Here are some files you can download:
download or copy-paste the hello.c
file above (which is
the same as in the lecture notes).
compile it using the C compiler clang
(or gcc
)
by typing the command:
clang hello.c -o hello
run the program by typing the command:
./hello
edit the file hello.c
so that it prints something else
out (keep it clean!).
recompile it - use the up arrow key to find the command you used before, then press enter to execute it, so that you don't have to retype it.
run it again, and check that it prints out your new message.
download the relevant Makefile above (renaming it back to
Makefile
if it gets downloaded as Makefile.exe
)
compile the program properly, with all the right options, by typing the command:
make
Warning: typing clang ... -o hello.c
tells
the compiler to put the compiled program in hello.c
instead of into
a different file. After that, your source program has been destroyed and can't
be recovered.
Once you have succeeded in compiling and running an altered Hello World
program, submit your program file hello.c
on SAFE. Read the aside on submission to find out how. The
submission is for three purposes:
You'll get a mark: 25% each for submitting something, for the filename being
correct (not Hello.c
or anything else), for it compiling, and for
it running. The submission system subtracts 10 if you submit a day late,
also caps your mark at 40 if you submit within a week late, and prevents you
from submitting after that. If you do submit late, you may have to ask
explicitly for your work to be marked.
There won't be any individual online feedback for this assignment. All your feedback for this assignment comes from asking questions in the lab. Please ask the student next to you, or put your hand up. Talking to other students, lab helpers, and lecturers is healthy and welcome.
make
The remainder of this assignment is not for submission, or marks, or feedback beyond the questions you ask in the lab. It is about exploration.
Explore the aside on make, try out the examples, and decide how you are going to issue compile commands in future.
Also, read any of the other asides that interest you.
Write a program square.c
containing a function
square
which squares an integer, and a function main
which finds and prints the square of 42
.
Find the hello.c
program (from the lecture notes if you don't
have it already), make a copy in a
file called square.c
, and use it as a starting point. In C,
multiplication is done with the *
operator, so "x
times y
" is written x * y
Overall, your program should look like this:
/* Demo: a squaring function. */ #include <stdio.h> ... square(...) { ... } int main() { ... }
All you have to do is fill in the ... parts.
Try sorting out the main
function from here
Your main
function should look something like this:
/* Demo: a squaring function. */ #include <stdio.h> ... square(...) { ... } int main() { int n = square(42); printf("42 squared is %d\n", n); return 0; }
The important thing is that the call to square
should just
be square(42)
(or equivalent).
Here's a complete answer:
/* Demo: a squaring function. */ #include <stdio.h> int square(int n) { return n * n; } int main() { int n = square(42); printf("42 squared is %d\n", n); return 0; }
Don't worry if you didn't manage it without looking at the answer
Use the program square.c
to find the square of
50000
. It should be clear to you that it hasn't worked. Can you
work out why?
Edit the file square.c
.
Replace 42
by 50000
.
Recompile it, and then rerun it
Squaring 50000
gives a negative answer. That's because the int
type has a limit to the numbers it can store, and 2500000000
goes
beyond that limit. That's called an overflow.
The C language, for efficiency, like almost all other languages, doesn't
detect and report overflows, it just accepts whatever the processor produces
(it uses signed modulo arithmetic, modulo 2^32
).
Write a program interest.c
which uses the double
type to calculate interest on savings. It contains a function add
which takes an amount of money, and a percentage rate of interest, and works out
the total after adding the interest. And it has a function main
which finds the total after adding 2.7
percent interest to
1000.0
pounds
Your program should look something like this:
/* Calculate interest. */ #include <stdio.h> double add(double amount, double interest) { ... } int main() { double a = 1000.0, i = 2.7; double total = add(a, i); printf("Adding %f%% interest to %f gives %f\n", i, a, total); return 0; }
In a printf
call, %%
prints out a percent
character.
Your add function should look something like this:
double add(double amount, double interest) { amount = amount + amount * interest / 100; return amount; }
The integer constant 100
gets converted to double, or you can
write 100.0
if you prefer
If you wanted to work out 5%
interest without using the add
function, you might write:
double total = amount + amount * (5 / 100);
If you try this, it doesn't work - why? How can you fix it?
When 5 / 100
is calculated, the integer constants don't get
converted to double. An integer division is done, throwing away any remainder,
so the result is 0
(which then gets converted to double, i.e.
0.0
, when multiplied by amount
). Conversions only
happen where an int and a double are combined. Writing 5.0
or
100.0
or both solves the problem
Find the limits of the int
type in the C language. Specifically,
find the largest number which can be correctly stored in a variable of that
type. Start with this program:
/* Find the limits of the int type */ #include <stdio.h> int main() { int n = 42; printf("%d\n", n); return 0; }
Plan A Increase the constant in the program from 42
to 43
, recompile, and rerun, checking that the number gets printed
out properly. Repeatedly increase the number by one until the number isn't
printed properly. When you get bored with this approach, switch to Plan B.
Plan B Use manual interval halving. First guess a giant number which
isn't printed out properly, so you have a range within which the answer must
lie. Then repeatedly try the above program with n
set to a number
half way through the range, so as to reduce the size of the range by a half and
home in on the answer. This is still very tedious, but feasible (it is likely
to take around 30 steps).
Three billion 3000000000
is a suitable
giant number which isn't printed out properly
Plan C Find out how to write a loop. Also find out how to check
whether a number has become too big to fit in an int
variable,
without printing it out. Then write a loop which increases a number until it
gets too big.
A suitable loop would be something like:
while (...) { n = n + 1; }
This repeatedly increases n
by 1
. The
...
needs to be a test for whether n
is too big or not
When a number goes past the limit, it 'wraps round' and becomes negative, so
n+1 < 0
means "n+1
has gone past the limit"
Alternatively, you could say that if n
is the largest
int
, then n+1
can't be bigger, it must be something
within range, so n+1 <= n
is also a good test to tell you that
n+1
has gone past the limit
/* Find the largest int. */ #include <stdio.h> int main() { setbuf(stdout, NULL); int n = 0; while (n+1 > n) { n = n + 1; } printf("The largest int is %d\n", n); }
Incrementing: increasing an integer variable by one is
called incrementing, and the abbreviation n++
can be used instead
of n = n + 1
. It is a matter of taste which you write. Both are
very common, so you definitely need to be able to read both.
Efficiency: the program performs a few billion operations,
and probably takes about 10 seconds when you run it. You can imagine that
there are many circumstances when a delay of 10 seconds would not be
acceptable. And finding the limit of the long
type
would need a few billion billion operations,
and take longer than your lifetime. So finding a faster method would be
essential in that case.
Plan D Write an interval halving loop. Use two variables to represent the current range, and repeatedly try the number half way in between.
This is harder than the previous loop, because we need to keep track of an
actual number which is larger than the maximum int
The type long
(abbreviation for long int
) stores integers
bigger than int
.
You need to find a way to check whether a number n
held in a
long
variable is beyond the int
range or not.
If you put a long
number ln
into an int
variable n
, then the two numbers ln
and n
are equal only if the number n
is within the
int
range
The important bit of the program is something like:
long low = 0; long high = 1000000000000000000; long mid; int test; while (low < high - 1) { mid = low + (high - low) / 2; test = mid; if (test == mid) low = mid; else high = mid; } printf("The largest int is %ld\n", low);
In printf
, %ld
is needed instead of %d
to print out a long
variable.
Note: low + (high - low) / 2
is a superior way of finding the
average half way between two numbers. The obvious alternative (low +
high) / 2
suffers from overflow a bit too soon.
Plan E Find an official way, according to the C language standard, to
find out what the largest int
is. And find out the real truth.
By typing C11 standard
into Google, you can find a PDF of the
language standard.
The standard says that if you include limits.h
, it provides the
constant INT_MAX
The simplest program to find out the maximum int
is:
/* Find the largest int. */ #include <limits.h> int main() { printf("The largest int is %d\n", INT_MAX); return 0; }
We've only found the answer on our computer. Is it the same on every
computer? No, because the standard says int
is the "most
convenient or most efficient integer type" on each computer. We happen to be in
a fairly stable age at the moment where int is usually 32 bits, but it used to
be 16 bits, and it may become 64 bits in the future.
The number printed out is 2147483647
, which is
231 - 1
. This is because an int is stored in binary
using 32 bits (4 bytes), and the first bit is used as a sign. Arithmetic using
int
is actually "signed modulo 232 arithmetic".
If you have time left after that, try to find the smallest (most negative)
number that can be held in the int
type, and do some
investigations of some other basic types in C
(char
, short
, long
, float
,
double
, bool
), and have a look at the
the aside on characters.