Next:Pointers and Arrays Up :Main

 

 

 PROGRAMMING

Before we start on a course in "Numerical methods and programming" we should look at  some of the basic aspects of programming. We will learn here, how to convert some of our ideas into a working program and what are the parameters to keep in mind when we design an algorithm.

 

There are many "languages" like, for example C, Fortran, PASCAL etc., that  help us to  convert an algorithm in to something that a computer can understand. We will focus here only on C programming

 

By the end of the first part, you should have a working knowledge on how to implement an algorithm. With this mind we will go through very basic features of C and some of the aspects C programming that is not immediately relevant to the implementation of the algorithms that are taught later in this course .

 

So. let us start looking at how do we create a "C program".There are basically three steps involved in converting your ideas into what is to be done to make it a working program.

 

There are three steps involved in converting your  idea of what is to be done to a working program

 

Ų Creating a source code in the form of the text file acceptable to the compiler.

 

Ų Invoking the compiler to process the source code and produce an object file.

 

Ų Linking all the object files and libraries to produce an executable

 

 

We will look at these parts in some more detail here.

 

The source code is where you express the the whole computation you want to do into a series of instructions.

 

The tradition is to use the C source code with an extension .c  For example myfile.c  .  Some compilers insist on this extension. This is an acsii file that you can create using any one of the editors that you are familiar with. We will look at the detailed structure of this code in a little while .

 

We may have different parts of the code in different files. We then compile them separately or together to form object files.  During this operation the compiler checks and convert your source code to a language understandable to the particular processor that is used in the computer. These object files that comes with an extension .o,  for example myfile.o ,  are in binary format.

 

The next step is to link these object files and other libraries and header files etc., to produce an executable. This executable file contains a set of instruction in a language that the processor can understand and is the one which we run on the computer. We will see the use of header files and system libraries  in the examples given below.

 

Before proceed let us summarize the steps that takes us to run a program in the form of a flow chart.

 

 

 

As we said earlier  it is the tradition to  write a C program file  name ending with the extension   .C.

 

Example: Below we give a program that computes the square root of a number and prints it on the scree. Since it is a C program we name it as "myfile.c" , that is with an extension ".c".

 

1    #include <math.h>

2    #include <stdio.h>

3    main()

   {

4      float x,y;

 

5          scanf("%f\n",&x);


6            y=sqrt(x);

7          printf("%f\n",y);

     }

 

 

Before we proceed to the compilation of this program let us take a minute to see what does each of the lines mean?.

 

Lines 1 and 2 are header files. These files contain the math library functions and the input output command functions. We need the math function library to use functions like "sqrt", "log", "power" etc. We need the stdio library to use functions like "scanf" and "printf" which reads and prints the data from the screen. More on this a little later.

 

 The program given above just has a main body. Line 3 is declares the starting on this part. The lines inside the { } following this are the part of the main program.

 

Line 4 is the declaration of the variables. Again we will see more on the variable types later in this course.  In this particular example we declare variables "x,y" as floating points.

 

Line 5 reads the value of the variable from the screen.

 

Line 6 computes the square root of the variable "x" and put the value into variable "y".

Line 7 prints out this value of y.

We first compile this code to produce an object code using the command  cc -c myfile.c   or an equivalent command available at your machine.

 

The object file produced by this, myfile.o is then linked with the system math library using the command, cc -lm myfile.o -o myfile.exe , to produce the executable myfile.exe.

 

(the second term in the command above "-lm" links the object file to the math library. The file name that comes just after -o is the name of the executable).

 

 We can combine compile and link into one step as will see in later part of the course.

   

Example: Let us now  look at a C program that uses the library and another function.

 

#include <math.h>

#include <stdio.h>

main()

{

       float x,y;
        
("%f\n",&x)

            y=sqrt(x);

            printf("%f\n",y);

            printit();
        

}

printf()

{    

        printf("The program is Over");

}

 

