Coursework: Week 1, Getting Started

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.

install

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.

look into Unix commands

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).

run a Hello World program

To make sure everything is set up properly, edit, compile and run a Hello World program. Here are some files you can download:

hello.c
Makefile

  1. download or copy-paste the hello.c file above (which is the same as in the lecture notes).

  2. compile it using the C compiler clang (or gcc) by typing the command:

    clang hello.c -o hello
    
  3. run the program by typing the command:

    ./hello
    
  4. edit the file hello.c so that it prints something else out (keep it clean!).

  5. 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.

  6. run it again, and check that it prints out your new message.

  7. download the relevant Makefile above (renaming it back to Makefile if it gets downloaded as Makefile.exe)

  8. compile the program properly, with all the right options, by typing the command:

  9. 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.

submit

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.

investigate 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.

try squaring

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.

Hint 1

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

Hint 2

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

Hint 3

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).

Answer

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

make squaring go wrong

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?

Hint

Edit the file square.c. Replace 42 by 50000. Recompile it, and then rerun it

Answer

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).

generate interest

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

Hint

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.

Answer

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

make interest go wrong

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?

Answer

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

check limits

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).

Hint

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.

Hint

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

Hint

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

Answer
/* 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);
}

 

Some details

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.

Hint

This is harder than the previous loop, because we need to keep track of an actual number which is larger than the maximum int

Hint

The type long (abbreviation for long int) stores integers bigger than int.

Hint

You need to find a way to check whether a number n held in a long variable is beyond the int range or not.

Hint

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

Answer

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.

Hint

By typing C11 standard into Google, you can find a PDF of the language standard.

Hint

The standard says that if you include limits.h, it provides the constant INT_MAX

Program

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;
}

 

The truth

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.

Some details

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.