Introduction to C Programming

Introduction to C Programming by Rob Miles, Electronic Engineering


Variables

Variables and Data
Types of Variables
Declaration
int variables
float variables
char variables
Missing Types
Variable Declaration
Giving Values to Variables
Expressions
Types of Data in Expressions
Getting Values into the Program

Variables and Data

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


Types of Variables

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.

When you are writing a specification you should worry about the precision to which values are to be held. Too much accuracy may slow the machine down - too little may result in the wrong values being used.
In the second case we can never hold what we are looking at exactly. Even if you measure a piece of string to 100 decimal places it is still not going to give you its exact length - you could always get the value more accurately. These are real. A computer is digital, i.e. it operates entirely on patterns of bits which can be regarded as numbers. Because we know that it works in terms of ons and offs it has problems holding real values. To handle real values the computer actually stores them to a limited accuracy, which we hope is adequate (and usually is).

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.


Declaration

Robs' Arbitrary Standard For Coloured Boxes!
You tell C about something you want to store by declaring it. The declaration also identifies the type of the thing we want to store. Think of this as C creating a box of a particular size, specifically designed to hold items of the given type. We identify what type of data a particular box can hold by making it a certain colour, according to RASFCB integer boxes are coloured red and real (or floating point) boxes are coloured green.

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:

int variables

Note that we can go one further negative than positive. This is because the numbers are stored using "2's complement" noation.
A type of box which can hold only integer values, i.e. no fractional part. The precise range of integers which are supported varies from one version of C to another, in the version we are using it goes from -32768 to +32767

float variables

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.

char variables

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.

Missing Types

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.


Variable Declaration

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.


Giving Values to Variables

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.

Expressions

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

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

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.

Types of Data in Expressions

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

Casting

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 ;
I do not think of this as a failing in C. It gives you great flexibility, at the cost of assuming you know what you are doing....
- the cast is doomed to fail. The value which gets placed in i will be invalid. Nowhere in C does the language check for mistakes like this. It is up to you when you write your program to make sure that you never exceed the range of the data types you are using - the program will not notice but the user certainly will!

Getting Values into the Program

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

For more about pointers, see the chapter about Functions.
When we want scanf to fetch something for us we have to give it a pointer. You can regard a pointer as a tag on the end of a piece of rope. The rope is tied to one of our boxes. All scanf has to do is follow the piece of rope to a box and then put the value into that box.

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.


Rob Miles, R.S.Miles@e-eng.hull.ac.uk, Electronic Engineering
HTML by Bronwen Reid, July 1995