You are on page 1of 14

1 of 14

1st Year Computing for Engineering

Session 3: C Programming Basics


Michaelmas Term 1999 Lab Organizer: Prof D W Murray

Summary of what you have to do this session


Building C Programs Spend about 45 minutes working through Exercise 3A Exercise 3B Main Exercise 8C Spend about 15 minutes Spend about 5 minutes Spend about 45 minutes on this

Document conventions
this typeface indicates something the machine should present,
this typeface indicates

a Unix command to be typed by you.

this typeface indicates C code.


If on your browser, curly brackets {} look similar to curvy brackets (), you will want to change the fixed with font on the Netscape browser. Select Edit, then Preferences, then, when the new panel appears, select Fonts, and choose Lucida Typewriter (B&H) at size 10 or 12 for the Fixed Width font.

1. Getting Started
Login, and start Openwindows. From your home directory, type into the cmdtool window % /packages/demo/yr1/script3 [return] which generates directories session3 and exercise3, and places several files in them. Change directory into "session3". % cd session3 [return]

02/20/2008 11:00 AM

2 of 14

2. Building a C program in Steps A-F


You are going to build a C program in elementary steps to highlight aspects of the structure of the language. At each step, you will compile and execute the program to see what happens. Step A: A program that does nothing. 1. Edit the program source code. Type the following into the text editor, then save as squares.c in the directory session3. Don't shut down the editor, you'll need it again.

void main() { }
2. Compile and link At the moment, the program squares.c is just a text file, and cannot be executed by the machine. To turn the program into an executable file, we first ``compile" the program, then ``link" it to the other routines we require. Use the following incantation in the cmdtool window: % gcc squares.c -o squares The gcc program (The Gnu C Compiler) will compile squares.c, link it automatically to the standard C library, and the -o squares puts the executable output into a file called squares. 3. Execute the program To execute the program, type in the cmdtool window: % squares Step A: Observations. 1. There were no complaints from Unix, so the program executed. However, as expected, it did not do anything. 2. Every program has at least a ``main'' routine, which is where the program starts executing. Each routine has a ``type'', defining the type of the return value of the function. Here though the routine does not return a value, so it of ``void'' type. Most routines have a list of arguments given inside the (), but here we have none. All routines surround their bodies with curly brackets { }. Here there are no statements though! 3. As we follow the steps below, you will see the general structure of a C program emerging: the program comprises a set of routines, each of the form

type routinename (type argument1, type argument2, ...)

02/20/2008 11:00 AM

3 of 14

{ declaration1; declaration2; ... statement1; statement2; ... return( value ); }


4. Also you will see the development cycle emerging, of edit, compile, then execute. Step B: Adding a statement Let us now add one statement to the main routine. 1. Edit. Go back to the editor, and add in two extra lines

#include <stdio.h> void main() { printf("Squares from 1 to 10\n"); }


and then save again as squares.c. 2. Compile and Execute % gcc squares.c -o squares % squares Step B: Observations 1. Each statement inside the body of the code surrounded by the outer curly { } must end with a semicolon. The statement actually calls another routine printf() , which writes output to the standard output. The "\n" puts a newline at the end of the text. 2. The #include
<stdio.h> is

a compiler directive which makes sure that C knows how printf() is defined.

(stdio.h is a file defining a number of routines for input and output.) Step C: Adding comments It is good practice to add comments to help explain your code.

02/20/2008 11:00 AM

4 of 14

1. Edit. Go back to the editor and add

/* /* /* /*

Name : Version: Author : Date :

squares.c 1.0 E Jarvis Thribbs 12 Oct 98

*/ */ */ */

#include <stdio.h> void main() { /* This program will eventually print out squares from 1 to 10 printf("Squares from 1 to 10\n"); }
Save again. 2. Compile and Execute. Save some fingerwork by using the exclamation mark shorthand % !gcc which will repeat the last command starting gcc. (This works for any command by the way: !p repeats the last command line beginning with p, !pa the last beginning with pa, and so on.) Step C: Observations 1. Nothing changes in the executable program. All text between /* and */ is ignored by the compiler, and has no effect on the code. 2. Comments can appear anywhere in the source code. One restriction is that you cannot nest comments as in /* A comment /* Nested = Bad */ */ Step D: Declarations of variables and constants To save space below, some of the comments in the printed code may disappear. Obviously there is no need for you to delete them. 1. Edit. Go back to the editor and add/alter:

*/

#include <stdio.h> void main() { /* This program will eventually

02/20/2008 11:00 AM

5 of 14

print out squares from 1 to 10 int i,isq; const int lolimit=1, hilimit=10;

*/

printf("Squares from %d to %d\n",lolimit,hilimit); }


Remember to save. 2. Recompile using !gcc 3. Execute. Step D: Observations 1. The first set of statements in a routine are the declarations mentioned earlier. They always come at the top of the routine, and the declared identifiers are valid only within the routine itself. Each variable and constant must be declared --- there are no default values. 2. Here we use integer variables i and isq, and integer constants called lolimit and hilimit. Constants cannot change their value during a routine. 3. The output is achieved using printf(). On execution, the format code %d is replaced with the corresponding integer value. Step E: Finishing off with a loop 1. Edit. Go back to the editor and add