This  simple C code  adds an additional component to the one we saw earlier, it calls a function "printit".

 

 As before you can see the "include" files, or what are called header files. Then we will see the main part of the program. This program is basically computing square root of the variable x and it is printing it out on the screen. Then it is calling some function, which prints out a statement.

 

Here we see on of the  main feature of a C program. The main part does some of the calculations and it calls another function.

 

The  function we called, named printit, which simply prints the sentence "the program is over."  can be put it a separate file. Let is call it "print.c". We will see that how it can be compiled and how it can be executed.

 

There are two ways to compile this program.

 

To compile these programs we could type

 cc -c sample.c and cc -c print.c separately.

 

This commands will create sample.o and print.o files. We can create the executable by typing the command.

 

cc sample.o print.o -lm -o a.out

 

In this linking command we have put together the two files and also included the math library file m.a

 

We can now execute the program by typing a.out.

 

You could try variations of these commands and programs to figure out why we need the math.h file and why we need to include -lm in the linker etc.  Also try it for different math functions, for example calculating the logarithm or trigonometric functions etc.

 

Another way to compile and generate an executable from this is to simply type      

 

cc sample.c print.c -lm -o a.out

 

In this the compilation and linking is put together.

 

Let us try another  program to illustrate the use of math library and the compilation and linking procedure.

 

 

Here is the file "sample.c",

 

#include<studio.h>

#include<math.h>

main( )

{

float x,y;

file *FP;

FP = fopen("sample.dat", "w");

while(x++<3.0)

  {

    y = tanh(x);

    fprintf(FP,"%f\n",y);

   }

 Printinit( );

 Fclose(FP);

}

 

and a file "print.c",

 

printinit()

        {

         printf("The program is over" "\n");

 

        }

 

 

As we discussed above, there are two ways for compiling.

 

 

cc      -c      sample.c creates the file called sample.o

 

cc      -c      print.c       creates the file called print.o

 

Now, we put them together and produce an executable. In the process we will link it to the math library using -lm and use -o to direct the executable to  an output "myexe".

 

 

cc sample.o print.o -lm -o myexe

 

this will create a file myexe. Now, if we did not use the part of the command after "-lm", an executable file a.out will be created by the compilation.

 

We could also do it (creating the executable) in one step with the command

 

cc sample.c print.c -lm -o myexe

 

 

To run the program, we use ./myexe. Then it prints on the screen that the "program is over". This is what we have asked the function print.c.

 

Actually what does this program do? It is computing the tangent hyperbolic function for a range of values of x. We achieve this using the "while" function. The output is written in a file called "sample.dat". Note the "fopen" and "fprintf" functions were called for this purpose.  Then it calls the function printinit(). Printinit () just prints out "the program is over" using the function "printf". We will see more examples of the use of these functions as we go along.

 

   

As we saw above in one command we can do two things, compile and link. We can do compilation alone  by invoking

-c  along with cc. If we won't use -c, it will compile and link, that is the default. -lm is here for linking to math library.

 

Let us see what happens if we do nnt use  "-lm" in the command , that is we do not

Link it to the math library and type only

 

cc sample.c print.c -o myexe

 

Does it work?

ą it says that it cannot understand "tanh"

 

Since, tanh is built into the math library, we need that math library to compile this program. To use mathematical functions, we need to link to  math library. For other functions, we might need other libraries. These libraries are stored in different parts of the computer. For example in a Linux platform, these libraries are stored in /users/lib . In general, for different operating systems, the library functions are in different places

 

We were also using header files in the program. Header files are used with "#include" statements.  Try removing header file  #include<studio.h> and then try to compile

 

cc sample.c print.c -lm  -o myexe

 

It says that it cannot understand fopen statement and and *FP declaration etc.,

 

FILE, fopen and all the statements are actually put in into the header file called <studio.h>. For simple "printf" statements, we don't need it.

 

So, we now have a basic idea about how to create a program, compile it and run it. We have seen simple codes with the function and we compile it and run it.

 

 

