Ten useful programs
Ten useful programs
There are a few very basic operations that students need to be able to perform on the computer, in whatever language they choose to work in. There are no tangible advantages of any one language over any other at this level of programming. Some of the most important simple programs that form building blocks of bigger, more sophisticated programs, would include the following;
1. Read in data from a named file.
2. Read in data from the console.
3. Pass data to a function by value.
4. Pass data to a function by address for processing.
5. Process data stored as an array, and print out formatted results.
6. Compute the roots of a function.
7. Solve Newton's equations of motion.
8. Generate random numbers and use them to simulate events.
9. Generate data for a graph, and build a graphic object.
10. Animate a simple system.
Reading files
The following program uses the fscanf function to read data from a file, which in C is specified by a pointer to the memory location in which the file is stored. It uses the feof function to determine when the end of the file has been encountered. It expects the file to be a single column of data (floating point numbers) of unspecified length.
/* this is a comment, within comment delimitors */
/* the following lines include library function declarations */
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
/* we expect no more than MAX data in the file */
#define MAX 1000
/* declare our variables */
int n, i;
float data[MAX];
FILE *fptr;
main (int argc, char *argv[])
{
if ((fptr = fopen (argv[1], "r")) == NULL)
{
printf ("No such file \n");
exit (0);
}
n = 0;
do
{
fscanf (fptr, "%f", &data[n]);
n = n + 1;
}
while (!feof (fptr));
n=n-1; /* we overcounted by incrementing n before testing for eof */
for (i = 0; i < n; i++)
printf ("%f\n", data[i]);
fclose (fptr);
}
Notice that we read the data into the memory address of the array element data[n], not its value, but we print out the value put into that address on the very next line. Notice that we open the file read-only, and close it when we are done. Our program accepts argc command line options, stored as strings in an array argv[ ], the zeroth being the name of the program, and the first being the name of the file that the program will read. Our program reads data from the file until it reaches the end, storing how many data it read in variable n. It uses two types of loops; a do-while and a for loop.
To compile this, save it as reader.c, and compile with gcc -o reader reader.c. Run it with ./reader datafile.
Now we make this do something useful. We add a little code to make the program find the average and variance of the data read in. We need to create two new variables, and add another loop.
/* this is a comment, within comment delimitors */
/* the following lines include library function declarations */
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
/* we expect no more than MAX data in the file */
#define MAX 1000
/* declare our variables */
int n,i;
float data[MAX], ave,std;
FILE *fptr;
main(int argc, char *argv[]){
if((fptr=fopen(argv[1],"r"))==NULL){
printf("No such file \n");
exit(0);
}
n=0;
do{
fscanf(fptr,"%f", &data[n]);
n=n+1;
}while(!feof(fptr));
n=n-1;
ave=0.0;
std=0.0;
for(i=0;i<n;i++){
ave=ave+data[i];
}
ave=ave/(float)n;
for(i=0;i<n;i++){
std=std+(data[i]-ave)*(data[i]-ave);
}
std=sqrt(std/(float)(n-1));
printf("The average is %f, and standard deviation is %f\n", ave, std);
fclose(fptr);
}
This program recasts the integer data n as a float, and uses the sqrt function prototyped in math.h. That means we need to link the code to the math library libm, by compiling with gcc -o reader reader.c -lm.
Reading the console
Ths is a little simpler, and uses the scanf function to read from the console into a pointer to the memory where we will store the data entered.
/* the following lines include library function declarations */
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
/* we expect no more than MAX data in the file */
#define MAX 1000
/* declare our variables */
int n,i;
float x[MAX], y[MAX];
main(){
printf("How many data points?\n");
scanf("%d",&n);
for(i=0;i<n;i++){
printf("enter x[%d] y[%d]\n",i,i);
scanf("%f%f",&x[i],&y[i]);
printf("You entered %f\t%f\n",x[i],y[i]);
}
}
Ou program queries the user for the number of data points (an integer), and then for pairs of space-separated floats representing coordinates of some object.
Functions
New features are; the prototyping and declaration of the function, calling of the function, and the actual code block for the function. This function computes an average, and so is passed an array by value, since it uses the values stored in the array without changing them, and an integer used for looping and computing the average.
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
/* we expect no more than MAX data in the file */
#define MAX 1000
/* declare our variables */
int n,i;
float x[MAX], av;
/* function declaration */
float average(float position[], int num);
main(){
printf("How many data points?\n");
scanf("%d",&n);
for(i=0;i<n;i++){
printf("enter x[%d] \n",i);
scanf("%f",&x[i]);
}
av=average(x,n);
printf("The average is %f\n", av);
} /* end of main() program */
float average(float position[], int num){
/* code block for the function */
int j;
float ave;
ave=0.0;
for(j=0;j<num;j++){
ave=ave+position[j];
}
ave=ave/(float)num;
return(ave);
}
Consider now the more impoeratant problem of processing an array of numbers; actually changing the contents of the array. To do this with a function, we pass a pointer to the array of data. This tells the computer which memory locations to overwrite with new values. Pointer arithmetic is subtle and bug-prone, but can be very powerful. Keep in mind that it is very picky, and care must be taken that your code actually does what you want it to do.
This program uses the address operator & and the dereferencing operator * which gives the value of the number stored in the address pointed to by the pointer.
/* the following lines include library function declarations */
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
/* we expect no more than MAX data in the file */
#define MAX 1000
/* declare our variables */
int n,i;
float x[MAX], av;
float *xptr;
/* function declaration */
void square(float *position_ptr, int num);
main(){
printf("How many data points?\n");
scanf("%d",&n);
for(i=0;i<n;i++){
printf("enter x[%d] \n",i);
scanf("%f",&x[i]);
}
xptr=&x[0]; /* point the pointer */
/* call the function */
square(xptr,n);
for(i=0;i<n;i++){
printf("%f\n", *(xptr+i)); /* print out what we did */
}
}
void square(float *position_ptr, int num){
int j;
for(j=0;j<num;j++){
*(position_ptr+j)=(*(position_ptr+j) ) *( *(position_ptr+j) );
}
}
This program calls a void function, one that performs a job, but does not return a value.
In the variation below we will load the data into a pointer to the actual data arrays, so that we could pass the arrays to a function for processing or changing the stored values. We need to declare the pointers; variables that represent the start of memory locations, point them to the memory locations that they represent, and later print out the numerical contents of what is stored in the memory locations.
/* the following lines include library function declarations */
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
/* we expect no more than MAX data in the file */
#define MAX 1000
/* declare our variables */
int n,i;
float x[MAX], y[MAX], *xptr, *yptr;
main(){
printf("How many data points?\n");
scanf("%d",&n);
for(i=0;i<n;i++){
printf("enter x[%d] y[%d]\n",i,i);
scanf("%f%f",&x[i],&y[i]);
printf("You entered %f\t%f\n",x[i],y[i]);
}
xptr=&x[0];
yptr=&y[0];
for(i=0;i<n;i++){
printf("%f\t%f\n", *(xptr+i), *(yptr+i));
}
}
Formatted output
Data generated by your program can be written to the console with printf(), or to a file with fprintf() , both of which accept an formatting string as an argument along with the values of the stuff to be printed. This is in contrast to scanf() and fscanf() which are passed pointers to the memory address where you want to store what will be read in. After all, how can you know the value of what you will read in until after you have read it?
Below is a simple example illustrating the printing of data into a named file.
/* the following lines include library function declarations */
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
/* we expect no more than MAX data in the file */
#define MAX 1000
/* declare our variables */
int n,i;
float y[MAX],dx,x;
FILE *fptr;
main(){
dx=0.01;
fptr=fopen("datafile","w"); /* open file for writing */
for (n=0;n<314;n++){
x=(float)n*dx;
y[n]= sin(x);
fprintf(fptr,"%f\t%f\n", x, y[n]);
}
printf("done\n");
fclose(fptr);
}
The program will create a file datafile, open it for writing, create data for a plot of sin(x) versus x by printing x, then a TAB character (8 spaces), then sin(x), followed by a newline or carriage return character, into the file. When it is finished, it will print ``done'' on the console.
Root extraction
The problem of computing the solutions to
is fundamental in applied mathematics. There are several easy to apply numerical methods for doing this task. The simplest is a brute force algorithm called the method of bisection, which uses no sophisticated mathematical concepts whatsoever.
To apply the bisection method, pick two points, x1 and x2. If there is a root between x1 and x2, then
otherwise
The first step in the algorithm is to test which case prevails.
If there is a root between x1 and x2, bisect the segment and let z = [(x1+x2)/2]. Now test if there is a root between x1 and z. If there is , reset x2 = z and iterate. If there was not, then there is a root between z and x2 and so we reset x1 = z and iterate. We continue to do this until we have narrowed down the interval in which there is a root to whatever accuracy we desire. The simple program below accomplishes this.
#include<stdio.h>
#include<math.h>
float f(float x);
float x0,x1,root;
int n;
float f(float x); /* code for the function */
main()
{
printf("Input x0 and x1, two points around a root\n");
scanf("%f%f",&x0,&x1);
for(n=0;n<20;n++){
if (f(x0)*f((x0+x1)/2.0)<0.0)
x1=(x0+x1)/2.0;
else x0=(x0+x1)/2.0;
}
/* one final bisection */
root=(x0+x1)/2.0;
printf("The root is %f\n",root);
}
float f(float x){
/* put your function code here, for example; */
return(x*x-3.0*x+1.0);
}
In order to turn this into a truly useful programming tool, we make use of a powerful application of pointers.
A function can be passed to another function by the following method. When one function declaration appears within another function, the name of that one being declared becomes a pointer to that function. This is even true of functions declared within the main function. For example consider the program stub below
#include<stdio.h>
float a,b,c;
float func(float (*pf)(float x), float x, float y);
float f( float z);
main()
{
a=2.0;
b=3.0;
c=func(f,a,b);
printf("%f\n",c);
}
float func(float(*pf)(float x), float x, float y)
{
float c;
c=(*pf)(x);
c=y*c;
return(c);
}
float f(float z)
{
return(1.0/(z*z));
}
This program passes an unknown or user specified function to another function as a pointer.
Bisection is geometrical, and so fails in higher dimension, or with functions of a complex variable. It is however quite simple to program, and is precise. Newton's method works on complex functions, is non-geometrical, but can be numerically unstable.
Solving a differential equation; Euler integration
Any differential equation of the form
can be very crudely integrated by expressing the derivative in terms of finite differences. We imagine the range of the function
as being divided into N discrete lattice points
|
xn = 0+ |
xmax-0 N
|
n = x0 +ndx, dx = |
xmax-0 N
|
|
|
then using the mean-value theorem of calculus
|
f¢( |
x1+x2 2
|
) » |
f(x2)-f(x1) x2-x1
|
|
|
we write the differential equation at the midpoint of the nth interval as
|
|
y(xn)-y(xn-1) xn-xn-1
|
= |
y(xn)-y(xn-1) dx
|
» f( |
xn+xn-1 2
|
) |
|
which is a recursion
|
y(xn) = y(xn-1)+dx f( |
xn+xn-1 2
|
) |
|
which we now proceed to build up from the initial value. Since xn = n dx, we adopt the notation y(xn) = y(n dx) = yn, then
|
yn = yn-1+dx f( (n- |
1 2
|
)dx) |
|
and we find that from our initial condition
and so on.
This is crude but quite fast and produces acceptable results as long as dx is small (N is large).
For a second order equation such as
we can use the same procedure, but we simplify the computations by using a ``Hamiltonian formalism'' that reduces the single second order equation into two first order equations. Introduce a ``momentum'' coordinate
then the differential equation above can be split into the pair
|
y¢(x) = p(x), p¢(x) = f(x,y) |
|
and we can again construct a recursive solution
|
yn = yn-1+ dx pn-1, pn = pn-1+dx f(xn-1, yn-1) |
|
Note that we did not use a midpoint prescription here since it is too hard to implement if f depends on y.
Below is a program that numerically integrates by the Euler algorithm the following differential equation;
|
y¢¢ = -y, y(0) = 0.5, y¢(0) = 1.0 |
|
and outputs a two-column table of x and y(x) values for any value of xmax that is specified on the command line.
#include<stdio.h> /* we need this in order to use argc, char *argv[] */
#include<stdlib.h>
#define N 100
double y[N + 1],p[N + 1];
double x,delta_x,x_max;
int n,m;
FILE *fptr; /* a data file to write to */
int main (int argc, char *argv[])
{
double (*x_ptr)[N + 1], (*p_ptr)[N + 1];
/* Do some error checking to avoid segmentation faults */
/* I hate segmentation faults. */
if(argc < 3 || argc > 3){
printf("usage: HO x_max filename\n");
exit(1);}
x_max=(double)atof(argv[1]); /* convert first command line arg to x_max */
fptr=fopen(argv[2],"w+"); /* second command line arguement is filename to*/
/* write to */
for(n=0; n<=N;n++){
y[n]=0.0;
p[n]=0.0;}
/* set initial conditions */
y[0]=0.5;
p[0]=1.0;
/* set the interval size */
delta_x= x_max/(double)N;
/* perform the recursion */
for(n=1;n<=N;n++){
x=(double)n*delta_x; /* the time */
p[n]=p[n-1]-delta_x*y[n-1]; /* the momentum */
y[n]=y[n-1]+delta_x*p[n-1]; /* the position */
/* write it to a file */
fprintf(fptr,"%f\t%f\n", x,y[n]); /* output time, position */
}
fclose(fptr); /* close the file and delete its pointer */
return ;
}
Generating random numbers
Random numbers are generated with the use of rand() and srand(), functions declared in stdlib.h. On Win32 platforms, these may be different. Srand will seed the generated sequence with a positive integer, and rand will generate the sequence. The program stub below illustrates all of the required syntax
#include<stdlib.h>
#define SEED 17531
main()
{
long num;
srand(SEED); /* initialise the sequence */
num=rand();
}
The random numbers generated will be between zero and a constant called RAND_MAX. This constant differs from compiler to compiler. Read through stdlib.h for this string and establish the value of RAND_MAX on your system. On mine it is 231-1.
A very handy seed for the random number generator on a UNIX system is the process ID (PID) of the program calling rand()
#include<sys/types.h>
#include<unistd.h>
pid_t getpid(void)
The function getpid() returns the process identifiers for the calling process, so for example
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
main()
{
long num;
srand((unsigned int)getpid()); /* initialise the sequence */
num=rand();
}
The result is really pretty damn random.
Monte-Carlo integration methods use random numbers to compute integrals. The method is not fast or accurate; N-point Gaussian quadrature could be thosands of times faster and more accurate, however in some cases no other integration scheme but Monte Carlo may work. To evaluate
first find a number h such that
Consider the rectangle of width b-a and height h, in the x-y plane, with the graph of y = f(x) plotted within it.
Generate a random number x1 between a and b. Generate a second random number x2 between 0 and h. Plot the point (x1,x2). Do this many times, the ratio of the area under the curve to the entire rectangle are should be equal to the ratio of the number of points that lie below our curve to the total number of points N. In other words
where Nunder is the number of points under the curve and N is the total number of shots.
#include<stdio.h>
#include<stdlib.h>
#define SEED 13175
long N=100000;
int n,N_u=0;
float a,b,h,x_1,x_2,area;
main()
{
srand(SEED);
for(n=1;n<=N;n++){
x_1=a+(b-a)*rand();
x_2=h*rand();
if(x_2<=f(x_1))
N_u=N_u+1;
}
area=h*(b-a)*N_u/N;
printf("The area is %f\n",area);
return(0);
}
float f(float x)
{
return(f(x)); /* your definition here */
}
Graphics
To create graphics with a C program (assuming that you are working on a Linux system in X-windows), you need a graphics library. I use plotutils-2.2, freely available from ftp://prep.ai.mit.edu/pub/gnu. I have created a simple header file for a PlotWindow graphical object similar to that used in TRUBASIC for plotting functions. A simple program given below calls the routine and plots a graph.
/* a program to illustrate how PlotWindow.h is used to create a graphics */
/* panel for plotting and animation */
/* compile with invocation */
/* gcc plotter3.c -L/usr/X11R6/lib -lplot -lXaw -lXmu -lXt -lSM
-lICE -lXext -lX11 -lm */
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<plot.h>
#include"PlotWindow.h"
#define Maxlines 1000
float X[Maxlines], Y[Maxlines];
int n, Whatsize;
int pl_handle;
FILE *fptr;
main ()
{
float *Xptr, *Yptr; /* pinters to x, y values to plot */
Whatsize=1000; /* size of data arrays passed to PlotWindow routine */
for (n = 0; n < Whatsize; n++)
{
X[n] = 90.0*exp(-(float)n*0.01)*sin((float)n*0.0314);
Y[n] = 90.0*exp(-(float)n*0.01)*cos((float)n*0.0314);
}
Xptr = &X[0];
Yptr = &Y[0];
/* from this set up a plotter window */
/* a static example; no animation or double buffering */
pl_parampl ("BITMAPSIZE", "400x400");
pl_handle = pl_newpl ("X", stdin, stdout, stderr);
pl_selectpl (pl_handle);
if (pl_openpl () < 0) /* open Plotter */
{
fprintf (stderr, "Couldn't open Plotter\n");
return 1;
}
/* call the plotter, plot the data */
PlotWindow(Xptr,Yptr,Whatsize, 100.0, -100.0,100.0,-100.0);
/* delete things, deallocate memory */
pl_closepl ();
pl_selectpl (0);
pl_deletepl (pl_handle);
}
This will create a logarithmic spiral.
The code for the header file PlotWindow.h can be downloaded from http://rustam.uwp.edu/499, or you can type the code below into a file. You only need to do this once, just include the header in your programs. It is designed to make your C graphics programs as close in form and structure to the TRUBASIC programs of physics 303 as possible.
/* a plotter-window callable qroutine */
void PlotWindow(float *Xp, float *Yp, int whatsize, float Xmax, float Xmin, \
float Ymax, float Ymin)
{
/* plotter window for graphing (Xp[n], Yp[n]), takes */
/* size of arrays, maximum x, y, minimum x, y as args */
int n;
float marginsize, tick;
float Dx, Dy, axisx, axisy, scale;
char sbuff[8], *divlabel;
/* determine margin sizes */
marginsize = 0.2 * fabs (Xmax - Xmin);
scale = fabs (Ymax - Ymin) / fabs (Xmax - Xmin);
pl_fspace (Xmin - marginsize, Ymin / scale - marginsize, Xmax + marginsize,\
Ymax / scale + marginsize);
pl_flinewidth (0.001 * fabs (Xmin - Xmax));
pl_erase ();
/* set up some graphics parameters */
if (Xmin * Xmax < 0.0)
axisx = 0.0;
else
axisx = Xmin;
if (Ymin * Ymax < 0.0)
axisy = 0.0;
else
axisy = Ymin / scale;
Dx = (Xmax - Xmin) / 10.0;
Dy = (Ymax - Ymin) / (10.0 * scale);
/* draw in axes */
pl_fline (axisx, Ymin / scale, axisx, Ymax / scale);
pl_fline (Xmin, axisy , Xmax, axisy );
/* draw in a bunch of tick marks on the axes */
/*printf ("%f\t%f\t%f\t%f\n", axisx, axisy, Dx, Dy); */
for (n = 0; n <= 10; n++)
{
pl_fline (Xmin + (float) n * Dx, axisy - 0.1 * Dy, Xmin + \
(float) n * Dx, axisy + 0.1 * Dy);
pl_fline (axisx - 0.1 * Dx, Ymin/scale + (float) n * Dy, axisx + \
0.1 * Dx, Ymin/scale + (float) n * Dy);
}
/* now plot the datafile */
for (n = 0; n < whatsize - 1; n++)
{
pl_fline (*(Xp + n), *(Yp + n) / scale, *(Xp + n + 1), \
*(Yp + n + 1) / scale);
}
/* rescale and draw in labels */
pl_ffontsize (0.04 * fabs (Xmax - Xmin));
pl_fontname ("HersheySans");
pl_fmove (Xmax + 0.5 * marginsize, -0.1 * marginsize);
pl_label ("x");
pl_fmove (0.5 * Xmax, -0.5 * marginsize);
divlabel = gcvt (Dx, 5, sbuff);
pl_label (divlabel);
pl_label (" per div.");
pl_fmove (-0.1 * marginsize, Ymax / scale + 0.5 * marginsize);
pl_label ("y");
divlabel = gcvt (Dy * scale, 5, sbuff);
pl_fmove (axisx - 0.5 * marginsize, 0.4 * Ymax / scale);
pl_textangle (90);
pl_label (divlabel);
pl_label (" per div.");
pl_textangle (0);
pl_fmove (0.25 * Xmax, Ymax / scale + 0.5 * marginsize);
divlabel = gcvt (axisx, 5, sbuff);
pl_label ("origin is (");
pl_label (divlabel);
pl_label (" , ");
divlabel = gcvt (axisy * scale, 5, sbuff);
pl_label (divlabel);
pl_label (")");
}
This is pretty easy to hack and reconfigure for whatever purposes you wish.
Animation
Using the same library, you can create complex, double-buffered animations that
run in real time, even for very large numbers of graphics primitives.
A simple GIF89 animation example
The following code can be downloaded from http://rustam.uwp.edu/499, and animates a planet in an Einsteinian orbit around the sun.
/* a program to illustrate how PlotWindow.h is used to create a graphics */
/* panel for plotting and animation */
/* compile with invocation */
/* gcc animation.c -L/usr/X11R6/lib -lplot -lXaw -lXmu -lXt -lSM -lICE
-lXext -lX11 -lm */
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<plot.h>
#include"PlotWindow.h"
#define Maxlines 1000
float X[Maxlines], Y[Maxlines];
int n, Whatsize;
int pl_handle;
FILE *fptr;
main (int argc, char *argv[])
{
float r;
int j;
float *Xptr, *Yptr; /* pointers to the data arrays to pass to plotter */
/* Do some error checking to avoid segmentation faults */
/* I hate segmentation faults. */
Whatsize=1000; /* size of data arrays passed to PlotWindow routine */
/* create some data for Keplerian planetary motion */
for (n = 0; n < Whatsize; n++)
{
r=0.025*(1.0+0.5*cos((float)n*0.0314));
r=1.0/r;
X[n] = r*cos((float)n*0.0314);
Y[n] = r*sin((float)n*0.0314);
}
Xptr = &X[0];
Yptr = &Y[0];
/* from this set up a plotter window */
/* an animation with double buffering */
pl_parampl ("BITMAPSIZE", "400x400");
pl_parampl ("USE_DOUBLE_BUFFERING", "yes");
pl_handle = pl_newpl ("X", stdin, stdout, stderr);
pl_selectpl (pl_handle);
if (pl_openpl () < 0) /* open Plotter */
{
fprintf (stderr, "Couldn't open Plotter\n");
return 1;
}
/* call the plotter, plot the data */
j=0;
do{
pl_filltype(0); /* do NOT fill in closed curves */
PlotWindow(Xptr,Yptr,Whatsize, 100.0, -100.0,100.0,-100.0);
pl_filltype(1); /* fill in closed curves */
pl_fillcolorname("yellow");
pl_fcircle(0.0,0.0,3.0); /* draw the sun */
pl_fillcolorname("blue");
pl_fcircle(X[j],Y[j],2.0); /* draw the earth */
j=j+5;
}while(j<Whatsize-5);
/* delete things, deallocate memory */
pl_closepl ();
pl_selectpl (0);
pl_deletepl (pl_handle);
}
There are few limits to the complexity of the graphics and animations that you can produce this way. I have prepared a full graphics programming manual and course for scientific computing. It is available to anyone who requests it.
Some Frequently Asked Questions
How do I compile a program?
Compilation is converting the actual text for the program code into machine language, which is an executable object. Actual compilation by invocation of the compiler is compiler specific. Suppose your program is called program.c. On my machine I can create an executable called program by typing
gcc -c program program.c
on the console command line. On a DOS machine with the Borland Turbo-C compiler, it might be
C:\TC\bin\tc program.c
and on a Sun SparcStation 10 it would be
cc -c program program.c
After compiling, what do I do?
You run the program. This amounts to typing
./program
on a Linux machine, or if you are on a DOS computer
program.exe
The kernel will then execute your program.
What do the file extensions .c, .cpp, .cc and so forth mean?
These are extensions used to determine what type of file the code represents. Most C programs should end in .c, a C++ program on my machine should end in .cc, and on a Borland Turbo-C machine it should be .cpp. A FORTRAN77 program should end in .f, an x86 assembly program should end in .s. Object files are files compiled to machine language by the compiler, and end in .o. A static library archive such as the math library will end in .a, and a dynamically loaded library will end in .so. Some compiler will choke if your file does not end in the correct extension.
What is a header file?
In C and C++ we often dramatically cut down the size of a program by using external libraries, and preprocessor directives to include a header file that declares all of the functions in the library. A statement such as #include < math.h > in a program tells the C preprocessor to include all of the function prototypes and declarations in the header file math.h, located in a central place such as /usr/include, in the program at compile time. Thats all that the header contains. If you create your own libraries, you will need to write header files for them containing declaration and prototyping lines.
How do I write a program?
The first step is to start up a text editor, such as vi or xemacs on a UNIX machine, or notepad on a WIN32 machine. You could use the DOS edit program as well. Now just type in your code. Save it with the correct file extension as ASCII text. Do not let the editor format it, if you do the compiler will not recognize it as a program text.
I tried to compile a program and got ``/tmp/ccYAJGpb.o(.text+0x1e4d): undefined reference to sqrt'', what the hell does that mean?
The compiler puts all of the objects that it creates in the /tmp directory
temporarily. If the linker fails to link your program with a library that you thought that you used, you get a message like this. This is a sign that you forgot to link your code to the library at compile time. To manually link to the math library in C, use
gcc -c program program.c -lm
If you link to multiple libraries, such as the multiple precision library, and the parallel thread library, you might need something like
gcc -D_REENTRANT -c program program.c -lm -lgmp -lpthread
What is optimization?
Some good modern compilers will rewrite your code on the fly at compile time in a way that maximizes performance. Highly optimized C can be as fast as hand-written assembly code. You can compile with optimization levels 1-6 with the -ON switch, for example optimization level 3;
gcc -O3 -c program program.c -lm
I usually compile -O6 -funroll-loops -fomit-frame-pointer -march=pentiumpro to specify loop unrolling (an old and venerable optimization trick to ``fatten'' a loop) and to specify X686 architecture enhancements.
How can I redirect output into a file to capture it?
Use data redirection; on both UNIX and DOS machines you can dump output into a file called data for example by
./program > data
and on Linux you could even pipe this into a graphics routine to plot it on the fly with
./program | graph -T X
Data redirection is quick and dirty, you can save your output without writing the code to create and write to a file.
What are the differences between C, C++ and Java?
At the procedural programming level, there are almost no syntactical differences. If you learn one of these, you can quickly pick up another, and pretty easily convert simple procedural programs from one language to another. C and C++ are about 40-100 times faster than Java, since they are compiled, and Java is interpreted like BASIC.
Java does not have pointers. This is good because pointers have the potential to introduce subtle bugs into a program. This is bad because pointers are perhaps the single most powerful programming construction. Take your pick.
I have a FORTRAN77 program, how easy is it to convert it to C?
Pretty damn simple; get the f2c converter. This is free from www.netlib.org at Oakridge National Laboratories. Simply type
f2c program.f program.c
it does a great job of rewriting the code in C.
In English please, what is a pointer?
A pointer is a data type. It is the address in the memory of where a certain chunk of data is stored. It is not the value of the data. If we want the pointer to be the address of where a double precision number is stored, we declare double *f_ptr, if we want it to point to an integer, int *i_ptr, and so forth. Pointer arithmetic must be done carefully, or the program using pointers may behave in unexpected ways.
When I ran my program, i got ``segmentation fault'', what does that mean?
It means that you misused either an array or a pointer, and attempted to access a memory location inappropriately. This is a pointer boo-boo. Typically, the most common error leading to such a message is that you tried to read the values pointed to by a pointer, but never initialized the pointer (you forgot to point it to some memory location). For example, to point a pointer f_ptr to the address of the variable x, we would need a line like fptr = &x; in the code before we tried to read the value stored in that location, via printf(``%f\n'', *fptr);. Remember to point your pointers before you try to read what they point to.
Is there a good book on C suitable for scientists?
I think the Schaum's Outline on C programming is the best book on the subject that I have seen yet.
After all of this, I think I want to do Java. What do I need?
You need the JDK; the Java Developement Kit. It is free and can be downloaded from www.blackdown.org, or from www.sunsoft.com. Most Linus distributions on CD contain a copy. You could buy the Microsoft version fairly cheap (under $100.00), but keep in mind that it is not standards compliant, and so some features may not function as expected.
The kit contains the bytecode compilers and interpreters, the virtual machine, and the class files; the Java equivalents of libraries and headers.
You will need a Java-aware browser to run your programs. Netscape is recommended.
Is animation and graphics easy or hard in C?
It is extremely easy and intuitive. You will need a graphics library, such as GNU plotutils-2.2 or higher, free from ftp://prep.ai.mit.edu/pub/gnu. Graphics and animation in C requires about the same amount of code as would be needed in any flavor of BASIC or Java, but is many times faster because C is compiled. My uderstanding is that the same is true in FORTRAN77, but I cannot recommend a graphics library for that language because I no longer use it. I think you would want plplot.
Graphics and animation in C, C++, or FORTRAN77 are also of much higher quality and resolution than in BASIC or Java. This is because the graphics libraries are affine vector based rather than pixel based.
To be fair, graphics programming in Java is possibly the easiest of any of these languages, but is hampered by lack of speed, and the need for a virtual machine to run the program. Java puts very high demands on your computer.
I use plotutils-2.2 to create all of the graphics for course material and research publications. It can also be used to create double buffered animations in real time, or save them as a GIF89 movie.
I got a ``parse error'' when I tried to compile. What is that?
Ninety-nine percent of the time this is because you forgot to close off a bracket }, or you forgot to put a semicolon ; at the end of some line where you needed one.
I want a debugger or IDE (integrated developement environment, gimme gimme gimme.
The Borland Turbo-C comes with a nice IDE and will debug your programs at compile time. There is a Linux version (free) called xwpe-alpha, and the GNU debugger gdb and graphical debugger ddd do a very good job on huge programming projects. These are free as well. Get them from www.appwatch.com.
On Digital UNIX, try LaDebug.
On Linux, if you intend to use gdb or ddd on a fairly brocken program, compile it with debugging symbols
gcc -g -o program program.c
and do not optimize.
File translated from
TEX
by
TTH,
version 2.69.
On 19 Dec 2000, 07:26.