#include <stdio.h> void main() { int i,isq; const int lolimit=1, hilimit=10; printf("Squares from %d to %d\n",lolimit,hilimit); i=lolimit; while (i <= hilimit) { isq = i*i; /* i multiplied by i */ printf("%d squared is %d\n",i,isq); i = i+1; } printf("Finished looping because i=%d \n",i); }

02/20/2008 11:00 AM

6 of 14

Remember to save. 2. Recompile (!gcc) 3. Execute. Step E: Observations 1. The variable i is initialized to lolimit. 2. The while
(condition) {statements ... } tests

that the condition is TRUE before entering the body of the

loop to execute the statements. When the condition becomes false, execution jumps to the first statement after the loop's body. 3. Notice the statement i=i+1; What would happen if this had been omitted?

3. Laying out your code


There are few restrictions on layout in C. Each compiler directive has to be on a separate line, and care must be taken splitting strings, but apart from that anything goes. As the mess below illustrates ugly programs are hard to understand and debug, and are thus bad engineering practice.

#include <stdio.h> void main(){ int i,isq; const int lolimit=1, hilimit =10;printf("Squares from %d to %d\n",lolimit, hilimit) ;i=lolimit; while (i<=hilimit){isq=i*i;printf( "%d squared is %d\n",i,isq);i = i+1;}printf( "Finished looping because i=%d \n",i);}

EXERCISE 3A
1. In a cmdtool window, copy the file squares.c to the file sqcubes.c 2. Edit the program sqcubes.c so that it calculates and prints BOTH the squares AND cubes of even integers between 2 and 16 inclusive. Don't just hack the existing program. Think a little about the design, so that your program, even though it is small, is elegant and efficient. Perhaps the output should appear as a table:
i i^2 i^3 --------------2 4 8 etc

Some observations

02/20/2008 11:00 AM

7 of 14

1. If there were language errors in your program, the compiler prints error messages to help you find the mistakes. Use the editor to correct them, save the editted file, and recompile. 2. It is important to realize that if the compiler fails, no new executable file is written. So if you had a working version of cubes, then altered sqcubes.c but introduced an error, and tried to compile, the old version of sqcubes would not be overwritten. So, sqcubes might appear to run, but it would be the old not new version.

2 ctd/ Building C Programs


Step F: Calling subroutines Your solution to the exercise probably involved writing something like

int icubed; ... icubed = isq*i;


Now suppose you had been asked to evaluate many more powers within the program. It would be tedious and error-prone to write the expressions out explicitly. Instead you might wish to write a separate routine. 1. Edit your program by adding a routine. Save the program as powers.c

#include <stdio.h> int power(int number, int pow) { /* This routine returns an integer value * equal to number raised to the pow. * Pow can be zero or positive. */ int pwr,i; pwr=1; i=pow; while(i>0) { pwr = pwr * number; i = i-1; } return(pwr); }

02/20/2008 11:00 AM

8 of 14

void main() { int i,i2,i4,i6,i8; const int lolimit=1, hilimit=10; printf("No Pow2 Pow4 Pow6 Pow8\n"); i=lolimit; while (i <= hilimit) { i2 = power(i,2); i4 = power(i,4); i6 = power(i,6); i8 = power(i,8); printf("%2d %4d %6d %7d %9d\n",i, i2, i4, i6, i8); i = i+1; } }
2. Compile powers.c 3. Execute powers Step F: Observations 1. The routine power() has type int because it returns an integer value using the return(pwr). The routine has two arguments, number and pow. Note how the routine is called in the main program. 2. We slightly altered the printf() format string: %4d supplies an output field with a fixed with of 4 places.

4. Variables Types in C: int, float and so on


There are several basic types

int, which can represent integers from - (231) to +231-1. float for floating point numbers. The largest float values are about &plumn; 3.40282 1038 and
the smallest non-zero float is 1.40129 10-45.

double provide a floating point nummber with higher precision and range. char is used for single characters.
These types can be modified in several ways, but for now these will suffice. Mathematical functions tend to use

double precision floating point numbers rather than floats. ... void main() {
02/20/2008 11:00 AM

9 of 14

int count; float volume; double fred; char label; ... count = -356; volume = 2345.456; fred = 2.123477834599725; label = 'a'; /* Notice these are closing-apostrophes' ' and not `speech marks' */ }

5. Operators
5.1 Standard operators

+ Add

(eg c=a+b;)

- Subtract (eg c=a-b;) * Multiply (eg c=a*b;) / Divide (eg c=a/b;)


A common error is to forget the multiply sign

c=2(a+b); /* WRONG */ c=2*(a+b); /* RIGHT */


5.2 Operator precedence There are strict rules for operator precendence. Expressions in brackets are worked on first. Multiplies and divides are done before adds and subtracts. A succession of multiplies and divides or adds and subtracts is worked on left to right. So, for example, suppose a=12 and b=4 and c=2, then