The anatomy of a program

 

Let us look at the anatomy of a program once again. It can be summarized as below.

 

Compiler preprocessor commands

 

main function name()

{

      variable declaration

       code

}

sub-function-name (arguments)

argument declarations

{

      variable declarations

      code

}

 

  

 We have some compiler preprocessor commands. This includes various #include files. Then comes the main function. Some name can also be given to the main function. Then, we have the variable declarations used in the main code. Then we have sub-functions.

 

 

In the previous example, we had the sub functions as a separate files. But you can also include them it into the main code. In this case, in one file, we can have main program of the main function and sub-functions or separately. It is a good idea to have the sub-functions separately. We also compile them n link them separately. It is always safer to do that. For large programs, it is good to have sub functions separately. Sub function has also the same structure like main function. It might have some arguments which would be passed into it. Then comes argument declaration. Then we have some variable declarations which is only private to sub functions only. We will see the examples of these.

 

 Before going to the example, let us look at each one these in detail.

 

The standard C compiler has four filters. The first one is known as the preprocessor. This part handles the inclusion of files mentioned using the  #include command, definition of constants, macro definition etc.

 

The second filter checks the language statements, generates a symbol table and reports any errors found.

 

The third part generates the code and a fourth filter optimizes the code for better performance

 

The fourth one optimizes the function. It improves the code and modifies the code and so that it runs faster.  This is an optional part of the compiler.

  

Then we look at variable declaration.

  

C language require that all variables are declared before they can be used. Here we declare the variable with its class name and the data type.

 

The variable declarations can have the following form,

 [class] [type] [name][ = initial value].

 The "initial value" is not a necessary quantity.

For example we can declare the real variable "trial" using "auto float trial" or "auto float trail = 0.0". In the latter we also assign the variable a value "0.0".

 

 

We will  now take a closer look at the  'class' statement.

 

In the statement for declaring the variable  "trial" we used "auto float trial" . This means we have assigned the [class] as auto. In fact this is the default class and not necessary to be mentioned in the declaration.

 

n auto variable is local to the function within which it is declared. Every time the function is entered we need to assign a value to it before it is used.

 

Auto variable is a default one. If we say float, it is taken it as auto. That is the default variable declarations. Here are more examples.

 

(Sample1.c)

 

#include<studio.h>

#include<math.h>

main( )

{

float x,y;

while(x++<10.0)

   {

    y = cube(x);

    printf("%f %f %f \n", x,pow(x,2),y);

   }

 

}

Cube(x)

  float x;

{

  float y;

  y = x*x*x;

  return (y);

 }

 

Here, the variable is declared as "float x,y". This is nothing but "auto float x, y".

 

We can add more number of variables to one declaration. When we are using more variables, it is separated by comma. Here we are using two variables.

In the C program, all the lines are separated by semi-colon.

 

The variable declared as an auto variable float x,y is only private to the main function unless one  passes  it to other functions. We can have the same variable declared in another function. For example, float y is declared in the sub function. The y value it takes inside the sub function is different from the other declared outside it.  So for the main function to get the result of the computation done in the sub function the value has to be  "returned".

 

In this program  x value takes starting from 0 in steps of one in floating point. (We will discuss more on what is a floating point and how is the floating point and  an integer actually stored in the computer etc., a little later . Right now, the floating point is the real number.)

 

The sub function actually computes the cubic value of x, returns the value to the main function and prints it. While executing the program, we get the value of square of x (through the "pow" function) as well as cube of x.

.

In the function call y = cube(x), we are passing the variable "x" to the sub funtion. But we are only passing the value of the variable.  In the sub function statement the variable name need not be the same. Even if it is the same it has to be decalred just after the function statement. and If we don't declare the use the float x inside the sub function, we will get the cube of x as zero.  That is, auto variable float x is private to the function.

 

 

External, is another class that is possible. An external variable is global to the program. It should be defined outside the function boundary. A function that uses it should declare it as extern.

 

