Introduction to C Programming by Rob Miles, Electronic Engineering
Programs operate on data. A programming language must give you a way of storing the data you are processing, otherwise it is useless. What the data actually means is something that you as programmer decide (see above digression on data).
Basically there are two types of data:
In the first case we can hold the value exactly; you always have an exact number of these items, they are integral.
This means that when we want to store something we have to tell the computer whether it is an integer or a real. In fact it is useful to have several types of data.
Note that C is often called weakly typed. This does not mean that you do not press the keys very hard (ho ho), what it means is that C does not fuss about what you put in each box. If you have a red box (of type integer), and then ask C to put a green value into it (of type real or floating point), C will not complain that what you want to do is meaningless, it will just do it. Other languages, for example PASCAL, get all hot under the collar when you try to do this, they are called strongly typed. Weakly typed languages let you do exactly what you want so, provided you know what you are doing, everything will work out OK.
We will consider just three types for the moment, there are others available but you can get by with these for now:
A type of box which can hold a real (i.e. floating point) number. These are held to limited precision, again the precision and range you get varies from one version of C to another, in the version of C we are using it goes from 3.4E-38 to 3.4E+38.
A type of box which can hold a single character. We have already come across characters when we looked at filenames and the like. A character is what you get when you press a key on a keyboard.
If you are used to other languages you might think that there are some storage types missing, for example there is no way to store strings of characters. In C, unlike BASIC, you have to manage the storage of strings yourself - however there are a large number of built in facilities to make like easier. We will come to these later.
Another missing type is that used to store logical values, i.e. either TRUE or FALSE. C does not provide this facility, but uses the convention throughout that 0 means false and any other value means true. There are operators that can be used to provide logical combinations in C, but they will work on any non-real data type.
Before you can use a particular box you have to tell the compiler about it. C will not just create boxes for you; it has to know the name of the box and what you are going to put into it. You tell C about a box by declaring it.
When the compiler is given a declaration it says something along the lines of:
Here is the name of something which we want to store. I will create a box of the type requested, paint it the correct colour and write the name on it. Later on I will put things in the box and get things out of it. I will put the box on a shelf out of the way for now.
Such a box is often called a variable. All languages support different types of variables, all have types equivalent to the C ones.
Remember that all we have is a box. The box is not empty at the moment, but there is nothing of interest in it; the contents are what we call undefined. If you use the contents of an undefined variable you can look forward to your program doing something different each time you run it!
C paints the name on the box using a stencil. There are only a few stencils available, so the characters that you can use to name a variable are limited. Also, because of the design of the stencils themselves, there are some rules about how the names may be formed, namely:
The length of the name allowed depends on the version of C you are using. You can use amazingly long names in any version of C, the important thing to remember is that only a certain number of characters are looked at, i.e.
very_long_and_impressive_C_variable_called_fred
and
very_long_amd_impressive_C_variable_called_jim
- would probably be regarded as the same in most versions of C.
Upper and lower case letters are different, i.e. Fred and fred are different variables.
Here are a few example declarations, one of which are not valid (see if you can guess which one and why) :
int fred ; float jim ; char 29yesitsme ;
One of the golden rules of programming, along with "always use the keyboard with the keys uppermost" is:
Always give your variables meaningful names.
According to the Mills and Boon romances that I have read, the best relationships are meaningful ones.
Once we have got ourselves a variable we now need to know how to put something into it, and get the value out. C does this by means of an assignment. There are two parts to an assignment, the thing you want to assign and the place you want to put it, for example consider the following:
void main ( void )
{
int first, second, third ;
first = 1 ;
second = 2 ;
second = second + first ;
}The first part of the program should be pretty familiar by now. Within the main function we have declared three variables, first, second and third. These are each of integer type.
The last three statements are the ones which actually do the work. These are assignment statements. An assignment gives a value to a specified variable, which must be of a sensible type (note that you must be sensible about this because the compiler, as we already know, does not know or care what you are doing). The value which is assigned is an expression. The equals in the middle is there mainly do confuse us, it does not mean equals in the numeric sense, I like to think of it as a gozzinta (see above). Gozzintas take the result on the right hand side of the assignment and drop it into the box on the left, which means that:
2 = second + 1 ;
is a piece of programming naughtiness which would cause all manner of nasty errors to appear.
An expression is something which returns a result. We can then use the result as we like in our program. Expressions can be as simple as a single value and as complex as a large calculation. They are made up of two things, operators and operands.
Operands are things the operators work on; They are usually constant values or the names of variables. In the program above first, second, third and 2 are all operands.
Operators are the things which do the work; They specify the operation to be performed on the operands. Most operators work on two operands, one each side. In the program above + is the only operator.
Here are a few example expressions:
2 + 3 * 4 -1 + 3 (2 + 3) * 4
These expressions are worked out (evaluated) by C moving from left to right, just as you would yourself. Again, just as in traditional maths all the multiplication and division is performed first in an expression, followed by the addition and subtraction.
C does this by giving each operator a priority. When C works out an expression it looks along it for all the operators with the highest priority and does them first. It then looks for the next ones down and so on until the final result is obtained. Note that this means that the first expression above will therefore return 14 and not 20.
If you want to force the order in which things are worked out you can put brackets around the things you want done first, as in the final example. You can put brackets inside brackets if you want, provided you make sure that you have as many open ones as close ones. Being a simple soul I tend to make things very clear by putting brackets around everything.
It is probably not worth getting too worked up about this expression evaluation as posh people call it, generally speaking things tend to be worked out how you would expect them.
For completeness here is a list of all operators, what they do and their precedence (priority). I am listing the operators with the highest priority first.
- unary minus, the minus that C finds in negative numbers, e.g. -1. Unary means applying to only one item.
* multiplication, note the use of the * rather than the more mathematically correct but confusing x.
/ division, because of the difficulty of drawing one number above another on a screen we use this character instead
+ addition, no problems here.
- subtraction. Note that we use exactly the same character as for unary minus.
This is not a complete list of all the operators available, but it will do for now. Because these operators work on numbers they are often called the numeric operators.
When C performs an operator, it makes a guess as to the type of the result that is to be produced. Essentially, if the two operands are integer, it says that the result should be integer, if the two are floating point, it says that the result should be floating point. This can lead to problems, consider the following :
1/2 1/2.0
You might think that these would give the same result. Not so. The compiler thinks that the first expression, which involves only integers, should give an integer result. It therefore would calculate this to be the integer value 0 (the fractional part is always truncated). The second expression, because it involves a floating point value would however be evaluated to give a floating point result, the correct answer of 0.5
We can force C to regard a value as being of a certain type by the use of casting. A cast takes the form of an additional instruction to the compiler to force it regard a value in a particular way. You cast a value by putting the type you want to see there in brackets before it. For example :
#include <stdio.h>
void main ( void )
{
int i = 3, j = 2 ; float fraction ;
fraction = (float) i / (float) j ;
printf ( "fraction : %f\n", fraction ) ;
}The (float) part of the above tells the compiler to regard the values in the integer variables as floating point ones, so that we get 1.5 printed out rather than 1.
When you cast, which you need to do occasionally, remember that casting does not affect the actual value, just how C regards the number. As we saw above, each type of variable has a particular range of possible values, and the range of floating point values is much greater than that for integers. This means that if you do things like :
int i ; i = (int) 12345678.999 ;
We have used the printf (print-formatted) standard input/output procedure from stdio.h to do the output, what we need is an equivalent procedure to do the input. C has got one of these, it is called scanf (scan-formatted). However, before we can turn it loose we have a little problem to solve; Where does scanf put the value that it fetches. "That is easy" you say, simply give it the name of the variable and scanf will know where to go. Wrong! scanf is very stupid. It cannot understand the names of variables. Why should it? All it was created for is to take something from one place (the keyboard) and put it somewhere else (a location). scanf does not want to know what the variable is called, all it needs to know is where the variable lives.
When we talk about C variables we mean a box which the compiler creates for us, with a name nicely painted on it. The compiler makes a box like this and then puts it on a shelf somewhere safe. The compiler then knows that when we say "i" we really mean the box with i written on it. scanf is simply a function that we call to fetch a value and stick it somewhere else, another kind of removal man. It needs to be told which box to put the result in. C calls referring to a thing by its location rather than its name as pointing.
Nice children have been brought up knowing that it is rude to point. In C things are rather different, you have to point to be able to do anything useful. (I am sure nanny would understand).
You tell the C compiler to generate a pointer to a particular variable by putting an ampersand "&" in front of the variable name, i.e.
x means the value of the variable x
&x means a pointer to the box where x is kept, i.e. the address of x.
scanf looks very like printf, in that it is a format string followed by a list of items, but in this case the items pointers to variables, rather than values, for example:
scanf ( "%d %d %d", &i, &j, &k) ;
The more adventurous amongst you may be wondering what happens if we leave off the ampersands by mistake. This can lead to one of two things:
A very big chunk of C involves address and pointer juggling. I make no apologies for this, it is one of the things that makes C the wonderful, fun loving, language that it is. However it can also be a little hard on the grey matter. Just keep in mind that only the C compiler can handle sticking values into variables. Everything else does not know the name, and can only talk in terms of following pointers to boxes.