C - From The Top (part 2)

Answers to last time's problem:

Remember, the code snippet was this:

#include <stdio.h>;
int main(void)
{
 printf("Hello there\nWho are you? ");
 scanf("%s",name);
 printf("Please to meet you %s",name);
 return 0;
};

The three mistakes were

  1. the semicolon at the end of the #include line,
  2. name wasn't defined and
  3. the semicolon at the end of the function isn't required.

Variable types

Broadly speaking, there are four main variable types in C: integers (int), characters (char), floating point (float) and double precision (double).

The way variables in C are addressed though isn't as simple as in Basic. You can still have the constructs such as:

BasicC
a%=5int a=5;
pi=3.1416float pi=3.1416;

However, you will notice that the variable type has to be declared explicitly (in Basic, the % signifies an integer value, but is normally not used).

In Basic, to assign a variable from within an input loop, it would be typical to have a line such as

INPUT "Enter your number ";number

The variable number hasn't been declared but is very easily entered. While not being noticeably slower, the number of steps the computer needs to break this down to is around five (print to screen, declare space in memory for the number, input, assign input result to number and write number to the memory space for the number). As number hasn't be declared, enough space is reserved by automatically assuming the undeclared variable is a double. The piece of Basic code also has to be converted into machine code.

In C, when you declare the variable, the compiler reserves the correct amount of space for that variable type and all inputs are directly placed into that memory location; the variable can be simply thought of as a pointer to that location in memory (more on pointers soon). It is also much faster as the final application is in machine code.

While the code for this routine would be longer in source code, it is actually processed by the computer far faster and takes up far less space in memory.

INT, DOUBLE and FLOAT are also known as signed - that is, they can be either negative or positive. Integers can have a value in the range of ±2147483648 with floats being ±1.7 x 1038 - a sizeable range indeed (as you would expect from a 32-bit processor!).

With this firmly in mind, how would you actually implement a C version of a standard input statement? I mean, if everything is placed straight into a reserved memory, won't there have to be a form of the old POKE command, and won't I need to add 1 for each new memory position? Eeek! this is sounding hard!

Well, as with most things, the answer is very simple. Whilst in C there isn't a version of the POKE or ! command, machines are quite clever. When you assign a variable to a type (e.g. int), the program reserves four bytes of memory (that's enough to store 2147483647 in binary). This memory address is remembered by the program. When you enter a number, this is converted into binary and stored there. The computer automatically increments the memory pointer to the next location for the number.

This still does pose the problem of getting the numbers into memory. In C, this is performed by the addition of the & in front of the variable name. For instance,

INPUT a% in Basic becomes scanf("%d",&a); in C.

The program then assigns the memory location of the variable to a (well, sort of - I'll explain this at a later point). This can then be recalled by doing something like printf("%d",a);

Nice and simple - told you so!

FLOAT and DOUBLEs are also assigned in a similar way, with the exception that the
input type (the letter following the %) becomes f instead of d. Printing back is the
same (f instead of d).

As I said at the start of this session, the three main variable types are all known as signed, that is, can be negative or positive. While in most cases this doesn't make a tap of difference, there are occasions when programs need a variable to be unsigned (that is, only positive). The only real difference is that the way they are stored, they can normally only have a value from 0 to 65535.

This leaves the one remaining point, the different letters following the % symbol - what do they mean?

%What it inputs or outputs
cone character
ddecimal (base 10) value
escientific notation e.g. 3 × 108
ffloating point number - this must include the decimal place
ggeneral format to represent values in either e or f format - whichever is the shorter
llong value
ooctal (base 8) values
ppointer values
sstring
uunsigned integer
xhexadecimal (base 16) values

The l and u field type can be placed in front of the other field types to make the types become (say) long floating values (this would be %lf).

There are times when a floating value would need to be worked on by an integer to give a whole number (any integer division will always end up as a whole number). It is possible in C to modify the variable type by placing the new variable type in brackets in front of the variable needing to be changed. E.g.

int whole=5,new1;
float fp_number=1.2,new2;
new1=whole/fp_number;
new2=(float) whole/fp_number;
printf("new1 = %d\nnew2 = %f",new1,
new2);

would produce:

new1 = 4
new2 = 4.166666666

the Acorn C compiler does produce a warning when compiling this due to the use of the (float) modifier.

Add, subtract and divide

As with any other computer language, numbers aren't much use unless you can do something with them. In C, there are five basic operators which can be used for simple maths:

addition (+)
subtraction (-)
multiplication (*)
division (/) and
modulus (%)

The format is very straightforward. While in Basic you may have had code which looks like

a=a+1 or a+=1

in C, you can still do the same, but (for addition and subtraction), it is simpler just to write a++ or a--. In a similar way to the a+=1 example, multiplication and division can be performed by using a*=3 and a/=5.

Modulus?

The modulus of a number is more easily thought of as the remainder after a division. For example, 5/3 = 1 (as int values), yet 5%3 = 2. Putting it another way, 5/3 = 1 remainder 2.

There is one important thing to remember here. Though you may be happy with a++ meaning a=a+1, printing a++ will give you the value of a, then a will be incremented. If, on the other hand, you printed ++a, a would be first incremented then the value output.

For more complex mathematical functions, you'll have to keep watching!

Next time, I'll cover program flow (the use of if, else, switch and case as well as the ? choice).

For now, a bit of a puzzle which you should be able to do if you've read the first part last month...

Light travels at 2.98 × 108 ms-1. The earth is roughly 150 million kilometers from the sun (this is an average due to the earth's orbital being elliptical). How long would it take for us to notice if the sun was no longer shining? (hint; the relationship is speed = distance / time). You should give the output as both decimal and scientific notation, and also in minutes (remember, the speed is in metres per second and the distance is in kilometres so these need to be converted first) to two decimal places.

While this may sound hard, it's not that hard - it can be done in 12 lines of code (includes the { and } brackets). It doesn't matter that the output will be in 100ths of a minute for now.


Source: Archive Magazine - 13.2
Publication: Archive Magazine
Contributor: Paul Johnson