The first declaration creates the storage and the subsequent declarations does not create storage, but just tells the compiler that the reference to this variable should be resolved by the linker. An example program that uses the real variable  as external is given below.

 

..

 sample3.c  :

 

# include<math.h>

#include<studio.h>

float z; /* External variable is common to the whole program and is decalred outside the main function */

main()

{

 float x;

 extern float z; /* The main and sub functions that uses  the variable should be declare it as extern */

 int i;

 x = 0.0;

 for(i=1;i<=3;i++)

  {

  add( x);

  printf("%f %f \n",x,z);

   }

 

  }

 

This is the main program.  Here we have declared float z outside the main function. That is  z has been declared as an external  floating point. We are using extern float z in the main function also. The sub function here that the program calls is add(x). That function is shown below.

 

add(a)

   float a;

{

   extern float z;

   float y;

   y = sqrt(a);

   z = x+y;

}

 

This function is receiving the variable "x" passed by the main function as variable "a". As we have discussed earlier these variables should be declared next line to the function statement.  It is also using the variable z which is declared as extern float z. If it is not declared in the sub function, the function will not know what z is. If the z value changes in the main function then automatically the value changes in the sub function and vice versa.

 

Now, the compilation is done by ,

 

cc   sample3.c add.c -lm -o a.out.

we are not creating the object file. We just do everything together. Then the program is run.

 

We run it and check what value "z" takes in the program of add.c if we change it in main. We should add printf statements inside the program add.c to do this.

 

add(x)

   float x;

{

  float y;

   extern float z;

   y = sqrt(x);

   z = x+y;

   printf ("%f \n",z);

}

 

Put similar print statements in the "main" to show that the value of "z" is changed even though it is not "passed" through the function call.

  

Then ,we could have a static variables. These are  special definitions.

 

Static variables are initialized only once by the function. The static data is assigned the initial value only on the first time the function is entered and is not re-initialized every time the function is entered.
 

We will see this here with an example

 

(sample2.c)

 

# include<math.h>

#include<studio.h>

float z;

main()

{

  float x;

  extern float z;

  int i;

  x = 0.0;

  for(i=1;i<=3;i++)

  {

  add( x);

  printf("%f %f \n",x,z);

   }

 

}

 

 add(x)

   float x;

  {

   static float y = 0.0;

   extern float z;

   y = y+2;

   z = x+y;

   }

 

We declared the static variable y = 0.0 here. It means that it will initialize the value for y as 0 at first. Then, it won't. If we run the program, we get the results as 2,4,6. First it takes the value 0 and then in every further calls to add it increments by 2.

 

Check what happens when static statement is removed? It would initialize this variable the first time it enters the sub function.  Since "y" is initialized every time the values of "z" will be 2 every time !

 

Static variables are very useful. In many cases, for example, in the case of random number generator, we have some  kind of seed. We pass this see to a random number generator and is returns a random number and updates the see. The next time we call the random number generator it give a new number because the seed is new. This is a case where we don't want the seed to me initialized in every call. We  want to get a   new  random number in every call. So in subsequent calls the seed value should not be initialized, that is it should be treated as "static".

  

We have auto variable ,static variable and external variables. These are the basic three classes that we have gone through. Going back to our definitions in the variable declaration. We have [class] [type] [name  ]=[initial value].

We can put any names here. We have to be careful,  the variables in the c language are case-sensitive. We mayor may not  put the initial value.

 

Second thing is the type.  So far we have used only one or two types, float and int..

 Here is the summary or the chart of the various data types.

 

 We could have an integer or we could have an floating point or we could have an character. Characters are declared as char and integers are declared as int and floating points as float.

 

There are two   different types of integers which we can declare, Long integer and Short integer. In most of the present day compilers the integers declared as int are only Long integers. It means if you have 32 bits, then 2^31 is the largest integer which we can represent. One bit is used for sign. The third one refers the unsigned interger, here can use the extra bit for representing integer without  sign. So,it is slightly longer than the long integers.

 