d=a/b+2; /* this is (a/b) + 2, => d = 5 d=a/(b+2); /* and not this! => d = 2 d=a/b*c; /* is (a/b) * c d=a/(b*c); /* and not this d=a/b/c; /* is (a/b)/c

*/ */

=> d = 8 */ => d = 1.5 */ => d = 1.5 */

02/20/2008 11:00 AM

10 of 14

It is always sensible to use brackets to make your meaning clear to you, others, and the compiler. 5.3 Some shorthand operators Avoid

j+=2; add 2 to j. Same as j=j+2; j-=2; take 2 from j. Same as j=j-2; j*=2; j=j*2; j/=2; j=j/2;
EXERCISE 3B
What value would c have at the end of this ugly piece of code?

a b a c c

= 8.0; = a - 2.0 * 3.0; -= 4.0; = ( (a/2.0/b) * 3.0/a*b)/b; *= 2.0;

You've got the message? Don't write code like this!

6. Conditionals
6.1 Numerical Conditionals The while loop you included in your code was controlled by testing a condition. Conditionals are either numerically based or logically based. A list of numerical conditionals is Operator Example Result < <= > >= == != (a < b) True if a less than b

(a <=b) True if a less than or equal to b (a >b) True if a greater than b

(a >=b) True if a greater than or equal to b (a ==b) True if a equal to b (a !=b) True if a not equal to b

6.2 Conditional IF statements

02/20/2008 11:00 AM

11 of 14

Conditionals are also used in the very frequently used if statement, which executes the statements in the block where the respective condition is TRUE. There are three flavours of if: Using plain if

if ( Condition ) { ... statements A ... (Executed if Condition is True) }


Using if ... else

if ( Condition ) { ... statements A ... (Executed if Condition is True) } else { ... statements B ... (Executed if Condition is False) }
Using if ... elseif ... else

if ( Condition1) { ... statements A ... (Executed if Condition1 is True) } else if ( Condition2) { ... statements B ... (Executed if Condition2 is True) } else { ... statements Z ... (Executed if all Conditions are False) }
Here is an example of an ``if ... else if ... else statement

if( i<0 ) { printf("i is negative!\n"); } else if ( i>0) {


02/20/2008 11:00 AM

12 of 14

printf("i is positive!\n"); } else if (j>0) { printf("i is zero and j is positive\n"); } else { printf("i is zero and j is zero or negative\n"); }

EXERCISE 3C
Recall the program powers.c which used a routine to compute the value of integer raised to an integer power. The integer power had to be greater or equal to zero. Your task now is to modify the routine to allow in addition raising to negative integer power. There are many ways of achieving this. It is worth thinking first about some common aspects to any solution. 1. The routine power() will have to check for a negative argument. This requires the use of the if condition. 2. Because an integer raised to a negative number is a floating point number, the result will now have to be a

double rather than an int. This will have repercussions in the main routine too.
3. Usually, the less ``clever'' you make the code, the easier it is to write and debug, and the easier it is to understand at a later date. A partial solution has been supplied to you, and is listed later. 1. % cd ~/exercise8 and then check that file npowers.c exists. 2. Load npowers.c into the text editor. You will see that the main routine is complete, but the subroutine is not. 3. Sort out the four ``FIXMEs'' in the code. Save the program, compile and link. If unsuccessful, reedit until it executes properly. If you feel you are making no progress, consult a demonstrator sooner rather than later. 4. Finally, show your results to a demonstrator

/* LISTING of npowers.c */ #include <stdio.h>


02/20/2008 11:00 AM

13 of 14

double power(int number, int pow) { int i; double result; result=1.0; i=pow; if( FIXME ) { /* This should deal with negative pow */ while(i < 0) { result = FIXME ; i= FIXME ; } } else { while(i > 0) { /* This should deal with positive or 0 pow */ result = result * (double)number; i = FIXME ; } return(result); } void main() { /* we will work out i^(-2,-1,0,1,2) */ int i; const int limit=11; double im2,im1,iz,ip1,ip2; i=1; while(i < limit) { im2 = power(i,-2); im1 = power(i,-1); iz = power(i,0); ip1 = power(i,1); ip2 = power(i,2); printf("%lf %lf %lf %lf %lf\n",im2,im1,iz,ip1,ip2); i = i+1; } }

Logging out

02/20/2008 11:00 AM

14 of 14

As ever exit openwin And then don't forget to logout from the console

Summary
In this session We have seen the following basic programming constructions in C: Assigments, eg result=1.0 Loops, eg for(i=1; Conditionals, eg if
+ a;

i<= 10; i++) { ... } (i==2) { ... } else {...} = power( 3.0, -1.0);

Subroutines, eg result

We have also gone round and round the design, edit, compile, execute cycle. Lab devised by: David Murray Lab Organizer: David Murray Last changed June 15th, 1999

02/20/2008 11:00 AM

You might also like