Unlike in MATLAB, to create a C program, the programmer doesn't interact with anything other than a text editor, such as dtpad or nedit. A complete program is prepared and then translated as a whole unit, directly into something that the central processor (in hex, for example) can execute directly.
A C program has a particular structure which must be followed. The smallest C program is one which does exactly nothing. Consider:
main() { } |
This program declares a function called main which does nothing (ie, has nothing further defined within its body delimited by the braces). Other things within C programs which do nothing are comments. Anything between /* and */ are not considered part of the program and are there to aid the programmer as documentation. For example:
/* This is my first C
program written on Monday */ main() { /* This bit doesn't do anything at all */ } |
This is exactly functionally identical to the program at the top. Comments
are ignored by C but should not be ignored by the programmer who instead should
use them to document what their program does, in stages.
Having logged into the UNIX system (hex), open a file called first.c using dtpad or nedit and enter the following program:
/* A slightly more useful program */ #include <stdio.h> main() { printf("This is my first C program\n"); } |
Pay particular attention to the placement of the include line - it must begin in the first column. Note also the way in which the contents of the curly brackets are indented by a few spaces. Check what you have typed and save the file, returning to the UNIX command prompt.
You have just typed into a file what is probably your first C program. Unlike when using MATLAB, nothing more has happened at this stage. We need to translate our C program into a form that the computer can directly understand. This process of translation is called compilation and linking. The source program above is compiled into machine code and then linked to any support libraries of code which may be needed to help your program execute correctly. The command cc and its arguments performs this translation and linking. Type:
cc first.c -o first |
The C compiler takes the contents of the file first.c, generates an object file (called first.o but you won't see this because it's deleted pretty quickly) then links it into an executable program which is output (the option flag -o) into the file first. The program can be executed simply by typing in its name:
fng24a-22$ first This is my first C program fng24a-23$ _ |
Let's consider another program before we discuss the general structure of a C program. This program will compute the circumference of a circle. Again, use the editor to enter the source of the program into a file called circum.c Ignore the line numbers in the pink column. They are for reference purposes in the following texts.
#include <stdio.h> #define PI 3.1415926 main() { float radius, circumference; printf("Enter the radius: "); scanf("%f",&radius); circumference = 2.0 * PI * radius; printf("Circumference is %f\n",circumference); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Compile the program using the cc command as before:
cc circum.c -o circum |
Execute the program. It will ask the user to enter the radius value. Type in, for example, 12.5 and press RETURN as below:
fng24a-24$ circum Enter the radius: 12.5 Circumference is 78.539818 fng24a-25$ _ |
Copy circum.c into another file called area.c and modify it so that calculates the area of the circle whose radius is requested as above. You will need to modify the name of the variable circumference for appearance's sake to area for example, and change the formula for its calculation. Remember that the area of a circle is PI times the square of its radius (express this as radius * radius). Compile and execute the program in the same way.
It's probably at this point, that you will encounter some syntax errors. These are mistakes in the source program. In simple programs such as those you have just typed into files, most of the errors encountered will have something to do with missing or misplaced punctuation. You will notice that every line or statement within the curly brackets of the program above ends in a semicolon. If you omit a semicolon at the end of a statement, the C compiler detects the mistake and produces an error message.
Consider what happens when the semicolon is omitted from the end of line 7 and the user tries to compile the program.
fng24a-26$ cc circum.c -o circum cc: line 9: error 1000: Unexpected symbol: "printf". cc: line 10: error 1588: "radius" undefined. cc: line 12: error 1588: "circumference" undefined. cc: line 12: error 1549: Modifiable lvalue required for assignment operator. fng24a-27$ _ |
The compiler is instantly confused by the absence of a semicolon. It scans on and sees printf on line 9 (ignoring blank line 8) where it expected a semicolon. It considers the whole of line 9 to be in error and ignores it. There was only one error in the program, so why did three other error messages appear for following lines? Errors detected earlier in a program can cause the compiler to stumble over the rest of the program text, making sometimes quite invalid assumptions about it.
From the programs you have been typing in and compiling, one or two things should be noticed about the general form of a C program - words like main and curly brackets. All C programs consist of a number of function definitions of which the function named main is the most important one. Taking the main (and only) function from our circumference finding program, we see that it consists of a number of units (called declarations and statements) surrounded by a set of curly brackets. Each unit ends with a semicolon.
main() { float radius, circumference; printf("Enter the radius: "); scanf("%f",&radius); circumference = 2.0 * PI * radius; printf("Circumference is %f\n",circumference); } |
1 2 3 4 5 6 7 8 9 10 |
Blank lines (4 and 7) have been introduced between sets of units. Although ignored by the C compiler, they serve to enhance readability by separating the statements (5,6,8 and 9) from the declarations (3). printf and scanf are standard C functions by which the values of variables can by input (from the keyboard or other files - scanf) or output along with explanatory text (to the display or files - printf).
In words, this program makes available (declares) two variables called radius and circumference. printf then causes the string Enter the radius: to be displayed on the screen. When scanf is encountered, the program pauses, waiting for the user to type in a numerical value which is then loaded into the variable radius. The variable circumference is the assigned the value of the expression 2.0 times the constant whose name is PI times the current value of the variable radius. The new value of circumference is then displayed on the screen, preceded by the text Circumference is, (%f is replaced by the value during output) and the cursor is moved to the beginning of the next line (\n).
As MATLAB users, you will be unfamiliar with the concept of a declaration. In the C programming language, a declaration introduces the name of a constant, variable or function name and attaches a type to it. Line 3 shows how two variables - radius and circumference - are declared as floating point variables so that they may be used in the statements that follow. It will always be the case that:
Variables must be declared BEFORE they are used!
Furthermore:
All declarations in a function must PRECEDE the first executable statement!
For example, it would be wrong to split up the declaration of radius and circumference (line 3) into two separate declarations, to place the declaration of circumference just before its first use on line 8. You would be attempting to place a declaration after a number of executable statements (lines 5 and 6).
Here are some more examples of variable declarations in C and their meanings:
int i; int a,b; char answer; float value,x,y; double t,variance; |
1 2 3 4 5 6 7 8 |
At this point, you should have three files in your
directory:
first.c
circum.c
area.c
Print copies of these and add them to your log books, clearly labelled.
In the above examples, you have already met two types of statements: assignment statements and function-calls.
From using MATLAB, you should already be familiar with the standard arithmetic operators: + - * /. C also has several more, a few of which actually modify the values with which they are calculating, ie. they have side-effects. The most useful of these operators is the assignment operator =.
Assuming the following program fragment:
int i, j, k; float a, b, c; i = 5; j = 6; k = j = 3; a = b = 5.0 * (c = 2.0); k = j % i; |
1 2 3 4 5 6 7 8 9 10 11 |
The declarations of lines 1 and 2 introduce integer variables i j and k, and floating point variables a b and c. Lines 4 and 5 assign the values 5 and 6 to the variables i and j as expected but these statements may also be considered expressions whose overall values have been thrown away (this is essentially what the semicolon means). This is why the statement on line 7 works. k and j are both set to the value 3 in the following steps: j is assigned the value 3 as expected. The result of j = 3 is itself 3 and this is assigned to k. You can see part of the implied bracketing in line 9 where: c is assigned the value 2.0 which is also therefore the result of the bracketed expression which is multiplied by 5.0. This result is assigned to b which is then assigned to a.
Line 11 introduces the modulus operator which returns the remainder after division. Be careful with division. If both sides of / are integer expressions, the result is an integer division. Remember the following:
It is common in programming to find assignment statements performing increment and decrement operations on variables (adding/subtracting 1 from them) or acting as accumulators.
i = i + 1; j = j - 1; a = a * 1.5; b = b + 0.5; |
i += 1; j -= 1; a *= 1.5; b += 0.5; |
The statements on the right are the shorthand ways of expressing those on the left in C. The variable whose value is to be modified need only be specified once. A further shortening is possible in the first two cases, where addition and subtraction of 1 is required.
i = 5; i++; j = 6; j--; k = i++; j = ++i; |
++ and -- can either prefix or follow a variable which is incremented and decremented. In the above example, i is assigned the value 5 and then incremented. j is given the value 6 which is then decremented. k is assigned the value of i BEFORE i is incremented, whereas j is given the value of i AFTER it has been incremented. -- can be treated in the same way.
printf and scanf are examples of standard functions that perform input and output operations. The f refers to formatted operations. There are many different kinds of input and output that a C program can perform, some of which interact with the underlying computer and operating system. We shall concern ourselves only with inputting variable values from the keyboard and outputting information to the display.
printf outputs the contents of its first argument (a string) onto the display.
printf("This is my first program\n"); |
When executed, the contents of the double-quotes (the string) are displayed on the screen. \n is a special control character which causes the cursor to take a new line, ie. move to the beginning of the next line. So:
printf("Joe Bloggs\nAberdeen\nScotland\n"); |
will cause the output:
Joe
Bloggs Aberdeen Scotland |
to be displayed when it is executed (as part of a complete program). Armed with this knowledge, write a program in the file address.c to output your own name, home city and country on the display. Compile and execute it as usual.
cc address.c -o address |
\n isn't the only special character. \t stands for tab and causes the cursor to move to the next 8th character position along the line. The % character, when followed by d or f, cause printf to substitute the values of expressions in the list following the string format. For example, consider the following program fragment:
float x; x = 5.0; printf("%f squared is %f \n",x,x*x); |
printf will substitute the values of x and x*x for each %f in the string, resulting in:
5.0 squared is 25.0 |
being displayed. %f is used to output floating point values or variables. %d is used for integers.
scanf is similar to printf, except that it waits for the keyboard to supply a number of characters making up numbers according to the format string and then dumps their values into a list of variables following the format string. For example, the following C fragment:
int i; float a; scanf("%d %f",&i,&a); |
This causes the C program to pause until the user types in an integer value and a floating point value, followed by the return key. These values are assigned to the variables i and a respectively. For now, accept the inclusion of the & character prior to a variable name. This will be much later. It is enough to know that it is required before variables in calls to scanf but never used in printf.
Write a program in the file quad.c to evaluate a quadratic expression ax2 + bx + c where a, b, c and x are floating point variables whose values are input using scanf. Express x2 as x * x in your C expression. Since a C program will not automatically instruct the user what is expected of him or her, you will need to precede your scanf statements with a printf or two, asking the user to type some values. The program written earlier in circum.c will demonstrate the way.
Copy the file quad.c into cubic.c and modify cubic.c so that it will calculate a cubic expression ax3 + bx2 + cx + d. In constructing the C expression equivalent to the cubic, avoid unnecessary, repeated multiplication of x by factoring it out. This is called nested multiplication. The first stage of this can be seen as follows:
d + x ( c + bx + ax2 )
You can factor out another x from the last two terms within the brackets in a similar way.
So far, we have learned to construct simple C programs that accept input from the keyboard, perform simple calculations and output their results. We have not really asked questions about the data being input or computed or used the calculations to guide or modify how the program reacts, ie. making parts of the program so that they execute only if certain conditions are met. We need to be able to ask questions about the values of our data first. Part of this is done with relational expressions and the idea of truth.
In C, a relationship between two values (say, two integers) is either true or false. C represents false with the value 0 (zero) and true with any other (non-zero) value, usually 1 (one). There are extra operators called relational operators (in addition to the arithmetic operators encountered earlier) defined as follows:
== | Equality. a == b (a * 3) == (b - 4) |
!= | Inequality (not equal to). t != 5 |
> >= |
Greater than. Greater than or equal to. t > 6 a * b >= c |
< <= |
Less than. Less than or equal to. a < c * d b < 4.0 |
Do not confuse == and =. The latter is the assignment operator which sets its lefthand side to be the value of the expression on the righthandside. == doesn't change anything. It merely returns true (1) if either side has the same numerical value and false (0) otherwise.
Now that we can determine relationships between values and expressions, we can make statements conditional, ie. executed only in certain conditions.
There are two forms of the if statement:
if (expression) statement1; |
and:
if (expression) statement1; else statement2; |
In the first example, statement-1 is executed only if the expression returns a non-zero (true) result. The lower example has an else clause: statement-2 is only executed if the expression returns a zero (false) value. Note that there is no semicolon after the closing bracket!! Consider the following examples, assuming suitable declarations for any variables used:
t = 5; if (t > 2) printf("The value of t is greater than 2\n"); i = 17; if (i > t + 5) i = t; else printf("Warning! Bad data!\n"); |
The reason for the warning may be made clear as follows. Take the first assignment and conditional statement above: the printf statement is only executed if t>2. If a semicolon is placed directly after the closing bracket
if (t > 2); printf("The value of t is greater than 2\n"); |
the printf statement becomes a separate statement which is always executed. The conditional statement is the empty statement between the closing bracket and the semicolon. The indentation emphasizes the structure of the statement, but it doesn't determine how the C program acts.
The if statement as described above takes a single conditional statement in its principal and else parts. What if the programmer wishes to make several statements conditional? A block may be used. You have already met a block in the definition of the main function of your program. It is a sequence of statements surrounded by braces. So the above conditionals may be expressed as:
if (expression) { statement-1; statement-2; ... statement-n; } else { statement-a; .... statement-x; } |
Again, the else part may be omitted. Note that a semicolon is never placed after the closing brace of a block. Let's consider the circumference-finding program earlier, with a conditional statement added to ensure that the radius supplied by the user is positive.
#include <stdio.h> #define PI 3.1415926 main() { float radius, circumference; printf("Enter the radius: "); scanf("%f",&radius); if (radius > 0.0) { circumference = 2.0 * PI * radius; printf("Circumference is %f\n",circumference); } else printf("The radius specified is <= 0\n"); } |
The calculation and result display are only executed if the value typed by the user is greater than zero, ensuring that the resulting circumference is also positive. Modify your area.c program so that the calculation become conditional in the same way - the radius must be positive otherwise a suitable error message is displayed instead.
Functions like sin, cos, and sqrt (square root) are not defined as a standard part of the C programming language. Instead, they must be imported from a library of predefined functions in the same way that scanf and printf are (except these are part of the standard library of C functions that are always included).
The definitions for the maths functions come from including a header file which you have already seen in previous examples and assumed as part of a standard C program. Let's consider an example using square roots. Enter the following (using dtpad or nedit as usual) into a file called roots.c.
The roots of the quadratic equation ax2 + bx +c = 0 are
found using the following formula:
r1,r2 = (-b +- sqrt(b2 -
4ac) / 2a which is coded as follows:
#include <stdio.h> #include <math.h> main() { double a,b,c,det,root1,root2; printf("Enter the coefficients of the quadratic a,b and c: "); scanf("%lf %lf %lf",&a,&b,&c); det = b * b - 4.0 * a * c; det = sqrt(det); root1 = ( -b + det ) / ( 2.0 * a ); root2 = ( -b - det ) / ( 2.0 * a ); printf("Roots are %lf and %lf\n",root1,root2); } |
Compiling the program as usual won't work. You will need to add an extra option to the cc command to tell it to include the maths library. The extra bit required is in red. Type:
cc roots.c -o roots -lm |
and ensure that you have typed it in correctly.
The first thing to note is that we are working with variables of type double because all of the maths functions declared by including the file math.h are defined in terms of the double type for improved accuracy. scanf and printf also require a slight modification because of this. The %f usually seen has to deal with a longer (bigger) data type, hence the l in front of f (standing for long float, which is another way of specifying double).
The calculation of (-b +- sqrt(b2 -4ac)/2a is split up into two sections of which the first is the calculation of the determinant. This is so that:
Try running the program roots with test data for a, b and c such that the determinant (det) will be less than zero. What happens?
Modify your program in roots.c, including a conditional statement so that the square root, calculations and output are only performed if the determinant (det) is positive. Otherwise have the program issue a suitable error message, stating that the roots of the quadratic equation are imaginary. A hint: the statements in red are the conditional ones.
There is another potential fault with the above program and it concerns the righthand side of the division when root1 and root2 are calculated. What happens if a is zero? Run the program with zero as a value of a to discover. Modify your program in roots.c with another conditional to ensure that a is non-zero. For extra credit, rather than simply displaying an error message, have the program calculate the single root (value of x) of the resulting linear equation: bx + c = 0. In words, your resultant program should look similar to:
main() { prompt and accept the values a,b and c; if (a is non-zero) { calculate the determinant det; if (determinant is greater than or equal to zero) { calculate roots and display; } else display message about imaginary roots; } else { calculate single root and display; } } |
Remember to keep the #include definitions at the beginning and the variable declarations as required.
You should have a number of files
now:
first.c
circum.c
area.c
address.c
quad.c
cubic.c
roots.c
Please ensure that you have a copy of these programs in your log books.
Next week, we shall look at loops, arrays/matrices (including strings of characters) and some function definitions.