Then, we have floating point. Here again we could have single precision or double precision. When we say float, it is single precision. If we say double, then it is double precision..

 

Let us look at the program which uses all the data types. Here is the program (sample4.c)

 

#include<studio.h>

#include<math.h>

 

main()

{

double x,y ;

long int i,,j,k;

char letter, chain[ ] = "a quick   fox\n" ;

 

letter = 'B';

Y = 1.01;

  i = 9247562;

i = 2;

 

printf("\n")

printf(" %lf %ld %c %s\n", y, i,letter,chain);

printf("\n");

j = 0;

while(j++<31)

   {

    x = y*y ;

    k = 2*i ;

    printf("%d,%lf,%ld\n",j,x,i);

    y = x ;

    i = k ;

 

   }

 

}

 

Here the variables x and y are declared as a double. (i.e. x and y - floating point (double) auto variables.). Then variables i.j.k are declared as long integers. If we are using large numbers, it is advisable to use long int. Long int can also be represented as long. We don't need to write long int.

 

"letter" is a character and is declared using char. Then we have a character array or the character string , 'a quick fox' which is called chain[ ].

 

These are the examples of character declarations. You can declare a single letter character or a group of characters as letter. We could have an array or string of characters. Here, letter is defined as 'B'. Letter is the character here when it is assigned to a character B. Usually, the character is assigned within single quotes.

 

  Then the integer i, has been assigned a number value two. Then, it is printed out. This program contains many printf statements. This example also demonstrates how do we use printf statements. printf usually prints on the screen. As shown in the previous example, you could also open a file and use a fprinf for printing into a file.

 

If we are going to print out a double precision number, then we use %lf or we could use '%e'. For long integers, we use %ld. In a C program, if we use wrong format in the printf statements, it will print junk but will not give compilation or run time errors The characters are printed using %c and the strings are printed using %s.

Run the  program and  see what it prints.

 

The program has a loop in which j value increases from 0 to 31. The j value is first assigned to zero and increased by  steps of one up to 31. The y value  is assigned to 1.01 to start with. It then computes the square of that number and it is assigned to y. Basically, it computes the (1.01) ^2 and the square of (1.01)^2 etc. so we will see how long it will go before goes beyond the capability of the computer. 

 

What I want to show you is that this floating points and integers, there is a limit to the size of the numbers which the computer can handle because the computer has a finite precision.

 

When then, the program is compiled and run, it prints the number y, integer i , the letter B and the string  a quick fox.

 

Then it enters into the loop and prints the square of "x"  every time. It prints x=1.02.Then it squares that and keeps squaring it. Since "x" has been declared as double precision, we can see that it goes all the way up to j=16. Then the machine  cannot handle it anymore. At j=17 th loop, "x" is printed as infinite. As for as the computer is concerned, it is infinite.

 

Similarly the integer "I" continues to double as "j" increments by one. You can see that 2^30 is the largest integer it could print. It cannot do beyond that. Then, it gives junk.

 

In the previous program, we can make a little change. Instead of  double x,y , we can change it by float x,y. Now, we see what happens. Again we compile it and run it. Now, we see it could not go beyond j=13. But it went up to 16 last time. So, if we want to use larger numbers and we want more precision it is better to use double.

 

Let is now summarize  what we have learned  about the structure of a c program.

 

 

 

A few word about constants. We see above an example of constant assignment  z = 2.0/3.0. Now, z is a floating point. For a mathematician  2/3 = 2.0/3.0; but for a computer  2/3 is zero and 2.0/3.0 is non zero!. In general if we find the ratio of 2 integers, the result is the integer only. If we declare z= 2/3 , then we get the value of zero. So, we have to be careful while making constant assignment and remember to write it as z=2.0/3.0 or z=2/3.0 or z=2.0/3.

Next:Pointers and Arrays Up :Main