****************************************************
* C Programming notes
* Mario Levesque
* E-Mail: Levteck@hotmail.com
*
****************************************************


References:
*******************************************
The essentials of C Programming Language, E.C. Ackermann ISBN: 0-87891-696-2

ANSI Stds:
American  National  Standard  for  Information   Systems - Programming Language C, X3.159-1989.

Ellis,  M.  A.,  and  Stroustrup,  B.   The  Annotated   C++ Reference Manual ANSI X3J16 Base Document, 1990.

See "IEEE Standard for Binary  Floating-Point   Arithmetic", IEEE  standard P754-1985  for  more information on floating point and its implementation.


Get DJGPP, it's a very good C and C++ Compiler.  Go to 
http://www.delorie.com/cgi-bin/zip-picker.cgi, 
or go to the main page
http://www.delorie.com/ 
and from there find a link to the ZIP Picker.  It tells you all the ZIP files you need to download for your purposes, depending on platform etc Homer J bubble_soft@yahoo.com



*******************************************
Compiling C programs
*******************************************

Ansi C keyword to be portable:  use -A switch when compiling or Borland
Option/Project ... compiler Source -> ANSI


If you are running in a Unix environment, you will need to compile your program by entering the following command at the % prompt: 
cc progname.c -o progname

However, the basic compilation command is: 
    cc program.c 
where program.c is the name of the file. 

If there are obvious errors in your program (such as mistypings, misspelling one of the key words or omitting a semi-colon), the compiler will detect and report them. There may, of course, still be logical errors that the compiler cannot detect. You may be telling the computer to do the wrong operations.  When the compiler has successfully digested your program, the compiled version, or executable, is left in a file called a.out or if the compiler option -o is used : the file listed after the -o. It is more convenient to use a -o and filename in the compilation as in 

    cc -o program program.c 

which puts the compiled program into the file program (or any file you name following the "-o" argument) instead of putting it in the file a.out . 

Some Useful Compiler Options 

See the online man pages (man cc) for further information and additional options. 

-c 
     Suppress the linking process and produce a .o file for each source file listed. Several can be subsequently linked by the  cc command, for example: 
         cc file1.o file2.o ...... -o executable 

-llibrary 
     Link with object libraries. This option must follow the source file arguments. The object libraries are archived and can be standard, third party or user created  Probably the most commonly used library is the math library ( math.h). You must link in this library explicitly if you wish to use the math functions (note do not forget to #include <math.h> header file), for example: 
         cc calc.c -o calc -lm 

Some libraries require extra options before the compiler can support their use. For example, to compile a program including functions from the math.h library the command might be 
cc mathprog.c -o mathprog -lm
The final -lm is an instruction to link the maths library with the program. The manual page for each function will usually inform you if any special compiler flags are required.

-Ldirectory 
     Add directory to the list of directories containing object-library routines. The linker always looks for standard and other system libraries in /lib and /usr/lib. If you want to link in libraries that you have created or installed yourself (unless you have certain privileges and get the libraries installed in /usr/lib) you will have to specify where you files are stored,  for example: 
         cc prog.c -L/home/myname/mylibs mylib.a 

-Ipathname 
     Add pathname to the list of directories in which to search for #include files with relative filenames (not beginning with slash   /).  By default, the preprocessor first searches for #include files in the directory containing source file, then in directories  named with -I options (if any), and finally, in /usr/include. So to include header files stored in
     /home/myname/myheaders you would do: 

         cc prog.c -I/home/myname/myheaders 

     Note: System library header files are stored in a special place (/usr/include) and are not affected by the -I option.
     System header files and user header files are included in a slightly different manner (see Chapters 13 and 34) 

-g 
     invoke debugging option. This instructs the compiler to produce additional symbol table information that is used by a variety of debugging utilities. 
-D 
     define symbols either as identifiers (-Didentifer) or as values (-Dsymbol=value) in a similar fashion as the #define
     preprocessor command.

Debugger:
The UNIX utility lint can assist in checking for a multitude of programming errors. Check out the online manual pages (man lint) for complete details of lint. It is well worth the effort as it can help save many hours debugging your C code. 

To run lint simply enter the command: 

    lint myprog.c

Lint is particularly good at checking type checking of variable and function assignments, efficiency, unused variables and function identifiers, unreachable code and possibly memory leaks. There are many useful options to help control lint (see man lint). 


*******************************************
Preprocessor Directives
*******************************************
Header files
In a modular approach you keep variable definitions, function prototypes etc. with each module. It is best to centralise the definitions in one file and share this file amongst the modules. Such a file is usually called a header file. Convention states that these files have a .h suffix.
Ex: #include <stdio.h>
You can define your own header files and include them in your programs via:
#include ``my_head.h''
NOTE: Header files usually ONLY contain definitions of data types, function prototypes and C preprocessor commands.

	Lines beginning with # are preprocessor directives.
	When the file is enclosed in < > then the implementation path is searched for the file.
	When the file is enclosed in " " then the local directory is searched first for the file.
	
	The # define directive allows for the association of meaningful identifiers.  If an identifier has been defined then it may not be re-defined differently within the same source program unless it is erased by the #undef directive.
	Ex:	#define MAX=100
	Ex: 	#define IF if
	Ex:	#undef MAX

Conditional Compilation:
	Used to make C programs portable and easy to transfer from one machine to another.  One part of the program can be skipped during compilation.
	#if   #elif  #else  #endif

	#ifdef and   #ifndef  perform the same as #if  but are not part of the ANSI standard.
	#ifndef	if not defined
	Ex:	/* Test not to include identifiers twice in source code */
	#ifndef TEST
	#define TEST
...
	#endif	/*if FAIL has not already been defined then process all lines until #endif */

The preprocessor more or less provides its own language which can be a very powerful tool to the programmer. All preprocessor directives or commands begin with a #. Use of the preprocessor is advantageous since it makes:
programs easier to develop, easier to read, easier to modify, C code more transportable between different machine architectures.
The preprocessor also lets us customise the language. For example to replace { ... } block statements delimiters by PASCAL like begin ... end we can do:
  #define begin {
  #define end  }
During compilation all occurrences of begin and end get replaced by corresponding { or } and so the subsequent C compilation stage does not know any difference!!!.
#define
Use this to define constants or any macro substitution. Use as follows:
 #define  <macro> <replacement name>
For Example
  #define FALSE  0
  #define TRUE  !FALSE
We can also define small ``functions'' using #define. For example max. of two variables:
#define max(A,B) ( (A) > (B) ? (A):(B))
? is the ternary operator in C.
Note: that this does not define a proper function max.
All it means that wherever we place max(C,D) the text gets replaced by the appropriate definition.
So if in our C code we typed something like:
x = max(q+r,s+t);
after preprocessing, if we were able to look at the code it would appear like this:
x = ( (q+r) > (r+s) ? (q+r) : (s+t));

Other examples of #define could be:
#define Deg_to_Rad(X) (X*M_PI/180.0)
/* converts degrees to radians, M_PI is the value of pi and is defined in math.h library */

#define LEFT_SHIFT_8 <<8
NOTE: The last macro LEFT_SHIFT_8 is only valid so long as replacement context is valid i.e.
x = y LEFT_SHIFT_8.

#undef
This commands undefined a macro. A macro must be undefined before being redefined to a different value.

#include
This directive includes a file into code.  It has two possible forms:
 #include <file>
 or
 #include ``file''
<file> tells the compiler to look where system include files are held. Usually UNIX systems store files in \usr\include\directory.
``file'' looks for a file in the current directory (where program was run from)
Included files usually contain C prototypes and declarations from header files and not (algorithmic) C code.


#if -- Conditional inclusion
#if evaluates a constant integer expression. You always need a #endif to delimit end of statement.
We can have else etc. as well by using #else and #elif -- else if.
Another common use of #if is with:
#ifdef
        -- if defined and
#ifndef
        -- if not defined
These are useful for checking if macros are set -- perhaps from different program modules and header files.
For example, to set integer size for a portable C program between TurboC (on MSDOS) and Unix (or other) Operating systems. Recall that TurboC uses 16 bits/integer and UNIX 32 bits/integer.  Assume that if TurboC is running a macro TURBOC will be defined. So we just need to check for this:
  #ifdef TURBOC
   #define INT_SIZE 16
  #else
   #define INT_SIZE  32
  #endif
As another example if running program on MSDOS machine we want to include file msdos.h otherwise a default.h file. A macro SYSTEM is set (by OS) to the type of system to check for this:
  #if SYSTEM == MSDOS
   #include <msdos.h>
  #else
   #include ``default.h''
  #endif

*******************************************
other example:
 #if ! defined BLABLA
   #define BLABLA
   ...
 #endif
*******************************************

Preprocessor Compiler Control
You can use the cc compiler to control what values are set or defined from the command line. This gives some flexibility in setting customised values and has some other useful functions. The -D compiler option is used. For
example:
cc -DLINELENGTH=80 prog.c -o prog
has the same effect as:
#define LINELENGTH 80
Note that any #define or #undef within the program (prog.c above) override command line settings.
You can also set a symbol without a value, for example:
cc -DDEBUG prog.c -o prog
Here the value is assumed to be 1.
The setting of such flags is useful, especially for debugging. You can put commands like:
#ifdef DEBUG
     print("Debugging: Program Version 1\");
#else
     print("Program Version 1 (Production)\");
#endif
Also since preprocessor command can be written anywhere in a C program you can filter out variables etc for printing etc. when debugging:
x = y *3;

#ifdef DEBUG
     print("Debugging: Variables (x,y) = \",x,y);
#endif
The -E command line is worth mentioning just for academic reasons. It is not that practical a command. The -E command will force the compiler to stop after the preprocessing stage and output the current state of your program.  Apart from being debugging aid for preprocessor commands and also as a useful initial learning tool (try this option out with some of the examples above) it is not that commonly used.


Other Preprocessor Commands
There are few other preprocessor directives available:
#error
        text of error message -- generates an appropriate compiler error message. e.g
        #ifdef OS_MSDOS
           #include <msdos.h>
        #elifdef OS_UNIX
           #include ``default.h''
        #else
           #error Wrong OS!!
        #endif
# line
        number "string" -- informs the preprocessor that the number is the next number of line of input. "string" is optional and names the next line of input. This is most often used with programs that translate other languages to C. For example, error messages produced by the C compiler can reference the file name and line numbers of the original source files instead of the intermediate C (translated) source files.


*******************************************
Some library functions in the ANSI Standard
*******************************************
<stdio.h>	Contains prototypes, types, and macros that account for almost 30% of the library. Including:
	fclose(),fopen(),remove(),rename(),fgetc(),fputc(), *fgets(), getc(),putc(), ungetc(), getchar(), putchar(),puts().*gets(), fread(),fwrite(), fseek(),rewind(), clearerr(), feof(),ferror(), perror(), fscanf(),scanf(),fprintf(),printf()
	Ex: #include <stdio.h>

<stdlib.h>	Contains functions for a variety of tasks.  Number conversion, storrage allocation, etc.
		Samples: atoi(), *calloc(), system(), rand(), 

<time.h>	Functions and type for manipulating date and time. Ex: 
	clock(void) returns the number of seconds of processor time used by the program since beginning of execution.  
	time(time_t *tp) returns the calendar time into *tp if tp in not NULL

<math.h>	Contains a variety of over twenty hyperbolic, logarithmic, trigonometric and utility mathematical functions. Example are:
		sinh(),cosh(),ln(),cos(),atan(),sqrt()

<limits.h> <float.h>	These header files contain a collection of constants for the size of integral and floating-point arithmetic.
	
<ctype.h>	Functions of all type int with one parameter of type int.   If test is true return is non-zero otherwise it is zero if the test is false.
	isalnum(int c), isalpha(int c), iscntrl(int c), isdigit(int c), isgraph(int c), islower(int c),  isprint(int c), ispunct(int c), isspace(int c), isupper(int c), isxdigit(int c), int tolower(int c), int toupper(int c)

<string.h>	Str* functions manipulate strings, mem* functions manipulate character arrays. Samples:  *strcpy(), *strncpy(), strcmp(), *strstr(), *memcpy(), *memset(), 

<assert.h>	Used for diagnostic tests in programs
<stdarg.h>	Contains a collection of macros and functions for writing functions with a variable number of arguments in a portable manner.
<setjmp.h>	For non-local jumps
<signals.h>	Provides means for handling exceptional conditions that may occur during execution. Ex abnormal termination, zero divide or overflow, invalid memory access, interrupts, etc.
<local.h>	International information.  Ex: Decimal point characters and currency characters are defined in this file.

Header files with header information can also be included at the beginning

	Ex: 	#include "filname.h"    /* place filename.h in the current directory when compiling*/

macros:  uses line-replacement
	Ex:	#define MIN(A,B)	( (A)<(B) ? (A) : (B) )
	Ex:	#define AREA(L,W)	( (L) * (W) ) 
	using macros instead of functions reduce execution time of a program
	Ex:	#define TEST(STMT)   printf(#STMT "executed \n"    /* will put words executed after the variable STMT in the printf */

	Other:
	#line constant	/* changes the internally stored line number */

	#error   /*causes the preprocessor to write a diagnostic message that includes the token sequence*/
	#pragma token-ring /*causes the preprocessor to perform an implementation-dependant action.
	
	_LINE_ 		A decimal constant containing the current source line number.
	_FILE_		A string literal containing the name of the file being compiled.
	_DATE_	A string literal containing the date of compilation, in the form "Mmm dd yyyy"
	_TIME_		A string literal containing the time of compilation in the form 'hh:mm:ss"
	_STDC_	The constant 1.  This will be defined only in implementation that meet the ANSI Standard.

The UNIX manual has an entry for all available functions. Function documentation is stored in section 3 of the manual, and there are many other useful system calls in section 2. If you already know the name of the function you want, you can read the page by typing (to find about sqrt): 

    man 3 sqrt 

If you don't know the name of the function, a full list is included in the introductory page for section 3 of the manual. To read this, type 

    man 3 intro 

There are approximately 700 functions described there.


*******************************************
Comments:
*******************************************
	Ex1:	/* comment */
	Ex2:	x= "this is not a comment /* delimiter because it's included in the quotes"
	Ex3:	/* comments can not be nested /* inside another*/ like this*/
( the above is interpreted as: "/* comments can not be nested /* inside another*/ "  followed by: "like this*/")


*******************************************
Operators and Separators:
*******************************************
+	addition
-	subtraction
* 	multiplication
/	division    Division / is for both integer and float division. So be careful. The answer to: x = 3 / 2 is 1 even if x is declared a float!! RULE: If both arguments of / are integer then do integer division. 
So make sure you do this. The correct (for division) answer to the above is x = 3.0 / 2 or x= 3 / 2.0 or (better) x =3.0 / 2.0.

%	remainder    The % (modulus) operator only works with integers.

+= 	addition assignment.     So we can rewrite    i = i + 3 as i += 3
-=	subtraction assignment
*= 	multiplication assignment.  Note that x *= y + 2 means x = x*(y + 2) and NOT x = x*y + 2.
/=	division assignment
%=	remainder assignment

The "*=" operator means "multiply the left side by the right side and assign this value to the left side." The "+=", "-=" and "/=" operators are also available, and "+=" and "-=" are used particularly often. 
Ex: balance *= (1.0 + (interest/frequency));

++	increment
-- 	decrement 
Example: i++    is equivalent to:   i = i + 1

=	simple assignment
==	equal.   To test for equality is ==

!=	not equal
<=	less than or equal
>=	greater than or equal
<	less than
> 	greater than

!	logical NOT
&&	logical AND
||	logical OR

&	address of
* 	indirection

>>	right shift
<<	left shift
>>=	right shift assignment
<<=	left shift assignment

|	bitwise inclusive  OR
~	bitwise complement
& 	bitwise AND
^ 	bitwise exclusive OR
|=	bitwise inclusive OR assignment
&= 	bitwise AND assignment
^=	bitwise exclusive OR assignment

+	unary plus (plus sign for positive)
- unary minus, arithmetic (minus sign for negative)

,	sequential evaluation
?: 	conditional

The separators are ( ) [ ] { } , ; :

Variables declared inside a block supersede those outside the block. In other words, if there is an "int i" declared at the start of main() and another "int i" declared inside a "for" loop, code within the "for" loop sees the latter variable's value.

From high priority to low priority the order for all C operators is: 
    	   ( )  [  ]  -> .
                 !   - * & sizeof cast ++ -
                       (these are right->left)
                 * / %
                 + -
                 < <= >= >
                 == !=
                 &
                 ^                |
                 &&
                 ||
                 ?:        (right->left)
                 = += -= (right->left)
                 ,   (comma)


*******************************************
Bitwise Operators
*******************************************
The bitwise operators of C a summarised in the following table:
Table: Bitwise operators
&      AND
|      OR
^       XOR
~       One's Compliment
        0 -> 1
        1 -> 0
<<      Left shift
>>      Right Shift

DO NOT confuse & with &&: & is bitwise AND, && logical AND. Similarly for | and ||.  
~ is a unary operator -- it only operates on one argument to the right of the operator. 
The shift operators perform appropriate shift by operator on the right to the operator on the left. The right operator must be positive. The vacated bits are filled with zero (i.e. There is NO wrap around).
For example: x << 2 shifts the bits in x by 2 places to the left. So:
if x = 00000010 (binary) or 2 (decimal) then:
x>>=2  /* => x=00000000 or 0 decimal */
Also: if x = 00000010 (binary) or 2 (decimal)
x<<=2  /* => x=00001000 or 8 decimal */
Therefore a shift left is equivalent to a multiplication by 2.  Similarly a shift right is equal to division by 2
NOTE: Shifting is much faster than actual multiplication (*) or division (/) by 2. So if you want fast multiplications or division by 2 use shifts.
To illustrate many points of bitwise operators let us write a function, Bitcount, that counts bits set to 1 in an 8 bit number (unsigned char)passed as an argument to the function.
int bitcount(unsigned char x)
 { int count;
   for (count=0; x != 0; x>>=1);
     if ( x & 01)
     count++;
     return count;
  }
This function illustrates many C program points:
for loop not used for simple counting operation
x>>=1   /*   x = x >> 1   */
for loop will repeatedly shift right x until x becomes 0, use expression evaluation of x & 01 to control if
x & 01 masks of 1st bit of x if this is 1 then count++


Bit Fields
Bit Fields allow the packing of data in a structure. This is especially
useful when memory or data storage is at a premium. Typical examples:
Packing several objects into a machine word. e.g. 1 bit flags can be
compacted -- Symbol tables in compilers.
Reading external file formats -- non-standard file formats could be read in.
E.g. 9 bit integers.
C lets us do this in a structure definition by putting :bit length after the
variable. i.e.
struct packed_struct {
                 unsigned int f1:1;
                 unsigned int f2:1;
                 unsigned int f3:1;
                 unsigned int f4:1;
                 unsigned int type:4;
                 unsigned int funny_int:9;
} pack;
Here the packed_struct contains 6 members: Four 1 bit flags f1..f3, a 4 bit
type and a 9 bit funny_int.
C automatically packs the above bit fields as compactly as possible,
provided that the maximum length of the field is less than or equal to the
integer word length of the computer. If this is not the case then some
compilers may allow memory overlap for the fields whilst other would store
the next field in the next word (see comments on bit fiels portability
below).
Access members as usual via:
pack.type = 7;
NOTE:
Only n lower bits will be assigned to an n bit number. So type cannot take
values larger than 15 (4 bits long).
Bit fields are always converted to integer type for computation. You are
allowed to mix ``normal'' types with bit fields.
The unsigned definition is important - ensures that no bits are used as a
flag.
Frequently device controllers (e.g. disk drives) and the operating system
need to communicate at a low level. Device controllers contain several
registers which may be packed together in one integer

1         1        1        1                                     1
8bits     9bits    5bits    5 bits ready  Error   Disk spinning   Write protection  Head Loaded  Error code
tracks   sector   command

Example Disk Controller Register We could define this register easily with
bit fields:
struct DISK_REGISTER  {
     unsigned ready:1;
     unsigned error_occured:1;
     unsigned disk_spinning:1;
     unsigned write_protect:1;
     unsigned head_loaded:1;
     unsigned error_code:8;
     unsigned track:9;
     unsigned sector:5;
     unsigned command:5;
};
To access values stored at a particular memory address, DISK_REGISTER_MEMORY
we can assign a pointer of the above structure to access the memory via:
struct DISK_REGISTER *disk_reg = (struct DISK_REGISTER *)
DISK_REGISTER_MEMORY;
The disk driver code to access this is now relatively straightforward:
/* Define sector and track to start read */
disk_reg->sector = new_sector;
disk_reg->track = new_track;
disk_reg->command = READ;
/* wait until operation done, ready will be true */
while ( ! disk_reg->ready ) ;
/* check for errors */
if (disk_reg->error_occured)
  { /* interrogate disk_reg->error_code for error type */
    switch (disk_reg->error_code)
    ......
  }

Portability
Bit fields are a convenient way to express many difficult operations.
However, bit fields do suffer from a lack of portability between platforms:
integers may be signed or unsigned
Many compilers limit the maximum number of bits in the bit field to the size
of an integer which may be either 16-bit or 32-bit varieties.  Some bit
field members are stored left to right others are stored right to left in
memory.
If bit fields are too large, next bit field may be stored consecutively in
memory (overlapping the boundary between memory locations) or in the next
word of memory.  If portability of code is a premium you can use bit
shifting and masking to achieve the same results but not as easy to express
or read. For example:
unsigned int  *disk_reg = (unsigned int *) DISK_REGISTER_MEMORY;
/* see if disk error occured */
disk_error_occured = (disk_reg & 0x40000000) >> 31;


*******************************************
Identifiers: variable names, functions, types and labels
*******************************************
	First character must be a letter.
	Identifiers are case sensitive.
	
main function:
	Ex1:
main(void)	/*when no parameters are passed to the program*/
	{
	}

return 0;
This statement returns a value of 0 to the calling function. Since this happens to be the main() function, a value of 0, which is generally accepted to mean the program ran successfully and without incident, is returned to the operating system. 


/* if the value is declared before the function main(), the memory area is initialized to zero and the value is a global variable */
Ex:     int value;
        main()


/* global variables take up room as long as the program remains active, which make less efficient use of RAM.  */


*******************************************
Static Variables 
*******************************************
A static variable is local to a particular function. However, it is only initialised once (on the first call to function).  Also the value of the variable on leaving the function remains intact. On the next call to the function the the static variable has the same value as on leaving. 
To define a static variable simply prefix the variable declaration with the static keyword. For example: 
    void stat(); /* prototype fn */ 
    main()
    { int i;
      for (i=0;i<5;++i)
      stat();
    }
    stat()
    { int auto_var = 0;
      static int static_var = 0;
      printf( ``auto = %d, static = %d n'',
      auto_var, static_var);
      ++auto_var;
      ++static_var;
    }
Output is: auto_var = 0, static_var= 0
           auto_var = 0, static_var = 1
           auto_var = 0, static_var = 2
           auto_var = 0, static_var = 3
           auto_var = 0, static_var = 4
Clearly the auto_var variable is created each time. The static_var is created once and remembers
its value. 


*******************************************
Data Types:
*******************************************
	void		no data or empty set of data see function Ex
	integral(integer)	sign or unsigned
	int or integral	short or long, unsigned
	enum or enumerations
	float 
	double
	char or character	sign or unsigned

Ex: char name[PLAYER_NAME_MAX_LEN+1];
Ex1:  int value = 10;    /* this is better than Ex2 in two seperate statements because the value is not initialized in-between */
Ex2:  int value;
      value = 10;


Note the use of the "char" type described above. Here we are declaring an array of char large enough to store a player's name. IMPORTANT: We must add one extra char of space in order to leave room for the NULL (0) character that terminates the string!

The const keyword is to declare a constant, as shown below: 
int const a = 1;
const int a =2;
Note:  You can declare the const before or after the type.  It is usual to initialise a const with a value as it cannot get a value any other way. The preprocessor #define is another more flexible method to define constants in a program. 

const int value=2;
/* the program will not allow the variable value to change in the program */

The keyword volatile is also part of the ANSI-C standard.  Even though the value of a volatile variable can be changed by you, the programmer, there may be another mechanism by which the value could be changed, such as by a hardware interrupt timer causing the value to be incremented. Example:
volatile int CENTER = 6;    /* The value of CENTER may be changed
                                 by something external to this
                                 program.                          */

32 bit

C type		Size in Byte	Lower Bound		Upper Bound
Char			1			-128			127
Unsigned char	1			0			255
Short int		2			-32768		+32767
Unsigned short int2			0			65536
long or  Int 	4			-2,147,483,648	+2exp91  1
Unsigned long	4			0			4,295,967,295
Unsigned int	4			0			4,295,967,295
Float			4			1.18 X 10exp-38	+3.4 X 10exp+38
enum			4			-2,147,483,648	+2exp91  1
Double		8			2.23 X 10exp-308	+1.79 X 10exp+308
Int64			8			-9,223,372,036,854,808	9,223,372,036,854,807
bool			1			false			true

BOOLEAN
0 means false
1,2,3,... means true

/* because of wrap around, problems can occur when using large values for an int the max value is 32,768 */
Ex:
int i;
int j;
i=15,000;
j=i+60,000;
/* j will not equal 75,000 !!!! */

/* use the following function to determine the size of variables on your cpu or to initialyze an array*/
sizeof()


*******************************************
Conversions from one type to another
Coercion or Type-Casting 
*******************************************
C is one of the few languages to allow coercion, that is forcing one variable of one type to be another type. C allows this using the cast operator ( ). So: 
    int integernumber;
    float floatnumber=9.87;
    integernumber=(int)floatnumber;
assigns 9 (the fractional part is thrown away) to integernumber. 
Coercion can be used with any of the simple data types including char, so: 
     int integernumber;
     char letter='A';
     integernumber=(int)letter;
assigns 65 (the ASCII code for `A') to integernumber. 
Some typecasting is done automatically -- this is mainly with integer compatibility. 
A good rule to follow is: If in doubt cast. 
Another use is the make sure division behaves as requested: If we have two integers internumber
and anotherint and we want the answer to be a float then : 
   floatnumber =  (float) internumber / (float) anotherint;
	
	CAST:	Ex:	int x;
			log((double)x);


*******************************************	
Character Constants:
*******************************************
	Sequence of one or more characters enclosed in single quotes. 
		Ex: 'a' '#' '\n'
	\n	newline		NL
	\t	horizontal tab	HT	
	\v	vertical tab	VT
	\b	backspace	BS
	\r	carriage return	CR
	\f	form feed	FF
	\a	audible alert	BEL
	\\	backlash		\
	\?	question mark	?
	\'	single quote	'
	\"	double quote	"
	\ooo	octal number	ooo
	\xhh	hex number	hh

Other:
	\	The backlash character may be used to splice lines for continuation.
	Ex:	a = 123 \
		.246;    
	is the same as:
		a = 123.246


*******************************************
Derived Data Types:
*******************************************
Enumerated Types 
Enumerated types contain a list of constants that can be addressed in integer values. We can declare types and variables as follows. 
  enum days {mon, tues, ..., sun} week; 
  enum days week1, week2; 
NOTE: As with arrays first enumerated name has index value 0. So mon has value 0, tues 1, and so on. week1 and week2 are variables. 
We can define other values: 
  enum escapes { bell = `a',
                 backspace = `b',  tab = `t',
                 newline = `n', vtab = `v',
                 return = `r'};
We can also override the 0 start value: 
  enum months {jan = 1, feb, mar, ......, dec}; 
Here it is implied that feb = 2 etc.


*******************************************
Arrays		
*******************************************
Arrays are defined in C as in the following example: 
Ex:
  int listofnumbers[50];

BEWARE: In C Array subscripts start at 0 and end one less than the array size. For example, in the above case valid subscripts range from 0 to 49. This is a BIG difference between C and other languages and does require a bit of practice to get in the right frame of mind. 

Elements can be accessed in the following ways:- 

  thirdnumber=listofnumbers[2];
  listofnumbers[5]=100;

Multi-dimensional arrays can be defined as follows: 

  int tableofnumbers[50][50];

Ex: 	ar[N] is ar[0] to ar[N-1]
	Array ar is a like a  pointer that has address the first element of the array, ar[0], except that ar is not a variable but a constant which make it different to a pointer. i.e. ar = ar + 1; is not possible
	instead do p=&ar[0], then p=p+2 and now p points to same as address of ar[2]

/* use the following function to determine the size of variables on your cpu or to initialyze an array*/
sizeof()

	
*******************************************
Strings
*******************************************

String Handling: <string.h>
Strings are defined as an array of characters or a pointer to a portion of memory containing ASCII characters. A string in C is a sequence of zero or more characters followed by a NULL ( \0 )character:
NAME: D A V E \0
      0 1 2 3 4
It is important to preserve the NULL terminating character as it is how C defines and manages variable length strings. All the C standard library functions require this for successful operation, apart from some
length-restricted functions ( strncat(), strncmp,() and strncpy()).

C Strings are defined as arrays of characters. For example, the following defines a string of 50 characters: 

char name[50];

C has no string handling facilities built in and so the following are all illegal after the definitions:
  char firstname[50],lastname[50],fullname[100];
       firstname= "Arnold"; /* Illegal */
       lastname= "Schwarznegger"; /* Illegal */
       fullname= "Mr"+firstname+lastname; /* Illegal */ 

#define TITLE "My program"; /* the compiler adds a 0 terminator at the end of the string */
char *strgptr = "My program";
char stringvar[]= "My program";
char bigstrg[80] = "My program";

To print a string we use printf with a special %s control character: 
   printf(``%s'',name); 

In order to allow variable length strings the 0 character is used to indicate the end of a string.

Ex: char s[20];   /* 19 character string plus 1 terminating 0 */

for long string use a slash "/" at the end of the line to continue
char *p = "This is a long string that I have /
typed to illustrate the example";

Str[12]='\0'; 	/* is the same as: */
Str[12]=0;  	/* both will terminate the string at position 13, however: */
Str[12]='0'; 	/* is different and represent the character zero: */
Str[12]=48; 	/* is the ASCII value for the zero character */


*******************************************
Pointers
*******************************************
		Variable that holds the address of an object.
		Ex: 	int *p 	/*pointer p to an object of type integer */
		Ex:	char *strs[10]   /*array of 11 pointers pointing to objects of type char */
		Ex:	*p  /* de-reference the pointers and gives value of content */
		Ex: 	p=&x	/*assign the address of x to p so that p points to x */
			x=4	/* assign 4 to x */
			y=*p	/* assign the value where p points to y, so y=4 */

A pointer is a variable which contains the address in memory of another variable. We can have a pointer to any variable type. The unary or monadic operator & gives the ``address of a variable''. The indirection or dereference operator * gives the ``contents of an object pointed to by a pointer''.
To declare a pointer to a variable do:
int *pointer;
NOTE: We must associate a pointer to a particular type: You can't assign the address of a short int to a long int, for instance.
IMPORTANT: When a pointer is declared it does not point anywhere. You must set it to point somewhere before you use it.
So ...
  int *ip;
  *ip = 100;   will generate an error (program crash!!).
The correct use is:
   int *ip;
   int x;
   ip = &x;
   *ip = 100;

We can do integer arithmetic on a pointer:
  float *flp, *flq;
  *flp = *flp + 10;
  ++*flp;
  (*flp)++;
  flq = flp;
NOTE: A pointer to any variable type is an address in memory -- which is an integer address. A pointer is definitely NOT an integer.  The reason we associate a pointer to a data type is so that it knows how many bytes the data is stored in. When we increment a pointer we increase the pointer by one ``block'' memory.
So for a character pointer ++ch_ptr adds 1 byte to the address.  For an integer or float ++ip or ++flp adds 4 bytes to the address.

Common Pointer Pitfalls

Two common mistakes made with pointers are:
1. Not assigning a pointer to memory address before using it
  int *x;
  *x = 100;
  we need a physical location say: int y;
  x = &y;
  *x = 100;
This may be hard to spot. NO COMPILER ERROR. Also x could be some random address at initialisation.
2. Illegal indirection
Suppose we have a function malloc() which tries to allocate memory dynamically (at run time) and returns a pointer to block of memory requested if successful or a NULL pointer otherwise.
char *malloc() -- a standard library function.
Let us have a pointer:
char *p;
Consider:
*p = (char *) malloc(100); /* request 100 bytes of memory */
*p = `y';
There is a mistake above. What is it?
No * in
*p = (char *) malloc(100);
Malloc returns a pointer. Also p does not point to any address.  The correct code should be:
p = (char *) malloc(100);
This code rectified one problem but if no memory is available and p is NULL the following line will not work:
*p = `y';
A good C program would check for this:
  p = (char *) malloc(100);
  if ( p == NULL)
     { printf(``Error: Out of Memory \n'');
       exit(1);
     }
  *p = `y';


*******************************************
Pointers and Arrays
*******************************************
Pointers and arrays are very closely linked in C. Hint: think of array elements arranged in consecutive memory locations.
Consider the following:
   int a[10], x;
   int *pa;
   pa = &a[0];  /* pa pointer to address of a[0] */
   x = *pa;     /* x = contents of pa (a[0] in this case) */
To get somewhere in the array using a pointer we could do:
pa + i     or     a[i]
WARNING: There is no bound checking of arrays and pointers so you can easily go beyond array memory and overwrite other things. C however is much more subtle in its link between arrays and pointers. For example we can just type
pa = a;
instead of
pa = &a[0]
and
a[i] can be written as *(a + i).
i.e.   &a[i]   is the same as:     a + i.
We also express pointer addressing like this:
pa[i]  or   *(pa + i).

However pointers and arrays are different.  A pointer is a variable. We can do
pa = a and pa++.
An Array is not a variable. a = pa and a++ ARE ILLEGAL.  When an array is passed to a function what is actually passed is its initial elements location in memory.
strlen(s) is the same as:
strlen(&s[0])
This is why we declare the function:
int strlen(char s[]);
An equivalent declaration is : int strlen(char *s);
since char s[] is the same as char *s.
strlen() is a standard library function that returns the length of a string.
Ex:
int strlen(char *s)
{
  char *p = s;
  while (*p != `\0');
  p++;
  return p-s;
}
The following examle is a function to copy a string to another string. strcpy() is a standard library function that does this.
void strcpy(char *s, char *t)
{  while ( (*s++ = *t++) != `\0');}
This uses pointers and assignment by value. NOTE: Uses of Null statements with while.

We can have arrays of pointers since pointers are variables. Example use: Sort lines of text of different length.
NOTE: Text can't be moved or compared in a single operation. Arrays of Pointers are a data representation that will cope efficiently and conveniently with variable length text lines. How can we do this?: 
Store lines end-to-end in one big char array  \n will delimit lines.
Store pointers in a different array where each pointer points to 1st char of
each new line.
Compare two lines using strcmp() standard library function.
If 2 lines are out of order -- swap pointer in pointer array (not text).


*******************************************
Multidimensional arrays and pointers
*******************************************
We should think of multidimensional arrays in a different way in C, a 2D array is really a 1D array, each of whose elements is itself an array. Hence a[n][m] notation. Array elements are stored row by row. When we pass a 2D array to a function we must specify the number of columns -- the number of rows is irrelevant.  The reason for this is pointers again. C needs to know how many columns in order that it can jump from row to row in memory. Consider int a[5][35] to be passed in a function. We can do:
f(int a[][35]) {.....}
or even:
f(int (*a)[35]) {.....}
We need parenthesis (*a) since [] have a higher precedence than *.
  int (*a)[35]; declares a pointer to an array of 35 ints. 
  int *a[35]; declares an array of 35 pointers to ints.
Now lets look at the (subtle) difference between pointers and arrays. Strings are a common application of this.
Consider:
char *name[10];
char Aname[10][20];
We can legally do name[3][4] and Aname[3][4] in C.
However
Aname is a true 200 element 2D char array.
access elements via
20*row + col + base_address
in memory.
name has 10 pointer elements.
NOTE: If each pointer in name is set to point to a 20 element array then and only then will 200 chars be set aside (+ 10 elements).  The advantage of the latter is that each pointer can point to arrays be of
different length.
Consider:
   char *name[] = { ``no month'', ``jan'',
                                ``feb'', ... };
   char Aname[][15] = { ``no month'', ``jan'',
                                ``feb'', ... };
(picture representation is:)
name
0 ->no month\0
1->jan\0
2->feb\0

Aname
no month\0 + x elements up to 15
jan\0 + x elements up to 15
feb\0 + x elements up to 15
....
additional rows up to 13


*******************************************
Static Initialisation of Pointer Arrays
*******************************************
Initialisation of arrays of pointers is an ideal application for an internal static array.
some_fn()
 {
   static char *months = { ``no month'', ``jan'', ``feb'', ...};
 }
static reserves a private permanent bit of memory.


*******************************************
Pointers to Pointers
*******************************************
Consider the following:
char ch;  /* a character */
char *pch; /* a pointer to a character */
char **ppch; /* a pointer to a pointer to a character */
             /* **ppch is the same as *ppch[] */
 **ppch refers to memory address of *pch which refers to the memory address
of the variable ch.

ppch -->pch-->ch

char * refers to a (NULL terminated string. So one common and convenient
notion is to declare a pointer to a pointer to a string
Pointer to String, Taking this one stage further we can have several strings
being pointed to by the pointer
Pointer to Several Strings We can refer to individual strings by ppch[0],
ppch[1], ..... Thus this is identical to declaring char *ppch[]. One common
occurrence of this type is in C command line argument input.


*******************************************
Character and String Conversion
*******************************************

Character conversions and testing, use:
 #include <ctype.h>  
The library ctype.h contains many useful functions to convert and test single characters. The common functions are prototyped as follows:
Character testing:
int isalnum(int c) -- True if c is alphanumeric.
int isalpha(int c) -- True if c is a letter.
int isascii(int c) -- True if c is ASCII .
int iscntrl(int c) -- True if c is a control character.
int isdigit(int c) -- True if c is a decimal digit
int isgraph(int c) -- True if c is a graphical character.
int islower(int c) -- True if c is a lowercase letter
int isprint(int c) -- True if c is a printable character
int ispunct(int c) -- True if c is a punctuation character.
int isspace(int c) -- True if c is a space character.
int isupper(int c) -- True if c is an uppercase letter.
int isxdigit(int c) -- True if c is a hexadecimal digit

Character Conversion:
int toascii(int c) -- Convert c to ASCII .
tolower(int c) -- Convert c to lowercase.
int toupper(int c) -- Convert c to uppercase.


To use string functions in this library you must use:
#include <stdlib.h>

There are a few functions that exist to convert strings to integer, long
integer and float values. They are:

double atof(char *string) -- Convert string to floating point value.
int atoi(char *string) -- Convert string to an integer value
int atol(char *string) -- Convert string to a long integer value.
double strtod(char *string, char *endptr) -- Convert string to a floating point value.
long strtol(char *string, char *endptr, int radix) -- Convert string to a long integer using a given radix.
unsigned long strtoul(char *string, char *endptr, int radix) -- Convert string to unsigned long.

/*conversion functions */
atof()  /* ascii to float */
atoi()  /* ascii to integer */
atol()  /* ascii to long integer */
Ex: price = atof(s);


Most of these are fairly straightforward to use. For example:
char *str1 = "100";
char *str2 = "55.444";
char *str3 = "      1234";
char *str4 = "123four";
char *str5 = "invalid123";
int i;
float f;
i = atoi(str1);  /* i = 100 */
f = atof(str2);  /* f = 55.44 */
i = atoi(str3);  /* i = 1234 */
i = atoi(str4);  /* i = 123 */
i = atoi(str5);  /* i = 0 */

Note:
-Leading blank characters are skipped.
-Trailing illegal characters are ignored.
-If conversion cannot be made zero is returned and errno is set with the
value ERANGE.


*******************************************
printf()
*******************************************
The function Printf is defined as follows:
int printf(char *format, arg list ...) -- prints to stdout the list of arguments according to specified format string.
Returns number of characters printed.
The format string has 2 types of object:
- ordinary characters -- these are copied to output.
- conversion specifications -- denoted by % and listed in Table below.

Table: Printf/scanf format characters
Format Spec (%)        Type             Result
c                      char                single character
i,d                    int                 decimal number
o                      int                 octal number
x,X                    int                 hexadecimal number lower/uppercase notation
u                      int                 unsigned int
s                      char *              print string terminated by \0
f                      double/float        format -m.ddd...
e,E                    double/float        Scientific Format -1.23e002
g,G                    double/float        e or f whichever is most compact
%                      -                   print % character

Between % and format char we can put:
- (minus sign)  left justify.
integer number  field width.
m.d   m = field width, d = precision of number of digits after decimal point or number of chars from a string.
Examples:
printf("%-2.3f\n",17.23478);
The output on the screen is:
          17.235
and:
printf("VAT=17.5%%\n");
....outputs:
          VAT=17.5%


/* Print out result */
  printf("Initial balance: %f Final balance: %f\n", initial_balance, balance);
The two %f sequences in the string are used to tell printf() where to print the floating-point values we will be passing to it. So the values of initial_balance and balance will be substituted for %f at those points. 
(The number of % sequences must match the number of arguments actually passed! To output an integer value, the %d sequence would be used instead of %f.) 

printf("bonjour \n"); /*new line after bonjour will need #include <stdio.h>
*/


*******************************************
scanf()
*******************************************

scanf
This function is defined as follows:
int scanf(char *format, args....)  reads from stdin and puts input in address of variables specified in args list. Returns number of chars read.  Format control string similar to printf Note: The ADDRESS of variable or a pointer to one is required by scanf.
scanf(``%d'',&i);
We can just give the name of an array or string to scanf since this corresponds to the start address of the array/string.
   char string[80];
   scanf(``%s'',string);

scanf("%d",&v);  /* passes the address of v and stores value in v */
scanf ("%20s",s)  /* prints the ascii string s */    /* Fetch starting values from user */  
    printf("Initial balance: ");
    scanf("%f", &initial_balance);
The first line is simple; it prints a message to the user, prompting for an initial balance. 
The second line calls scanf(), a function which can be used to gather user input. scanf is analogous to printf(), and is used in a similar fashion: a series of % sequences between double-quotes specify the types of values to be input (%f for floating-point values here, just as for printing such values), and the variables to be input follow the quoted string.

When you pass a variable to a function, the function receives the value, but stored in a different place.
So while the function is permitted to change the value, that change won't be reflected in the calling function. Since a function can't change the values passed to it, in order for scanf() to let the user set the variables you pass, it must be given the *location* of the variables, instead of the *value* stored at them. The "&" operator returns the *location* of a variable. 

Sometimes we replace scanf() with user-made functions line_read() and int_read() because scanf() does not respect carriage returns well, which can lead to serious confusion for the user of a program. 

void line_read(char *s, int max_len);

This function's purpose is to read a line of input (ending with the user striking carriage return), and copy the characters to the location pointed to by "s". 

void line_read(char *s, int max_len) {
  int len;
  /* Now use fgets to read a line of input from the user. scanf("%s") would be easier, but would not allow spaces. We call the function fgets(), which is part of the standard I/O package brought in by stdio.h. fgets accepts three arguments: a pointer to char (s in this case), a maximum number of characters (of which it reserves the last for a terminating null), and a "stream." Streams are variables of type "FILE *". They are used to access files on disk, and also to communicate with other devices. In this case, we are using the stream "stdin".   "stdin" is a global variable, accessible to any program which includes stdio.h. It refers to the stream of input from the user. */
  fgets(s, max_len, stdin); 
/*Here we invoke the function strlen(), provided by string.h, in order to fetch the length of the string pointed to by s. (The length of the string is the number of characters *before* the terminating null, and does not include the null itself.) */
  len = strlen(s); 
/* fgets() stores the carriage return itself in the string, so we need to remove it. Here we access the last element in the string (again, not including the null), test to see if it is a carriage return, and, if so, set it to a null, ending the string at that point to get rid of the carriage return. */
  if (s[len-1] == '\n') {
    s[len-1] = '\0';
    }    
  }   

This function reads a line of input also, converts the text the user entered to an integer, and returns the integer. It is similar to scanf("%d", &x), where x is the integer variable being read into, but not identical, because scanf() is sensitive to spaces; if the user enters "4 5" instead of "45", scanf() treats this as two separate numbers by scanf() and the *next* call to scanf() will get the 5, which is confusing to the user (particularly in a situation where we are prompting for one number and the user should not be entering two!). Even worse, scanf() does not get rid of the carriage return following the user's input, which confuses attempts to read a line of text elsewhere after scanf() has read in a value. 

int int_read(); /* prototype */
int int_read() {
  char s[10];
  int i;
  line_read(s, 10);
  /* atoi(): a standard function which accepts a string such as "123" and 
    returns an integer such as 123. */
  i = atoi(s);
  return i;
}


*******************************************
sprintf and sscanf
*******************************************
These are like fprintf and fscanf except they read/write to a string.
int sprintf(char *string, char *format, args..)
int sscanf(char *string, char *format, args..)
For Example:
  float full_tank = 47.0; /* litres */
  float miles = 300;
  char miles_per_litre[80];
  sprintf( miles_per_litre,``Miles per litre = %2.3f'', miles/full_tank);


*******************************************
getchar() and putchar()
*******************************************
There are a couple of function that provide basic I/O facilities, probably the most common are: getchar() and putchar(). They are defined and used as follows:
- int getchar(void) -- reads a char from stdin
- int putchar(char ch) -- writes a char to stdout, returns character written.
   int ch;
   ch = getchar();
  (void) putchar((char) ch);

Related Functions:
int getc(FILE *stream),
int putc(char ch,FILE *stream)


*******************************************
String Functions
*******************************************
Basic String Handling Functions. All the string handling functions are prototyped in the following libraries so you will need:
#include <string.h>
or
#include <stdio.h>

getch()  /* does not echo characters */
getche() /* echos characters */
gets()
Ex:     char buffer[128];
        gets(buffer);

char *strcpy(const char *string1,const char *string2) -- Copy string2 to stringl.
char *strncpy(const char *string1,const char *string2, size_t n) --Copy first n characters of string2 to stringl.
  ex: strncpy(des,source,10)  /*copies 10 char from source to destination */

Overwriting the end of a character array is easier to do than with the numeric array.  Some bytes of memory somewhere were just erased  by the following mistake in this example:
Char buff[10] = 'a string';
Strcpy(buff, "This is a test.");   //OOPS, the second string is too long and will overide some unknown parts in the memory!!!!

char *stpcpy (const char *dest,const char *src) -- Copy one string into another.

int strcmp(const char *string1,const char *string2) -- Compare string1 and string2 to determine alphabetic order.

stricmp()               /* compares strings and ignores upper and lower case*/

int strncmp(const char *string1, char *string2, size_t n) -- Compare first n characters of two strings.

int strcasecmp(const char *s1, const char *s2) -- case insensitive version of strcmp().

int strncasecmp(const char *s1, const char *s2, int n) -- case insensitive version of strncmp().

int strlen(const char *string) -- Determine the length of a string.

strdup()                /* returns the address of a string addressed by its argument, used with free() after */
  free()                /* used after strdup()*/

strncat()               /* concatenates two strings */
char *strncat(const char *string1, char *string2, size_t n) -- Append n characters from string2 to stringl.

char *strerror(int errnum) -- Get error message corresponding to specified error number.

The use of most of the functions is straightforward, for example:
char *str1 = "HELLO";
char *str2;
int length;
length = strlen("HELLO"); /* length = 5 */
(void) strcpy(str2,str1);
Note that both strcat() and strcpy() both return a copy of their first argument which is the destination array. Note the order of the arguments is destination array followed by source array which is sometimes easy to get
the wrong around when programming.
The strcmp() function lexically compares the two input strings and returns:
  Less than zero     -- if string1 is lexically less than string2
  Zero               -- if string1 and string2 are lexically equal
  Greater than zero  -- if string1 is lexically greater than string2

The strncat(), strncmp,() and strncpy() copy functions are string restricted version of their more general counterparts. They perform a similar task but only up to the first n characters. Note the the NULL terminated requirement may get violated when using these functions, for example:
char *str1 = "HELLO";
char *str2;
int length = 2;

(void) strcpy(str2,str1, length); /* str2 = "HE" */
str2 is NOT NULL TERMINATED!! -- BEWARE


*******************************************
Memory Operations: <memory.h>
*******************************************
Although not strictly string functions the functions are prototyped in:
#include <string.h>

void *memchr (void *s, int c, size_t n) -- Search for a character in a buffer .

int memcmp (void *s1, void *s2, size_t n) -- Compare two buffers.
memcmp()                /* compares memory characters */

void *memcpy (void *dest, void *src, size_t n) -- Copy one buffer into another .
memcpy()                /* fills memory bytes with specified char,  use #include <mem.h>  */

void *memmove (void *dest, void *src, size_t n) -- Move a number of bytes from one buffer to another.
memmove()               /* fills memory bytes with specified char,  use #include <mem.h>  */

void *memset (void *s, int c, size_t n) -- Set all bytes of a buffer to a given character.
memset()                /* fills memory bytes with specified char,  use #include <mem.h>  */

Their use is fairly straightforward and not dissimilar to comparable string operations (except the exact length (n) of the operations must be specified as there is no natural termination here).
Note that in all case two bytes of memory are copied. The sizeof() function comes in handy again here, for example:
char src[SIZE],dest[SIZE];
int  isrc[SIZE],idest[SIZE];
memcpy(dest,src, SIZE); /* Copy chars (bytes) ok */
memcpy(idest,isrc, SIZE*sizeof(int)); /* Copy arrays of ints */
memmove() behaves in exactly the same way as memcpy() except that the source and destination locations may overlap.
memcmp() is similar to strcmp() except here unsigned bytes are compared and returns less than zero if s1 is less than s2 etc.



*******************************************
String Searching functions
*******************************************

The library also provides several string searching functions:

char *strchr(const char *string, int c) -- Find first occurrence of character c in string.

char *strrchr(const char *string, int c) -- Find last occurrence of character c in string.
ex:  strrchr(s,'b')          /* search for last occurence of 'b' in string s */

char *strstr(const char *s1, const char *s2) -- locates the first occurrence of the string s2 in string s1.
Ex:  strstr(filename,".TXT") /* search for substring in filename */

char *strpbrk(const char *s1, const char *s2) -- returns a pointer to the first occurrence in string s1 of any character from string s2, or a null pointer if no character from s2 exists in s1

size_t strspn(const char *s1, const char *s2) -- returns the number of characters at the begining of s1 that match s2.

size_t strcspn(const char *s1, const char *s2) -- returns the number of characters at the begining of s1 that do not match s2.


char *strtok(char *s1, const char *s2) -- break the string pointed to by s1 into a sequence of tokens, each of which is delimited by one or more characters from the string pointed to by s2.

char *strtok_r(char *s1, const char *s2, char **lasts) -- has the same functionality as strtok() except that a pointer to a string placeholder lasts must be supplied by the caller.

strupr(filename)        /* to convert the original string to all uppercase letters before calling strstr(); */

strchr() and strrchr() are the simplest to use, for example:
char *str1 = "Hello";
char *ans;
ans = strchr(str1,'l');
After this execution, ans points to the location str1 + 2

strpbrk() is a more general function that searches for the first occurrence of any of a group of characters, for example:
char *str1 = "Hello";
char *ans;
ans = strpbrk(str1,'aeiou');
Here, ans points to the location str1 + 1, the location of the first e.

strstr( ) returns a pointer to the specified search string or a null pointer if the string is not found. If s2 points to a string with zero length (that is, the string ""), the function returns s1. For example,
char *str1 = "Hello";
char *ans;
ans = strstr(str1,'lo');
will yield ans = str + 3.

strtok() is a little more complicated in operation. If the first argument is not NULL then the function finds the position of any of the second argument characters. However, the position is remembered and any subsequent calls to strtok() will start from this position if on these subsequent calls the first argument is NULL. For example, If we wish to break up the string str1 at each space and print each token on a new line we could do:
char *str1 = "Hello Big Boy";
char *t1;
for ( t1 = strtok(str1," ");
      t1 != NULL;
      t1 = strtok(NULL, " ") )
printf("%s\n",t1);
Here we use the for loop in a non-standard counting fashion:
- The initialisation calls strtok() loads the function with the string str1
- We terminate when t1 is NULL
- We keep assigning tokens of str1 to t1 until termination by calling
strtok() with a NULL first argument.


*******************************************
The if statement 
*******************************************
The if statement has the same function as other languages. It has three basic forms: 

 	 if  (expression)
 	    statement;
...or: 
  	if  (expression)
 	    statement1;
 	else
    statement2;
...or: 
if  (expression)
    statement1;
              else if (expression)
   statement2;
else
   statement3;

For example:- 
  int x,y,w;
  main()
  {
      if (x>0)
      {
          z=w;
          ........
       }
       else
       {
           z=y;
           ........
       }
  }


*******************************************
The ? operator 
*******************************************
The ? (ternary condition) operator is a more efficient form for expressing simple if statements. It has the following form: 

  expression1 ? expression2:  expression3

It simply states:      if expression1 then expression2 else expression3 

For example to assign the maximum of a and b to z: 

  z = (a>b) ? a : b;

which is the same as: 
  if (a>b)
        z = a;
  else
        z=b;


*******************************************
switch statement
*******************************************
Ex:
switch (value) {
  case 11: 
    printf("jack ");
    break;
  case 12:
    printf("queen ");
    break;
  case 13:
    printf("king ");
    break;
  case 14:
    printf("ace ");
    break;
  default:
    /* This shouldn't happen, so say so */
    printf("Unknown card! Value: %d\n", value);
    break;
}


*******************************************
for loop
*******************************************
The "for" keyword is always followed by a set of three expressions, all enclosed in an outer set of parentheses. The first of the three is an assignment statement. This statement is performed once, at the very beginning of the loop.  The second is a "conditional expression". In C, a conditional expression is actually no different from any other expression (computation). If the expression yields a NON-ZERO value (any value EXCEPT zero), it is regarded as "true." If it yields precisely zero, it is regarded as "false." The conditional expression in a for loop is evaluated at the *start* of every pass through the loop. (Note that this means that if the condition is not true on the first pass through the loop, the loop will never execute at all!) 
A for loop consists of the for keyword, the three expressions inside the parentheses, and the next statement *following* the parentheses. This following statement can be either a simple statement (one action ending in a semicolon) or a compound statement (a series of statements within { } 's). To avoid losing track of whether the loop is correctly written, it is best to always use a compound statement, even if you only put one simple statement inside it. 

The C for statement has the following form: 
  for  (expression1; 2; expression3)
                                 statement;
                                 or {block of statements}
expression1 initialises; expression2 is the terminate test; expression3 is the modifier (which may be more than just simple increment);

Ex:
  /* Loop through interest periods, increasing balance */
  for (i=0; (i < interest_periods); i++) {
...;
}
Ex2:
for (x=0;((x>3) && (x<9)); x++)
Ex3: 
for (x=0,y=4;((x>3) && (y<9)); x++,y+=2)
Ex4:
for (x=0,y=4,z=4000;z; z/=10)

Example3 shows that multiple expressions can be separated by a ,. 
Example4, the loop will continue to iterate until z becomes 0;


*******************************************
while loop
******************************************* 
While loops are similar to the for loops, in that they continue until a condition ceases to be true. But they are simpler in that they consist only of the while keyword, a conditional expression in parentheses, and the following statement, which is executed until the condition ceases to be true. The condition is tested each time the loop returns to the top. If the condition is false at the very beginning, the loop will never execute. 

The while has the form: 
  while (expression)
        statement

Ex: 
while (!done) {
...;
}
Ex2:
while ( (ch = getchar()) != `q')
      putchar(ch);

The second example uses C standard library functions getchar() - reads a character from the keyboard - and putchar() - writes a given char to screen. The while loop will proceed to read from the keyboard and echo characters to the screen until a 'q' character is read. NOTE: This type of operation is used a lot in C and not just with character reading.


*******************************************
do loop
*******************************************
A "do" loop is just like a while loop, except that the condition comes at the end. This is convenient when we know we always want the loop to execute at least once.  

C's do-while statement has the form: 
  do 
   statement;
   while (expression);

Ex:
do {
    /* Flag */
    int blackjack = 0;
    ... additional code ...
  } while (new_game);


*******************************************
break and continue
*******************************************
The "continue" statement, when encountered inside any loop, skips over the remainder of the code inside the innermost loop and goes on to the next pass through the loop (if any). If several "for", "while", or "do" loops have been "nested", the innermost loop executing is the one affected. 

The break statement is similar to the continue statement, except that it escapes the innermost loop entirely, instead of skipping to the next iteration (pass through the loop). 

     break -- exit form loop or switch. 
     continue -- skip 1 iteration of loop. 


*******************************************
Structures:
*******************************************
It would be possible to write the complete programs using only simple variables and arrays. But consider how many different arguments would have to be passed to functions in order to do this! A function which prints out information about a player would need to be passed the player's name, the number of cards the player has, the array of cards in that player's hand, and so on. 
In C a "struct" is used  to declare a "record type" which can be passed and copied as a whole, and
its individual "fields" accessed when necessary.  A structure declaration consists of the word "struct", an (optional) name for the structure, and a list of variable declarations inside braces ("{" and "}").  The  declaration is followed by a final semicolon.

Ex:
/* A player_struct structure holds all the information associated with
  a particular player. */

struct player_struct {
  char name[PLAYER_NAME_MAX_LEN+1];
  int cards_total;
  int hand[HAND_CARDS_MAX];
  int games_won;
  int busted;
};

Now take a look at the first field's declaration: 
 
Now the structure has been described; but there is one more step necessary in order to turn it into a full- fledged C type. For this we use the "typedef" keyword: 

typedef struct player_struct player_t;

A "typedef" statement begins with the keyword "typedef" and is followed by type declaration (such as a struct definition or an existing type like int, char or float), followed by the name we wish the newly defined type to have.  If we did not do this, we could still use player_struct, but we would have to declare each variable of that type as follows: 

struct player_struct player;

By defining player_struct to be a type in its own right called player_t, we become able to use a much simpler declaration: 

player_t player;


*******************************************
Pointers and Structures
*******************************************
These are fairly straight forward and are easily defined. Consider the following:
struct COORD {float x,y,z;} pt;
struct COORD *pt_ptr;
pt_ptr = &pt; /* assigns pointer to pt */
the -> operator lets us access a member of the structure pointed to by a pointer.i.e.:
pt_ptr->x = 1.0;
pt_ptr->y = pt_ptr->y - 3.0;

Example: Linked Lists
 typedef struct {  int value;
                   ELEMENT *next;
                 } ELEMENT;
 ELEMENT n1, n2;
 n1.next = &n2;

(picture representation is:)
n1                  n2
  value,     /---->  value,
  *next ----/        *next

Linking Two Nodes NOTE: We can only declare next as a pointer to ELEMENT. We cannot have a element of the variable type as this would set up a recursive definition which is NOT ALLOWED. We are allowed to set a pointer reference since 4 bytes are set aside for any pointer. The above code links a node n1 to n2.


*******************************************
Unions:
*******************************************
A union is a variable which may hold (at different times) objects of different sizes and types. C uses the union statement to create unions, for example: 
          union number
                                 {
                                 short shortnumber;
                                 long longnumber;
                                 double floatnumber;
                                 } anumber

defines a union called number and an instance of it called anumber. number is a union tag and acts in
the same way as a tag for a structure. Members can be accessed in the following way: 
          printf("%ldn",anumber.longnumber);
This clearly displays the value of longnumber.  When the C compiler is allocating memory for unions it will always reserve enough room for the largest member (in the above example this is 8 bytes for the double).   In order that the program can keep track of the type of union variable being used at a given time it is common to have a structure (with union embedded in it) and a variable which flags the union type:


*******************************************
Functions:
*******************************************
C does not have procedures -- it uses functions to service both requirements. 

The void function provide a way of emulating PASCAL type procedures.  If you do not want to return a value you must use the return type void and miss out the return statement: 

	Ex:	void prn2d(int d)	/*function that does not return any values*/

Function declaration using prototypes as per ANSI standard occur when types of parameters are defined in the function declaration. It is usual (and therefore good) practice to prototype all functions at the start of the program, although this is not strictly necessary.  To declare a function prototype simply state the type the function returns, the function name and in brackets list the type of parameters in the order they appear in the function definition.

At the beginning before the main() function we give a "prototype" to tell the compiler what to expect.  Function prototypes always end in a semicolon. This distinguishes them from actual functions, which are followed by code between braces ( "{" and "}" ). 

Example to find the average of two integers: 
We would declare the function as:
      float findaverage(float a, float b);
 
We would call the function as follows:
      main()
      {
float x=5,y=15,result;
 	result=findaverage(x,y);
printf("average=%f\n",result);
      }
And define it as follows:
      float findaverage(float a, float b)
     { float average;
        average=(a+b)/2;
        return(average);
      }
Ex2:
/* The function deck_draw draws a card from a deck. It returns an integer between 0 and 51 representing the card. deck_draw() reshuffles the deck if necessary. The function accepts an array of cards and a pointer to the number of the top card in the array, which it will update after drawing a card. */

int deck_draw(int deck[ ], int *card_top); /* prototype */
main()
{
...
    /* Note the use of the & operator to pass the address of card_top, rather than just its value, in order to permit it to be changed. */
c = deck_draw(deck, &card_top);
...
}
/* Implementation of deck_draw(). The second argument is a "pointer" to a variable containing the number of the current top card.  This approach allows deck_draw() to modify the value. */
  
int deck_draw(int deck[ ], int *card_top) {
  /* Position of top card */
  int pos;
  /* Card to be returned */
  int c;
  /* Use the * operator, which in this context is the opposite of the & operator, to fetch the *value* stored at the *location* referred to by the pointer card_top */
  pos = *card_top;
  /* Fetch the card from the deck */
  c = deck[pos];
  /* Advance the card pointer */
  pos++;
  /* If we have just drawn the last card, reshuffle the deck */
  if (pos == 52) {
    deck_shuffle(deck);
    /* Which brings us back to the first card, at position 0 */
    pos = 0;
  }
  /* Now store this pos back into the location pointed to by card_top */ 
  *card_top = pos;
  /* Finally we return the card drawn */
  return c;
}


*******************************************
Functions and arrays
*******************************************
Single dimensional arrays can be passed to functions as follows:
  float findaverage(int size,float list[ ])
{ int i;
float sum=0.0;
for (i=0;i<size;i++)
sum+=list[i];
return(sum/size);
}
Here the declaration  float list[ ] tells C that list is an array of float. Note we do not specify the dimension of the array when it is a parameter of a function. Multi-dimensional arrays can be passed to functions as follows: 
void printtable(int xsize,int ysize,
float table[ ][5])
{ int x,y;
  for (x=0;x<xsize;x++)
  { for (y=0;y<ysize;y++)
    printf("t%f",table[x][y]);
    printf("n");
  }
}

Here float table[][5] tells C that table is an array of dimension N by 5 of float. Note we must
specify the second (and subsequent) dimension of the array BUT not the first dimension.


*******************************************
Pointer and Functions
*******************************************
When C passes arguments to functions it passes them by value. There are many cases when we may want to alter a passed argument in the function and receive the new value back once the function has finished. Other languages do this (e.g. var parameters in PASCAL). C uses pointers explicitly to do this. Other languages mask the fact that pointers also underpin the implementation of this.  The best way to study this is to look at an example where we must be able to receive changed parameters.

The usual function call:
swap(a, b) WON'T WORK.
Pointers provide the solution: Pass the address of the variables to the functions and access address of function.
Thus our function call in our program would look like this:
swap(&a, &b)
The Code to swap is fairly straightforward:
    void swap(int *px, int *py)
    { int temp;
      temp = *px;   /* contents of pointer */
      *px = *py;
      *py = temp;
    }

We can return pointer from functions. A common example is when passing back structures. e.g.:
typedef struct {float x,y,z;} COORD;
main()
{
   COORD p1, *coord_fn();  /* declare a fonction coord_fn to return a ptr of COORD type */
    ....
   p1 = *coord_fn(...);    /* assign contents of address returned */
    ....
}
   COORD *coord_fn(...)
   {
     COORD p;
     .....
     p = ....;  /* assign structure values */
     return &p; /* return address of p */
    }
Here we return a pointer whose contents are immediately unwrapped into a variable. We must do this straight away as the variable we pointed to was local to a function that has now finished. This means that the address space is free and can be overwritten. It will not have been overwritten straight after the function has quit though so this is perfectly safe.


*******************************************
Pointers to a Function
*******************************************
Pointer to a function are perhaps one of the more confusing uses of pointers in C. Pointers to functions are not as common as other pointer uses. However, one common use is in passing pointers to a function as a parameter
in a function call.  This is especially useful when alternative functions maybe used to perform similar tasks on data. You can pass the data and the function to be used to some control function for instance. The C standard library provided some basic sorting ( qsort) and searching (bsearch) functions. You can easily embed your own functions.
To declare a pointer to a function do:
int (*pf) ();
This simply declares a pointer *pf to function that returns an int. No actual function is pointed to yet.
If we have a function int f() then we may simply write:
pf = &f;
For compiler prototyping to fully work it is better to have full function prototypes for the function and the pointer to a function:
int f(int);
int (*pf) (int) = &f;
Now f() returns an int and takes one int as a parameter.
You can do things like:
ans = f(5);
ans = pf(5);
which are equivalent.
The qsort standard library function is a very useful function that is designed to sort an array by a key value of any type into ascending order, as long as the elements of the array are of fixed type.
qsort is prototyped in (stdlib.h):
void qsort(void *base, size_t num_elements, size_t element_size, int(*compare)(void const *, void  const *));
The argument base points to the array to be sorted, num_elements indicates how long the array is, element_size is the size in bytes of each array element and the final argument compare is a pointer to a function.  qsort calls the compare function which is user defined to compare the data when sorting. Note that qsort maintains it's data type independence by giving the comparison responsibility to the user. The compare function must return certain (integer) values according to the comparison result:
less than zero     : if first value is less than the second value
zero               : if first value is equal to the second value
greater than zero  : if first value is greater than the second value
Some quite complicated data structures can be sorted in this manner. For example, to sort the following structure by integer key:
typedef struct {
  int   key;
  struct other_data;
} Record;
We can write a compare function, record_compare:
int record_compare(void const *a, void  const *a)
  {  return ( ((Record *)a)->key - ((Record *)b)->key );
  }
Assuming that we have an array of array_length Records suitably filled with date we can call qsort like this:
qsort( array, arraylength, sizeof(Record), record_compare);


*******************************************
Searching and Sorting
*******************************************
To use all functions in this library you must use:
#include <stdlib.h>

The stdlib.h provides 2 useful functions to perform general searching and sorting of data on any type.
The qsort standard library function is a very useful function that is designed to sort an array by a key value of any type into ascending order, as long as the elements of the array are of fixed type.
qsort is prototyped in stdlib.h as:
void qsort(void *base, size_t num_elements, size_t element_size, int(*compare)(void const *, void  const *));
Similarly, there is a binary search function, bsearch() which is prototyped in stdlib.h as:
void *bsearch(const void *key, const void *base, size_t nel, size_t size, int (*compare)(const void *, const void *));
Using the same Record structure and record_compare function as the qsort()
example
typedef struct {
  int   key;
  struct other_data;
} Record;
int record\_compare(void const *a, void  const *a)
  {  return ( ((Record *)a)->key - ((Record *)b)->key );
  }
Also, Assuming that we have an array of array_length Records suitably filled with date we can call bsearch() like this:
Record key;
Record *ans;
key.key =  3; /* index value to be searched for */
ans = bsearch(&key, array, arraylength, sizeof(Record), record_compare);
The function bsearch() return a pointer to the field whose key filed is filled with the matched value of NULL if no match found.  Note that the type of the key argument must be the same as the array elements (Record above), even though only the key.key element is required to be set.


*******************************************
Command line input
*******************************************
C lets read arguments from the command line which can then be used in our programs. We can type arguments after the program name when we run the program. In order to be able to use such arguments in our code we must define them as follows:
main(int argc, char **argv)
So our main function now has its own arguments. These are the only arguments main accepts.
argc is the number of arguments typed -- including the program name.
argv is an array of strings holding each command line argument -- including the program name in the first array element.
A simple program example:
#include<stdio.h>
main (int argc, char **argv)
 { /* program to print arguments from command line */
   int i;
   printf(``argc = %d \n \n'',argc);
   for (i=0;i<argc;++i)
     printf(``argv[%d]: %s \n'',
     i, argv[i]);
 }
Assume it is compiled to run it as args.
So if we type:
args f1 ``f2'' f3 4 stop!
The output would be:
  argc = 6
  argv[0] = args
  argv[1] = f1
  argv[2] = f2
  argv[3] = f3
  argv[4] = 4
  argv[5] = stop!

NOTE:  <<...>>  argv[0] is program name.  argc counts program name Embedded `` '' are ignored.  Blank spaces delimit end of arguments.  Put blanks in `` '' if needed.


*******************************************
Dynamic Memory Allocation and Dynamic Structures
*******************************************
Dynamic allocation is a unique feature to C (amongst high level languages). It enables to create data types and structures of any size and length to suit program need within the program. Two common applications of this are: 
1. dynamic arrays 
2. dynamic data structure e.g. linked lists Malloc, Sizeof, and Free
The Function malloc is most commonly used to attempt to ``grab'' a continuous portion of memory. It is defined by:
void *malloc(size_t number_of_bytes)
That is to say it returns a pointer of type void * that is the start in memory of the reserved portion of size number_of_bytes. If memory cannot be allocated a NULL pointer is returned. Since a void * is returned the C standard states that this pointer can be converted to any type. The size_t argument type is defined in stdlib.h and is an unsigned type.  So:
 char *cp;
 cp = malloc(100);
attempts to get 100 bytes and assigns the start address to cp. Also it is usual to use the sizeof() function to specify the number of bytes:
    int *ip;
    ip = (int *) malloc(100*sizeof(int));
Some C compilers may require to cast the type of conversion. The (int *) means coercion to an integer pointer. Coercion to the correct pointer type is very important to ensure pointer arithmetic is performed correctly. It is good practice to use sizeof() even if you know the actual size you want. It makes for device independent (portable) code. sizeof can be used to find the size of any data type, variable or structure. Simply supply one of these as an argument to the function. SO:
  int i;
  struct COORD {float x,y,z};
  typedef struct COORD PT;
  sizeof(int), sizeof(i),
  sizeof(struct COORD) and
  sizeof(PT) are all ACCEPTABLE
In the above we can use the link between pointers and arrays to treat the reserved memory like an array. i.e we can do things like:
ip[0] = 100; or
for(i=0;i<100;++i) scanf("%d",ip++);
When you have finished using a portion of memory you should always free() it. This allows the memory freed to be available again, possibly for further malloc() calls The function free() takes a pointer as an argument and frees the memory to
which the pointer refers. 


*******************************************
Calloc and Realloc
*******************************************
There are two additional memory allocation functions, Calloc() and Realloc(). Their prototypes are given below:

void *calloc(size_t num_elements, size_t element_size};
void *realloc( void *ptr, size_t new_size);

Malloc does not initialise memory (to zero) in any way. If you wish to initialise memory then use calloc. Calloc is slightly more computationally expensive but, occasionally, more convenient than malloc. Also note the different syntax between calloc and malloc in that calloc takes the number of desired elements, num_elements, and element_size, element_size, as two individual arguments. Thus to assign 100 integer elements that are all initially zero you would
do:
 int *ip;
 ip = (int *) calloc(100, sizeof(int));

Realloc is a function which attempts to change the size of a previous allocated block of memory. The new size can be larger or smaller. If the block is made larger then the old contents remain unchanged and memory is added to the end of the block. If the size is made smaller then the remaining contents are unchanged. If the original block size cannot be resized then realloc will attempt to assign a new block of memory and will copy the old block contents. Note a new pointer (of different value) will consequently be returned. You must use this new value. If new memory cannot be reallocated then realloc returns NULL.
Thus to change the size of memory allocated to the *ip pointer above to an array block of 50 integers instead of 100, simply do:
ip = (int *) realloc( ip, 50);


*******************************************
Linked Lists
*******************************************
Let us now return to our linked list example:
  typedef struct {  int value;
                    ELEMENT *next;
                 } ELEMENT;
We can now try to grow the list dynamically:
link = (ELEMENT *) malloc(sizeof(ELEMENT));
This will allocate memory for a new link. If we want to deassign memory from a pointer use the free() function:
free(link)


*******************************************
Arithmetic Functions
*******************************************
There are three basic categories of functions: Arithmetic, Random Numbers, String Conversion
To use all functions in this library you must use:
#include <stdlib.h>

There are 4 basic integer functions:

int abs(int number);
long int labs(long int number);
div_t div(int numerator,int denominator);
ldiv_t ldiv(long int numerator, long int denominator);

Essentially there are two functions with integer and long integer compatibility.
abs
functions return the absolute value of its number arguments. For example,
abs(2) returns 2 as does abs(-2).
div  takes two arguments, numerator and denominator and produces a quotient and a remainder of the integer division. The div_t structure is defined in stdlib.h as follows:
typedef struct {
        int  quot; /* quotient */
        int  rem;  /* remainder */
} div_t;
(ldiv_t is similarly defined).
Thus:
#include <stdlib.h>
.....
int num = 8, den = 3;
div_t ans;
ans = div(num,den);
printf("Answer:\n\t Quotient = %d\n\t Remainder = %d\n", \
ans.quot,ans.rem);
Produces the following output:
Answer:
  Quotient = 2
  Remainder = 2


*******************************************
Mathematics: <math.h>
*******************************************
You must #include <math.h> and must remember to link in the math library at compilation:
cc mathprog.c -o mathprog -lm
Consider:
double x;
x = sqrt(63.9);
If the #include is forgotten, having not seen the prototype for sqrt the compiler (by default) assumes that the function returns an int and converts the value to a double with meaningless results.

Math Functions
Some common math functions are listed below:
double acos(double x)                -- Compute arc cosine of x.
double asin(double x)                -- Compute arc sine of x.
double atan(double x)                -- Compute arc tangent of x.
double atan2(double y, double x)     -- Compute arc tangent of y/x.
double ceil(double x)                -- Get smallest integral value that exceeds x.
double cos(double x)                 -- Compute cosine of angle in radians.
double cosh(double x)                -- Compute the hyperbolic cosine of x.
div_t div(int number, int denom)     -- Divide one integer by another.
double exp(double x)                 -- Compute exponential of x
double fabs (double x)               -- Compute absolute value of x.
double floor(double x)               -- Get largest integral value less than x.
double fmod(double x, double y)      -- Divide x by y with integral quotient and return remainder.
double frexp(double x, int *expptr)  -- Breaks down x into mantissa and exponent of no.
labs(long n)                         -- Find absolute value of long integer n.
double ldexp(double x, int exp)      -- Reconstructs x out of mantissa and exponent of two.
ldiv_t ldiv(long number, long denom) -- Divide one long integer by another.
double log(double x)                 -- Compute log(x).
double log10 (double x )             -- Compute log to the base 10 of x.
double modf(double x, double *intptr) -- Breaks x into fractional and integer parts.
double pow (double x, double y)      -- Compute x raised to the power y.
double sin(double x)                 -- Compute sine of angle in radians.
double sinh(double x)                -- Compute the hyperbolic sine of x.
double sqrt(double x)                -- Compute the square root of x.
void srand(unsigned seed)            -- Set a new seed for the random number generator (rand).
double tan(double x)                 -- Compute tangent of angle in radians.
double tanh(double x)                -- Compute the hyperbolic tangent of x.

Math Constants
The math.h library defines many (often neglected) constants. It is always advisable to use these definitions:

HUGE -- The maximum value of a single-precision floating-point number.
M_E -- The base of natural logarithms (e).
M_LOG2E -- The base-2 logarithm of e.
M_LOG10E - The base-10 logarithm of e.
M_LN2 -- The natural logarithm of 2.
M_LN10 -- The natural logarithm of 10.
M_PI -- pi   i.e.   3.14159...
M_PI_2 -- pi/2.
M_PI_4 -- pi/4.
M_1_PI -- 1/pi.
M_2_PI -- 2/pi.
M_2_SQRTPI -- 2/(sqrt of pi)
M_SQRT2 -- The positive square root of 2.
M_SQRT1_2 -- The positive square root of 1/2.
MAXFLOAT -- The maximum value of a non-infinite single- precision floating
point number.
HUGE_VAL -- positive infinity.

There are also a number a machine dependent values defined in #include <value.h> -- see man value or list value.h for further details.


*******************************************
Random Numbers
*******************************************

To use all functions in this library you must use:
#include <stdlib.h>

Random numbers are useful in programs that need to simulate random events, such as games, simulations and experimentations. In practice no functions produce truly random data -- they produce pseudo-random numbers. These are computed form a given formula (different generators use different formulae) and the number sequences they produce are repeatable. A seed is usually set from which the sequence is generated. Therefore is you set the same seed all the time the same set will be be computed. One common technique to introduce further randomness into a random number generator is to use the time of the day to set the seed, as this will always be changing.  There are many (pseudo) random number functions in the standard library. They all operate on the same basic idea but generate different number sequences (based on different generator functions) over different number ranges.
The simplest set of functions is:
int rand(void);
void srand(unsigned int seed);
\end{vebatim}
{\tt rand()}  returns successive pseudo-random numbers in the range from 0 to (2^15)-1.
{\tt srand()} is used to set the seed. A simple example of using the time of the day to initiate a seed is via the call:
\begin{verbatim}
srand( (unsigned int) time( NULL ));
The following program card.c illustrates the use of these functions to simulate a pack of cards being shuffled:

/*** Use random numbers to shuffle the "cards" in the deck. The second
** argument indicates the number of cards. The first time this
** function is called, srand is called to initialize the random
** number generator.*/
#include <stdlib.h>
#include <time.h>
#define TRUE 1
#define FALSE 0
void shuffle( int *deck, int n_cards )
{
        int i;
        static int first_time = TRUE;
        /*
        ** Seed the random number generator with the current time
        ** of day if we haven't done so yet.
        */
        if( first_time ){
                first_time = FALSE;
                srand( (unsigned int)time( NULL ) );
        }
         /* ** "Shuffle" by interchanging random pairs of cards.
        */
        for( i = n_cards - 1; i > 0; i -= 1 ){
                int where;
                int temp;
                where = rand() % i;
                temp = deck[ where ];
                deck[ where ] = deck[ i ];
                deck[ i ] = temp;
        }
}

Ex2:
  /* Initialize random numbers. Take advantage of the clock to choose a different seed on each run. */
  srand(time(0));

There are several other random number generators available in the standard library:
double drand48(void);
double erand48(unsigned short xsubi[3]);
long lrand48(void);
long nrand48(unsigned short xsubi[3]);
long mrand48(void);
long jrand48(unsigned short xsubi[3]);
void srand48(long seed);
unsigned short *seed48(unsigned short seed[3]);
void lcong48(unsigned short param[7]);
This family of functions generates uniformly distributed pseudo-random numbers.
Functions drand48() and erand48() return non-negative double-precision floating-point values uniformly distributed over the interval [0.0, 1.0).
Functions lrand48() and nrand48() return non-negative long integers uniformly distributed over the interval [0, 2**31).
Functions mrand48() and jrand48() return signed long integers uniformly distributed over the interval [-2**31, 2**31).
Functions srand48(), seed48(), and lcong48() set the seeds for drand48(), lrand48(), or mrand48() and one of these should be called first.


*******************************************
Input and Output (I/O): stdio.h
*******************************************
Your programs will need to include the standard I/O header file so do:
#include <stdio.h>
Reporting Errors
The standard library perror() is an easy to use and convenient fonction useful to report errors in a C program.  It is used in conjunction with errno and frequently on encountering an error you may wish to terminate your
program early.
perror()
The function perror() is prototyped by:
void perror(const char *message);
perror() produces a message (on standard error output), describing the last error encountered, returned to errno (see below) during a call to a system or library function. The argument string message is printed first, then a
colon and a blank, then the message and a newline. If message is a NULL pointer or points to a null string, the colon is not printed.
errno
errno is a special system variable that is set if a system call cannot perform its set task. It is defined in #include <errno.h>.   To use errno in a C program it must be declared via:
extern int errno;
It can be manually reset within a C program (although this is uncommon practice) otherwise it simply retains its last value returned by a system call or library function.
exit()
The function exit() is prototyped in #include <stdlib> by:
void exit(int status)
Exit simply terminates the execution of a program and returns the exit status value to the operating system. The status value is used to indicate if the program has terminated properly:
 - it exist with a EXIT_SUCCESS value on successful termination
 - it exist with a EXIT_FAILURE value on unsuccessful termination.
On encountering an error you may frequently call an exit(EXIT_FAILURE) to terminate an errant program.

!!!!!!!!!!!!need an example look into code or book!!!!!!!!!!!!!!!!!


*******************************************
Streams
*******************************************
Streams are a portable way of reading and writing data. They provide a flexible and efficient means of I/O.
A Stream is a file or a physical device (e.g. printer or monitor) which is manipulated with a pointer to the stream. There exists an internal C data structure, FILE, which represents all streams and is defined in stdio.h. We simply need to refer to the FILE structure in C programs when performing I/O with streams.  We just need to declare a variable or pointer of this type in our programs.  We do not need to know any more specifics about this definition. We must open a stream before doing any I/O, then access it and then close it. Stream I/O is BUFFERED: That is to say a fixed ``chunk''is read from or written to a file via some temporary storage area (the buffer). NOTE the file pointer actually points to this buffer.  This leads to efficient I/O but beware: data written to a buffer does not appear in a file (or device) until the buffer is flushed or written out. (\n does this).
Any abnormal exit of code can cause problems.

Predefined Streams
UNIX defines 3 predefined streams (in stdio.h):
stdin, stdout, stderr
stdin and stdout can be used with files, programs, I/O devices such as keyboard, console, etc.. stderr always goes to the console or screen. The console is the default for stdout and stderr. The keyboard is the default
for stdin. Predefined stream are automatically open.

Redirection
This is how we override the UNIX default predefined I/O defaults. This is not part of C but operating system dependent. We will do redirection from the command line.
> -- redirect stdout to a file.
So if we have a program, out, that usually prints to the screen then 
out > file1 
will send the output to a file, file1.
< -- redirect stdin from a file to a program.
So if we are expecting input from the keyboard for a program, "in" we can read similar input from a file
in < file2.
| -- pipe: puts stdout from one program to stdin of another
prog1 | prog2
e.g. Sent output (usually to console) of a program direct to printer:
out | lpr

<       /* redirects stdin to obtain input from a file */
>       /* redirects stdin to send output to a file */
>prn    /* redirects outputs to printer */
CTRL Z /* end of file */



*******************************************
Files
*******************************************
Files are the most common form of a stream. The first thing we must do is open a file. The function fopen() does this:
FILE *fopen(char *name, char *mode)
fopen returns a pointer to a FILE. The name string is the name of the file on disc that we wish to access. The mode string controls our type of access.  If a file cannot be accessed for any reason a NULL pointer is returned.
Modes include:
``r'' -- read,
``w'' -- write and
``a'' -- append.
To open a file we must have a stream (file pointer) that points to a FILE structure.
So to open a file, called myfile.dat for reading we would do:
  FILE *stream, *fopen();
 /* declare a stream and prototype fopen */
 stream = fopen(``myfile.dat'',``r'');
it is good practice to check if the file is opened correctly:
 if ( (stream = fopen( ``myfile.dat'',``r'')) == NULL)
 {  printf(``Can't open %s\n'', ``myfile.dat'');
  exit(1);
 }
 ...

*******************************************
FILE INPUT/OUTPUT 
*******************************************

OUTPUT TO A FILE 
We begin as before with the include statement for stdio.h, and include the header for the string functions. 
The type FILE is a structure and is defined in the stdio.h file. It is used to define a file pointer for use in file operations. The definition of C requires a pointer to a FILE type to access a file, and as usual, the name can be any valid variable name. Many writers use fp for the name of this first file pointer. 

OPENING A FILE 

Before we can write to a file, we must open it. What this really means is that we must tell the system that we want to write to a file and what the filename is. We do this with the fopen() function. The file pointer, fp in our case, will point to the structure for the file and two arguments are required for this function, the filename first, followed by the file attribute. The filename is any valid filename for your operating system, and can be expressed in upper or lower case letters, or even mixed if you so desire. It is enclosed in double quotes. For this example we have chosen the name TENLINES.TXT. This file should not exist on your disk at this time. If you have a file with this name, you should change its name or move it because when we execute the program, its contents will be overwritten. If you don't have a file by this name, this program will create one and write some data into it. 

Note that we are not forced to use a string constant for the file name. We can use a string variable which contains the filename then use any method we wish to fill in the name of the file
to open. 

READING ("r") 

The second parameter is the file attribute and can be any of three letters, "r", "w", or "a", and must be lower case. There are actually additional attributes available in C to allow more flexible I/O. When an "r" is used, the file is opened for reading, a "w" is used to indicate a file to be used for writing, and an "a" indicates that you desire to append additional data to the data already in an existing file. Opening a file for reading requires that the file already exist. If it does not exist, the file pointer will be set to NULL and can be checked by the program. It is not checked in this program, but could be easily checked as follows. 

     if (fp == NULL) {
        printf("File failed to open\n");
        exit (1);
     } 

Good programming practice would dictate that all file pointers be checked to assure proper file opening in a manner similar to the above code. The value of 1 used as the parameter of exit() will be explained shortly.

WRITING ("w") 

When a file is opened for writing, it will be created if it does not already exist and it will be reset if it does, resulting in deletion of any data already there. If the file fails to open for any reason, a NULL will be returned so the pointer should be tested as above.

APPENDING ("a") 

When a file is opened for appending, it will be created if it does not already exist and it will be initially empty. If it does exist, the data input point will be set to the end of the data already contained in the file so that new data will be added to any data that already exists in the file. Once again, the return value can and should be checked for proper opening. 

OUTPUTTING TO THE FILE 

The job of actually outputting to the file is nearly identical to the outputting we have already done to the standard output device.  The only real differences are the new function names and the addition of the file pointer as one of the function arguments. In the example program, fprintf() replaces our familiar printf() function name, and the file pointer defined earlier is the first argument within the parentheses. The remainder of the statement looks like, and in fact is identical to, the printf() statement. 

CLOSING A FILE 

To close a file, use the function fclose() with the file pointer in the parentheses. Actually,  it is not necessary to close the file because the system will close all open files before returning to the operating system. It would be good programming practice for you to get in the habit of closing all files in spite of the fact that they will be closed automatically, because that would act as a reminder to you of what files are open at the end of each program. 

You can open a file for writing, close it, and reopen it for reading, then close it, and open it again for appending, etc. Each time you open it, you could use the same file pointer, or you could use a different one. The file pointer is simply a tool that you use to point to a file and you decide what file it will point to. 

OUTPUTTING A SINGLE CHARACTER AT A TIME 

The program begins with the include statements, then defines some variables including a file pointer. The file pointer is named point this time, but we could have used any other valid variable name. We then define a string of characters to use in the output function using a strcpy() function. We are ready to open the file for appending and we do so with the fopen() function, except this time we use the lower cases for the filename. This is done simply to illustrate that some operating systems don't care about the case of the filename. Some operating systems, including UNIX, are case sensitive for filenames, so you will need to fix the case before compiling and executing this program. Notice that the file will be opened for appending so we will add to the lines inserted during the last program. If the file could not be opened properly, a NULL value is returned by the fopen() function.

The constant named EXIT_FAILURE is defined in the stdlib.h file and is usually defined to have the value of 1. The constant named EXIT_SUCCESS is also defined in the stdlib.h file and is usually defined to have the value of 0. The operating system can use the returned value to determine if the program operated normally and can take appropriate action if neccessary. For example, if a two part program is to be executed and the first part returns an error indication, there is no need to execute the second part of the program. Your compiler probably executes in several passes with each successive pass depending on successful completion of the previous pass.

THE putc() FUNCTION 

The part of the program we are interested in is the putc() function. It outputs one character at a time, the character being the first argument in the parentheses and the file pointer being the second and last argument. Why the designer of C made the pointer first in the fprintf() function, and last in the putc() function is a good question for which there may be no answer. It seems like this would have been a good place to have used some consistency. 

READING A FILE 

The main body of the program is one do while loop in which a single character is read from the file and output to the monitor until an EOF (end of file) is detected from the input file. The file is then closed and the program is terminated. 

CAUTION CAUTION CAUTION 

At this point, we have the potential for one of the most common and most perplexing problems of programming in C. The variable returned from the getc() function is a character, so we can use a char variable for this purpose. There is a problem that could develop here if we happened to use an unsigned char however, because C returns a minus one for an EOF. An unsigned char type variable is not capable of containing a negative value. An unsigned char type variable can only have the values of zero to 255, so it will return a 255 for a minus one which can never compare to the EOF. This is a very frustrating problem to try to find. The program can never find the EOF and will therefore never terminate the loop. This is easy to prevent. Always use a int type variable when the return can be an EOF, because an int is always signed. According to the ANSI-C standard, a char can be implemented as either a signed or an unsigned type by any particular compiler.

Some compilers use a char type that is not 8 bits long. If your compiler uses other than 8 bits for a char type variable, the same arguments apply. Do not use an unsigned type if you need to check for an EOF returned by the function, because an EOF is usually defined as -1 which cannot be returned in an unsigned type variable.

READING A WORD AT A TIME 

this program uses the fscanf() function to read in a string at a time. Because the fscanf() function
stops reading when it finds a space or a newline character, it will read a word at a time, and display the results one word to a line. First we must examine a programming problem. 

THIS IS A PROBLEM 

Inspection of the program will reveal that when we read data in and detect the EOF, we print out something before we check for the EOF resulting in an extra line of printout. What we usually print out is the same thing printed on the prior pass through the loop because it is still in the buffer named oneword. We therefore must check for EOF before we execute the printf() function.

NOW LET'S FIX THE PROBLEM 

An experienced C programmer would code lines in the following manner;

   while((c = fscanf(fp1, "%s", oneword) != EOF)
   {
      printf("%s\n", oneword);
   }

There is no question that this code is more difficult to read. Even though is is more efficient, it is not clear whether the slight gain in efficiency is worth the reduced readability. If the program saves ten milliseconds when reading in a file once a day, and it takes a programmer an hour longer to make a modification to the code a year after the program is released, there is not much savings in using such code. Even though the time assumptions are all judgement calls in the above text, it is plain to see that there are often tradeoffs
when writing a program. You will make many decisions concerning execution efficiency and readability when you are writing non-trivial programs.

This is a rather contrived example, because most experienced C programmers would not think this code is at all cryptic, but is written in a standard C notation. As you gain experience, you will come to accept this as clearly written C code. The philosophical argument about code complexity and readability has been made however, and should be considered for all software development.

READ A FULL LINE 

We are using fgets() which reads an entire line, including the newline character, into a buffer. The buffer to be read into is the first argument in the function call, and the maximum number of characters to read is the second argument, followed by the file pointer. This function will read characters into the input buffer until it either finds a newline character, or it reads the maximum number of characters allowed minus one. It leaves one character for the end of string null character. In addition, if it finds an EOF, it will return a value of NULL.  NULL is defined as zero in your stdio.h file. 

HOW DO WE PRINT? 

we open PRN for writing. Printing is identical to writing data to a disk file except that we use a standard name for the filename. Many C compilers use the reserved filename of PRN that instructs the compiler to send the output to the printer. There are other names that are used occasionally such as LPT, LPT1, or LPT2.
Check the documentation for your particular compiler. Some of the newest compilers use a predefined file pointer such as stdprn for the print file. Once again, check your documentation. 

The program is simply a loop in which a character is read, and if it is not the EOF, it is displayed and printed. When the EOF is found, the input file and the printer output files are both closed. Note that good programming practice includes checking both file pointers to assure that the files opened properly.

A READING ASSIGNMENT

Spend some time studying the documentation for your compiler and reading about the following functions. You will not understand everything about them but you will get a good idea of how the library functions are documented. 

fopen(), fclose(), putc(), putchar(), printf(), fprintf(), scanf(), fgets()

Also spend some time studying stdio.h, looking for prototypes for the above functions and for the declaration of FILE.



*******************************************
Reading and writing files
*******************************************
The functions fprintf and fscanf a commonly used to access files. int fprintf(FILE *stream, char *format, args..)
int fscanf(FILE *stream, char *format, args..)
These are similar to printf and scanf except that data is read from the stream that must have been opened with fopen(). The stream pointer is automatically incremented with ALL file read/write functions.
  char *string[80]
  FILE *stream, *fopen();
  if ( (stream = fopen(...)) != NULL)
  fscanf(stream,``%s'', string);
Other functions for files:
int getc(FILE *stream), int fgetc(FILE *stream)
int putc(char ch, FILE *s), int fputc(char ch, FILE *s)
These are like getchar, putchar.
getc is defined as preprocessor MACRO in stdio.h. fgetc is a C library
function. Both achieve the same result!!
fflush(FILE *stream) -- flushes a stream.
fclose(FILE *stream) -- closes a stream.
We can access predefined streams with fprintf etc.
fprintf(stderr,``Cannot Compute!!\n'');
fscanf(stdin,``%s'',string);



*******************************************
Stream Status Enquiries 
*******************************************
There are a few useful stream enquiry functions, prototyped as follows:
 int feof(FILE *stream);
 int ferror(FILE *stream);
 void clearerr(FILE *stream);
 int fileno(FILE *stream);
Their use is relatively simple:
feof()
returns true if the stream is currently at the end of the file. So to read a stream, fp, line by line you could do:
while ( !feof(fp) )
  fscanf(fp,"%s",line);
ferror()
reports on the error state of the stream and returns true if an error has occurred.
clearerr()
resets the error indication for a given stream.
fileno()
returns the integer file descriptor associated with the named stream.



*******************************************
Low Level I/O
*******************************************
This form of I/O is UNBUFFERED  each read/write request results in accessing disk (or device) directly to fetch/put a specific number of bytes. There are no formatting facilities -- we are dealing with bytes of information. This means we are now using binary (and not text) files. Instead of file pointers
we use low level file handle or file descriptors which give a unique integer number to identify each file.
To Open a file use:
int open(char *filename, int flag, int perms) -- this returns a file descriptor or -1 for a fail.
The flag controls file access and has the following predefined in fcntl.h:
O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_WRONLY + others see online man pages or reference manuals.
perms -- best set to 0 for most of our applications.
The function:
creat(char *filename, int perms)
can also be used to create a file.
int close(int handle) -- close a file
int read(int handle, char *buffer, unsigned length)
int write(int handle, char *buffer, unsigned length)
are used to read/write a specific number of bytes from/to a file (handle)
stored or to be put in the memory location specified by buffer.
The sizeof() function is commonly used to specify the length.
read and write return the number of bytes read/written or -1 if they fail.
/* program to  read a list of floats from a binary file */
/* first byte of file is an integer saying how many  */
/* floats in file. Floats follow after it, File name got from */
/* command line */
#include<stdio.h>
#include<fcntl.h>
float bigbuff[1000];
main(int argc, char **argv)
{  int fd;
   int bytes_read;
   int file_length;
   if ( (fd = open(argv[1],O_RDONLY)) = -1)
   { /* error file not open */....
     perror("Datafile");
     exit(1);
   }
   if ( (bytes_read = read(fd,&file_length, sizeof(int))) == -1)
   { /* error reading file */...
        exit(1);
   }
   if ( file_length > 999 )  {/* file too big */ ....}
   if ( (bytes_read = read(fd,bigbuff,file_length*sizeof(float))) == -1)
   { /* error reading open */...
        exit(1);
   }
}


*******************************************
File Access and Directory System Calls
*******************************************
There are many UNIX utilities that allow us to manipulate directories and files. cd, ls, rm, cp, mkdir etc. are examples. Similar tasks can be done from within a C program.

Directory handling functions: <unistd.h>
This basically involves calling appropriate functions to traverse a directory hierarchy or inquire about a directories contents.
int chdir(char *path) -- changes directory to specified path string.
Example: C emulation of UNIX's cd command:

#include<stdio.h>
#include<unistd.h>
main(int argc,char **argv)
{
  if (argc < 2)
  {  printf(``Usage: %s <pathname>\n'',argv[0]);
     exit(1);
  }
  if (chdir(argv[1]) != 0)
  { printf(``Error in chdir \n'');
    exit(1);
  }
}
char *getwd(char *path) -- get the full pathname of the current working directory. path is a pointer to a string where the pathname will be returned. getwd returns a pointer to the string or NULL if an error occurs.

Scanning and Sorting Directories: <sys/types.h>,<sys/dir.h>
Two useful functions (On BSD platforms and NOT in multi-threaded application) are available

scandir(char *dirname, struct direct **namelist, int (*select)(), int (*compar)()) -- reads the directory dirname and builds an array of pointers to directory entries or -1 for an error. namelist is a pointer to an array
of structure pointers.   (*select))() is a pointer to a function which is called with a pointer to a directory entry (defined in <sys/types> and should return a non zero value if the directory entry should be included in the array. If this pointer is NULL, then all the directory entries will be included. The last argument is a pointer to a routine which is passed to qsort (see man qsort) -- a built in function which sorts the completed array. If this pointer is NULL, the array is not sorted.

alphasort(struct direct **d1, **d2) -- alphasort() is a built in routine which will sort the array alphabetically.

Example - a simple C version of UNIX ls utility
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/param.h>
#include <stdio.h>
#define FALSE 0
#define TRUE !FALSE
extern  int alphasort();
char pathname[MAXPATHLEN];
main()
{ int count,i;
  struct direct **files;
  int file_select();
  if (getwd(pathname) == NULL )
  { printf("Error getting path \n");
    exit(0);
  }
  printf("Current Working Directory = %s\n",pathname);
  count = scandir(pathname, &files, file_select, alphasort);
  /* If no files found, make a non-selectable menu item */
  if (count <= 0)
  { printf(``No files in this directory \n'');
    exit(0);
  }
  printf(``Number of files = %d \n'',count);
  for (i=1;i<count+1;++i)
  printf(``%s  '',files[i-1]->d_name);
  printf(``\n''); /* flush buffer */
 }
int file_select(struct direct   *entry)
{
  if ((strcmp(entry->d_name, ``.'') == 0) || (strcmp(entry->d_name, ``..'')
== 0))
    return (FALSE);
  else
    return (TRUE);
}
scandir returns the current directory (.) and the directory above this (..) as well as all files so we need to check for these and return FALSE so that they are not included in our list.
Note: scandir and alphasort have definitions in sys/types.h and sys/dir.h.  MAXPATHLEN and getwd definitions in sys/param.h
We can go further than this and search for specific files: Let's write a modified file_select() that only scans for files with a .c, .o or .h suffix:

int file_select(struct direct *entry)
{
 char *ptr;
 char *rindex(char *s, char c);
 if ((strcmp(entry->d_name, ``.'')== 0) || (strcmp(entry->d_name, ``..'') ==
0))
   return (FALSE);
  /* Check for filename extensions */
 ptr = rindex(entry->d_name, '.')
 if ((ptr != NULL) && ((strcmp(ptr, ``.c'') == 0)(strcmp(ptr, ``.h'') ==
0)(strcmp(ptr, ``.o'') == 0) ))
   return (TRUE);
 else
   return(FALSE);
}
NOTE: rindex() is a string handling function that returns a pointer to the last occurrence of character c in string s, or a NULL pointer if c does not occur in the string. (index() is similar function but assigns a pointer to 1st occurrence.)  The function struct direct *readdir(char *dir) also exists in <sys/dir.h>>
to return a given directory dir listing.


*******************************************
File Manipulation Routines: unistd.h, sys/types.h, sys/stat.h
*******************************************
There are many system calls that can be applied directly to files stored in a directory.
File Access
int access(char *path, int mode) -- determine accessibility of file. path points to a path name naming a file. access() checks the named file for accessibility according to mode, defined in #include <unistd.h>:
R_OK
- test for read permission
W_OK
- test for write permission
X_OK
- test for execute or search permission
F_OK
- test whether the directories leading to the file can be searched and the
file exists.
access() returns: 0 on success, -1 on failure and sets errno to indicate the
error. See man pages for list of errors.

*******************************************
errno
*******************************************
errno is a special system variable that is set if a system call cannot perform its set task. To use errno in a C program it must be declared via:
extern int errno;

It can be manually reset within a C program other wise it simply retains its last value.
int chmod(char *path, int mode) change the mode of access of a file. specified by path to the given mode.
chmod() returns 0 on success, -1 on failure and sets errno to indicate the error. Errors are defined in #include <sys/stat.h>
The access mode of a file can be set using predefined macros in sys/stat.h
-- see man pages -- or by setting the mode in  a 3 digit octal number. The rightmost digit specifies owner privileges, middle group privileges and the leftmost other users privileges. For each octal digit think of it a 3 bit binary number. Leftmost bit = read access (on/off) middle is write, right is executable.
So 4 (octal 100) = read only, 2 (010) = write, 6 (110) = read and write, 1 (001) = execute.
so for access mode 600 gives user read and write access others no access. 666 gives everybody read/write access.
NOTE: a UNIX command chmod also exists

*******************************************
File Status
*******************************************
Two useful functions exist to inquire about the files current status. You can find out how large the file is (st_size) when it was created (st_ctime) etc. (see stat structure definition below. The two functions are prototyped in <sys/stat.h>
int stat(char *path, struct stat *buf),
int fstat(int fd, struct stat *buf)
stat() obtains information about the file named by path. Read, write or execute permission of the named file is not required, but all directories listed in the path name leading to the file must be searchable. fstat() obtains the same information about an open file referenced by the argument descriptor, such as would be obtained by an open call (Low level I/O).
stat(), and fstat() return 0 on success, -1 on failure and sets errno to indicate the error. Errors are again defined in #include <sys/stat.h> buf is a pointer to a stat structure into which information is placed
concerning the file. A stat structure is define in #include <sys/types.h>, as follows
struct stat {
          mode_t   st_mode;     /* File mode (type, perms) */
          ino_t    st_ino;      /* Inode number */
          dev_t    st_dev;      /* ID of device containing */
                                /* a directory entry for this file */
          dev_t    st_rdev;     /* ID of device */
                                /* This entry is defined only for */
                                /* char special or block special files */
          nlink_t  st_nlink;    /* Number of links */
          uid_t    st_uid;      /* User ID of the file's owner */
          gid_t    st_gid;      /* Group ID of the file's group */
          off_t    st_size;     /* File size in bytes */
          time_t   st_atime;    /* Time of last access */
          time_t   st_mtime;    /* Time of last data modification */
          time_t   st_ctime;    /* Time of last file status change */
                                /* Times measured in seconds since */
                                /* 00:00:00 UTC, Jan. 1, 1970 */
          long     st_blksize;  /* Preferred I/O block size */
          blkcnt_t st_blocks;   /* Number of 512 byte blocks allocated*/
}
*******************************************
File Manipulation:stdio.h, unistd.h
*******************************************
There are few functions that exist to delete and rename files. Probably the most common way is to use the stdio.h functions:
int remove(const char *path);
int rename(const char *old, const char *new);
Two system calls (defined in unistd.h) which are actually used by remove() and rename() also exist but are probably harder to remember unless you are familiar with UNIX.
int unlink(cons char *path) -- removes the directory entry named by path unlink() returns 0 on success, -1 on failure and sets errno to indicate the error. Errors listed in #include <sys/stat.h>
A similar function link(const char *path1, const char *path2) creates a linking from an existing directory entry path1 to a new entry path2

*******************************************
Creating Temporary Files:<stdio.h>
*******************************************
Programs often need to create files just for the life of the program. Two convenient functions (plus some variants) exist to assist in this task. Management (deletion of files etc) is taken care of by the Operating System.

The function FILE *tmpfile(void) creates a temporary file and opens a corresponding stream. The file will automatically be deleted when all references to the file are closed. The function char *tmpnam(char *s) generate file names that can safely be used for a temporary file. Variant functions char *tmpnam_r(char *s) and char *tempnam(const char *dir, const char *pfx) also exist NOTE: There are a few more file manipulation routines not listed here see man pages.


*******************************************
Time Functions
*******************************************
How to access the clock time with UNIX system calls.
Uses of time functions include:
- telling the time.
- timing programs and functions.
- setting number seeds.

Basic time functions
Some of the basic time functions are prototypes as follows:
time_t time(time_t *tloc) -- returns the time since 00:00:00 GMT, Jan. 1, 1970, measured in seconds.
If tloc is not NULL, the return value is also stored in the location to which tloc points.
time() returns the value of time on success. On failure, it returns (time_t) -1. time_t is typedefed to a long (int) in <sys/types.h> and <sys/time.h> header files.
int ftime(struct timeb *tp) -- fills in a structure pointed to by tp, as defined in <sys/timeb.h>:
   struct timeb
   { time_t time;
     unsigned short millitm;
     short timezone;
     short dstflag;
   };
The structure contains the time since the epoch in seconds, up to 1000 milliseconds of more precise interval, the local time zone (measured in minutes of time westward from Greenwich), and a flag that, if nonzero, indicates that Day light Saving time applies locally during the appropriate part of the year. On success, ftime() returns no useful value. On failure, it returns -1.  Two other functions defined etc. in #include <time.h>
char *ctime(time_t *clock),
char *asctime(struct tm *tm)
ctime() converts a long integer, pointed to by clock, to a 26-character string of the form produced by asctime(). It first breaks down clock to a tm structure by calling localtime(), and then calls asctime() to convert that
tm structure to a string.
asctime() converts a time value contained in a tm structure to a 26-character string of the form:
Sun Sep 16 01:03:52 1973
asctime() returns a pointer to the string.

Example time applications
we mentioned above three possible uses of time functions (there are many more) but these are very common.
Example 1: Time (in seconds) to perform some computation This is a simple program that illustrates that calling the time function at distinct moments and noting the different times is a simple method of timing fragments of code:

/* timer.c */
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
main()
  {  int i;
     time_t t1,t2;
     (void) time(&t1);
     for (i=1;i<=300;++i)
       printf(``%d %d %d\n'',i, i*i, i*i*i);
     (void) time(&t2);
     printf(``\n Time to do 300 squares and cubes= %d seconds\n'', (int)
t2-t1);
  }

Example 2: Set a random number seed
this time we use the lrand48() function to generate of number sequence:

/* random.c */
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
main()
  { int i;
    time_t t1;
    (void) time(&t1);
    srand48((long) t1);
    /* use time in seconds to set seed */
    printf(``5 random numbers (Seed = %d):\n'',(int) t1);
    for (i=0;i<5;++i)
      printf(``%d '', lrand48());
      printf(``\n\n''); /* flush print buffer */
   }
lrand48() returns non-negative long integers uniformly distributed over the interval (0, 2**31).
A similar function drand48() returns double precision numbers in the range [0.0,1.0).
srand48() sets the seed for these random number generators. It is important to have different seeds when we call the functions otherwise the same set of pseudo-random numbers will be generated. time() always provides a unique
seed.


*******************************************
Writing Larger Programs
*******************************************
When writing large programs they should be divided up into modules. These would be separate source files. main() would be in one file, main.c say, the others will contain functions. We can create our own library of functions by writing a suite of subroutines in one (or more) modules. In fact modules can be shared amongst many programs by simply including the modules at compilation. There are many advantages to this approach:
- the modules will naturally divide into common groups of functions.
- we can compile each module separately and link in compiled modules.
- UNIX utilities such as make help us maintain large systems.


A full listing example could included main.c, WriteMyString.c and header.h as follows:
main.c:
/*
 *      main.c
 */
#include "header.h"
#include <stdio.h>
char    *AnotherString = "Hello Everyone";
main()
{
  printf("Running...\n");
  /*
   *    Call WriteMyString() - defined in another file
   */
  WriteMyString(MY_STRING);
  printf("Finished.\n");
}

WriteMyString.c:
/*
 *      WriteMyString.c
 */
extern char     *AnotherString;
void WriteMyString(ThisString)
char    *ThisString;
{
        printf("%s\n", ThisString);
        printf("Global Variable = %s\n", AnotherString);
}

header.h:
/*
 *      header.h
 */
#define MY_STRING "Hello World"
void WriteMyString();

We would usually compile each module separately. Some modules have a #include ``header.h'' that share common definitions. Some, like main.c, also include standard header files also. main calls the function WriteMyString() which is in WriteMyString.c module. The function prototype void for WriteMyString is defined in Header.h NOTE that in general we must resolve a tradeoff between having a desire for each .c module to have access to the information it needs solely for its job and the practical reality of maintaining lots of header files.
Up to some moderate program size it is probably best to one or two header files that share more than one modules definitions.  One problem left with module approach:
SHARING VARIABLES
If we have global variables declared and instantiated in one module how can we pass knowledge of this to other modules.  We could pass values as parameters to functions, BUT:
- this can be laborious if we pass the same parameters to many functions and / or if there are long argument lists involved.
- very large arrays and structures are difficult to store locally -- memory problems with stack.

External variables and functions
``Internal'' implies arguments and functions are defined inside functions -- Local
``External'' variables are defined outside of functions -- they are potentially available to the whole program (Global)  but NOT necessarily.
External variables are always permanent.
NOTE: That in C, all function definitions are external. We CANNOT have embedded function declarations like in PASCAL.

Scope of externals
An external variable (or function) is not always totally global.
C applies the following rule:
The scope of an external variable (or function) begins at its point of declaration and lasts to the end of the file (module) it is declared in.
Consider the following:

main()
 { .... }
int what_scope;
float end_of_scope[10]
void what_global()
 { .... }
char alone;
float fn()
 { .... }
main cannot see what_scope or end_of_scope but the functions what_global and fn can. ONLY fn can see alone. This is also one of the reasons why we should prototype functions before the body of code etc. is given. So here main will not know anything about the functions what_global and fn. what_global does not know about fn but fn knows about what_global since it is declared above.
NOTE: The other reason we prototype functions is that some checking can be done the parameters passed to functions.
If we need to refer to an external variable before it is declared or if it is defined in another module we must declare it as an extern variable. e.g. extern int what_global. So returning to the modular example. We have a global string AnotherString declared in main.c and shared with WriteMyString.c where it is declared extern.
BEWARE the extern prefix is a declaration NOT a definition. i.e NO STORAGE is set aside in memory for an extern variable -- it is just an announcement of the property of a variable.   The actual variable must only be defined once in the whole program -- you can have as many extern declarations as needed.  Array sizes must obviously be given with declarations but are not needed with extern declarations. e.g.:
main.c: int arr[100]:
file.c: extern int arr[];

Advantages of Using Several Files
The main advantages of spreading a program across several files are:
- Teams of programmers can work on programs. Each programmer works on a different file.
- An object oriented style can be used. Each file defines a particular type of object as a datatype and operations on that object as functions. The implementation of the object can be kept private from the rest of the
program. This makes for well structured programs which are easy to maintain.
- Files can contain all functions from a related group. For Example all matrix operations. These can then be accessed like a function library.
- Well implemented objects or function definitions can be re-used in other programs, reducing development time.
- In very large programs each major function can occupy a file to itself.  Any lower level functions used to implement them can be kept in the same file. Then programmers who call the major function need not be distracted by all the lower level work.
- When changes are made to a file, only that file need be re-compiled to rebuild the program. The UNIX make facility is very useful for rebuilding multi-file programs in this way.

How to Divide a Program between Several Files
Where a function is spread over several files, each file will contain one or more functions. One file will include main while the others will contain functions which are called by others. These other files can be treated as a library of functions.
Programmers usually start designing a program by dividing the problem into easily managed sections. Each of these sections might be implemented as one or more functions. All functions from each section will usually live in a
single file.  Where objects are implemented as data structures, it is usual to to keep all functions which access that object in the same file. The advantages of this are:
- The object can easily be re-used in other programs.
- All related functions are stored together.
- Later changes to the object require only one file to be modified. Where the file contains the definition of an object, or functions which return values, there is a further restriction on calling these functions from another file. Unless functions in another file are told about the object or function definitions, they will be unable to compile them correctly.
The best solution to this problem is to write a header file for each of the C files. This will have the same name as the C file, but ending in .h. The header file contains definitions of all the functions used in the C file.
Whenever a function in another file calls a function from our C file, it can define the function by making a #include of the appropriate .h file.

Organisation of Data in each File
Any file must have its data organised in a certain order. This will typically be:
- A preamble consisting of #defined constants, #included header files and typedefs of important datatypes.
- Declaration of global and external variables. Global variables may also be initialised here.
- One or more functions.
The order of items is important, since every object must be defined before it can be used. Functions which return values must be defined before they are called. This definition might be one of the following:
- Where the function is defined and called in the same file, a full declaration of the function can be placed ahead of any call to the function.
- If the function is called from a file where it is not defined, a prototype should appear before the call to the function.
A function defined as   

float find_max(float a, float b, float c)
  {  /* etc ... ... */
would have a prototype of
  float find_max(float a, float b, float c);
The prototype may occur among the global variables at the start of the source file. Alternatively it may be declared in a header file which is read in using a #include.
It is important to remember that all C objects should be declared before use.


*******************************************
The Make Utility
*******************************************
The make utility is an intelligent program manager that maintains integrity of a collection of program modules, a collection of programs or a complete system -- It does not have to be managing programs, in practice it can be
any system of files ( e.g. chapters of text in book being typeset). Its main use has been in assisting the development of software systems. Make was originally developed on UNIX but it is now available on most systems.
NOTE: Make is a programmers utility not part of C language or any language for that matter. Consider the problem of maintaining a large collection of source files:
main.c f1.c ......... fn.c
We would normally compile our system via:
cc -o main main.c f1.c ......... fn.c
However, if we know that some files have been compiled previously and their sources have not changed since then we could try and save overall compilation time by linking in the object code from those files say:
cc -o main main.c f1.c ... fi.o .. fj.o ... fn.c
We can use the C compiler option -c to create a .o for a given module. For example:
cc -c main.c
will create a main.o file. We do not need to supply any library links here as these are resolved at the linking stage of compilation. We have a problem in compiling the whole program in this long hand way however,  It is time consuming to compile a .c module -- if the module has been compiled before and not been altered there is no need to recompiled it. We can just link the object files in. However, it will not be easy to remember which files are in fact up to date. If we link in an old object file our final executable program will be wrong.  It is error prone and laborious to type a long compile sequence on the command line. There may be many of our own files to link as well as many system library files. It may be very hard to remember the correct sequence.  Also if we make a slight change to our system editing command line can be error prone. If we use the make utility all this control is taken care by make. In general only modules that have older object files than source files will be recompiled.

*******************************************
Make Programming
*******************************************
Make programming is fairly straightforward. Basically, we write a sequence of commands which describes how our program (or system of programs) can be constructed from source files.  The construction sequence is described in
makefiles which contain dependency rules and construction rules.  A dependency rule has two parts - a left and right side separated by a : (colon) left side : right side
The left side gives the names of a target(s) (the names of the program or system files) to be built, whilst the right side gives names of files on which the target depends (eg. source files, header files, data files)
If the target is out of date with respect to the constituent parts, construction rules following the dependency rules are obeyed.  So for a typical C program, when a make file is run the following tasks are performed:
1.
The makefile is read. Makefile says which object and library files need to be linked and which header files and sources have to be compiled to create each object file.
2.
Time and date of each object file are checked against source and header files it depends on. If any source, header file later than object file then files have been altered since last compilation THEREFORE recompile object
file(s).
3.
Once all object files have been checked the time and date of all object files are checked against executable files. If any later object files will be recompiled.
NOTE: Make files can obey any commands we type from command line. Therefore we can use makefiles to do more than just compile a system source module.  For example, we could make backups of files, run programs if data files have been changed or clean up directories.

Creating a makefile
This is fairly simple: just create a text file using any text editor. The makefile just contains a list of file dependencies and commands needed to satisfy them.
Lets look at an example makefile:

prog: prog.o f1.o f2.o
  c89 prog.o f1.o f2.o -lm etc.

prog.o: header.h prog.c
                 c89 -c prog.c

f1.o: header.h f1.c
                 c89 -c f1.c

f2.o: ---
      ---

Make would interpret the file as follows:
1.
prog depends on 3 files: prog.o, f1.o and f2.o. If any of the object files have been changed since last compilation the files must be relinked.
2.
prog.o depends on 2 files. If these have been changed prog.o must be recompiled. Similarly for f1.o and f2.o.
The last 3 commands in the makefile are called explicit rules -- since the files in commands are listed by name.
We can use implicit rules in our makefile which let us generalise our rules and save typing.
We can take

f1.o: f1.c
  cc -c f1.c
f2.o: f2.c
  cc -c f2.c

and generalise to this:
..c.o: cc -c $<

We read this as .source_extension.target_extension: command $< is shorthand for file name with .c extension.
We can put comments in a makefile by using the # symbol. All characters following # on line are ignored. Make has many built in commands similar to or actual UNIX commands. Here are a few:

break
date
mkdir
> type
chdir
mv (move or rename)
cd
rm (remove)
ls
cp (copy)
path

There are many more see manual pages for make (online and printed reference)

Make macros
We can define macros in make -- they are typically used to store source file names, object file names, compiler options and library links.  They are simple to define, e.g.:

SOURCES          = main.c f1.c f2.c
CFLAGS           = -g -C
LIBS             = -lm
PROGRAM          = main
OBJECTS          = (SOURCES: .c = .o)
where (SOURCES: .c = .o) makes .c extensions of SOURCES .o extensions.
To reference or invoke a macro in make do $(macro_name).e.g.:

$(PROGRAM) : $(OBJECTS)
$(LINK.C) -o $@ $(OBJECTS) $(LIBS)
NOTE:
- $(PROGRAM) : $(OBJECTS) - makes a list of
- dependencies and targets.
- The use of an internal macros i.e. $@.
There are many internal macros (see manual pages) here a few common ones:
$*   -- file name part of current dependent (minus .suffix).
$@   -- full target name of current target.
$<   -- .c file of target.

An example makefile for the WriteMyString modular program discussed in the above is as follows:
#
# Makefile
#
SOURCES.c= main.c WriteMyString.c
INCLUDES=
CFLAGS=
SLIBS=
PROGRAM= main

OBJECTS= $(SOURCES.c:.c=.o)
..KEEP_STATE:
debug := CFLAGS= -g
all debug: $(PROGRAM)
$(PROGRAM): $(INCLUDES) $(OBJECTS)
        $(LINK.c) -o $@ $(OBJECTS) $(SLIBS)
clean:
        rm -f $(PROGRAM) $(OBJECTS)
Running Make
Simply type make from command line.  UNIX automatically looks for a file called Makefile (note: capital M rest
lower case letters). So if we have a file called Makefile and we type make from command line. The Makefile in our current directory will get executed. We can override this search for a file by typing make -f make_filename
e.g. make -f my_make There are a few more -options for makefiles -- see manual pages.



make [-f makefile] [-eiknpqrst] [names]

make allows the programmer to maintain, update, and regenerate groups of computer programs. make executes commands in makefile to update one or more target names (names  are  typically  programs).  If the -f option is not present, then makefile, Makefile, and the Source Code Control System (SCCS)files s.makefile, and s.Makefile are tried in order. If makefile is -, the standard input is taken.  More than one -f makefile argument pair may
appear. make updates a target only if its dependents are newer than the target.  All prerequisite files of a target are added recursively to the list of targets.  Missing files are deemed to be outdated.

Creating the makefile
  The makefile invoked with the -f option is a carefully structured file of explicit instructions for updating and regenerating programs, and contains a sequence of entries that specify dependencies.  The first line of an entry is a blank-separated, non-null list of targets, then a :, then a (possibly null) list of prerequisite files or dependencies. Text following a ; and all following lines that begin with a tab are shell commands to be executed to update the target. The first non-empty line that does not begin with a tab or # begins a new dependency or macro definition.  Shell commands may be continued across lines with a  backslash-new-line (\ new-line) sequence.
Everything printed by make (except the initial tab) is passed directly to the shell as is.  Thus,
               echo a\
               b
          will produce
               ab
exactly the same as the shell would.

 The following makefile says that pgm depends on two files a.o and b.o, and that they in turn depend on  their corresponding source files (a.c and b.c) and a common file incl.h:
               pgm: a.o b.o
                    cc a.o b.o -o pgm
               a.o: incl.h a.c
                    cc -c a.c
               b.o: incl.h b.c
                    cc -c b.c
Command lines are executed one at a time, each by its own shell.   The SHELL environment variable can be  used to specify which shell make should use to execute commands. The default is /usr/bin/sh.
Include Files
  If the string include appears as the first seven letters of a line in a makefile, and is followed by a blank or a tab, the rest of the line is assumed to be a filename and will be read by the current invocation, after
substituting for any macros.

Macros
  Entries of the form string1 = string2 are macro definitions.

Internal Macros
  There are five internally maintained macros that are useful for writing rules for building targets.

  $*   The macro $* stands for the filename part of the current dependent with the suffix deleted.  It is evaluated only for inference rules.

  $@   The $@ macro stands for the full target name of the current target. It is evaluated only for explicitly named dependencies.

  $<   The $< macro is only evaluated for inference rules or the .DEFAULT rule.  It is the module that is outdated with respect to the target (the ``manufactured'' dependent  file  name).  Thus, in the .c.o rule, the $<
macro would evaluate to the .c file.  An example for making optimized .o files from .c files is:
                    .c.o:
                         cc -c -O $*.c
               or:
                    .c.o:
                         cc -c -O $<
  $?   The $? macro is evaluated when explicit rules from the makefile are evaluated.  It is the list of prerequisites that are outdated with respect to the target, and essentially those modules that must be rebuilt.

  $%   The $% macro is only evaluated when the target is an archive library member of the form lib(file.o).  In this case, $@ evaluates to lib and $% evaluates to the library member, file.o.

Four of the five macros can have alternative forms.  When an upper case D or F is appended to any of the four macros, the meaning is changed to ``directory part'' for D and ``file part'' for F.  Thus, $(@D) refers to the
directory part of  the string $@. If there is no directory part,  ./  is generated. The only macro excluded from this alternative form is $?.

  Suffixes
Certain names (for instance, those ending with .o) have inferable prerequisites such as .c, .s, etc.  If no update commands for such a file appear in  makefile, and if an inferable prerequisite exists, that prerequisite is compiled to make the target.  In this case, make has inference rules that allow building files from other files by examining the suffixes and determining an appropriate inference rule to use.  The current
default inference rules are:
..c     .c~      .f     .f~    .s       .s~     .sh      .sh~   .C     .C~
~      .c.a   .c.o   .c~.a  .c~.c  .c~.o    .f.a   .f.o   .f~.a    .f~.f
..f~     ~.o     .h~.h  .l.c   .l.o   .l~.c  .l~.l  .l~.o    .s.a   .s.o
..s~.a  .s~   ~.o       .s~.s   .sh~.sh  .y.c   .y.o   .y~.c  .y~.o  .y~.y
..C.a   .C.o    .C~   ~.a       .C~.C  .C~.o  .L.C     .L.o    .L~.C    .L~.L
..L~.o  .Y.C   .Y.o   .Y~   ~.C     .Y~.o  .Y~.Y

 A tilde in the above rules refers to an SCCS file [see sccsfile(4)].  Thus, the rule .c~.o would transform an SCCS C source file into an object file (.o).  Because the s. of the SCCS files is a prefix, it is incompatible with the make suffix point of view.  Hence, the tilde is a way of changing any file reference into an SCCS file reference.
A rule with only one suffix (for  example,  .c:) is the definition of how to build x from x.c.  In effect, the other suffix is null. This feature is useful for building targets from only one source file, for example, shell
procedures and simple C programs.
 Libraries
If a target or dependency name contains parentheses, it is assumed to be an archive library, the string  within parentheses referring to a member within the library.  Thus, lib(file.o) and $(LIB)(file.o) both refer to an
archive library that contains file.o. (This example assumes the LIB macro has been previously defined.) The expression $(LIB)(file1.o file2.o) is not legal.  Rules pertaining to archive libraries have the form .XX.a where the XX is the suffix from which the archive member is to be made. An unfortunate by-product of the current implementation requires the XX to be different from the suffix of the archive member. Thus, one cannot have
lib(file.o) depend upon file.o explicitly.  The most common use of the archive interface follows.  Here, we assume the source files are all C type source:

               lib: lib(file1.o) lib(file2.o) lib(file3.o)
                    @echo lib is now up-to-date
               .c.a:
                    $(CC) -c $(CFLAGS) $<
                    $(AR) $(ARFLAGS) $@ $*.o
                    rm -f $*.o



----------C on UNIX------------------

NCR C/C++ compiler   --  The ``NCR Unix SVR4 MP-RAS High Performance C/C++ Compiler Programmers Guide'' Document number BD10-2613-D

The following command compiles the program in file sort.c, links it, and generates a load module named sort:

cc -o sort sort.c

Other examples:
        cc -g hello.c                   /* compiles and provides better
error info */
        cc hello.c -o exec_filename     /* compiles and places output file
in exec_filename */
        cc -Hansi hello.c               /* compiles and makes sure that the source code is ANSI compliant */

The cc command accepts several types of files as arguments.  Files whose names end with .c are taken to be C source files and may be preprocessed, compiled, optimized, amended with profiling  code, assembled, and link
edited.  Files whose names end with .C, .cc, or .cpp are taken to be C++ source files and  may be operated on in the same ways.  The compilation process may be stopped after the completion  of any pass if the appropriate
options are supplied.  If the compilation process runs through the assembler, then  a relocatable object file is produced whose name is (by default) that of the source file with .o substituted for .c. However, the .o file is normally deleted if a single C or C++ file is compiled and then immediately link edited to produce an executable. In the same way, files whose names end in .s are taken to be assembly source files; they may be assembled and link edited.
Files whose names end in .i and .ii are taken to be preprocessed C and C++ source files, and they  may be compiled, optimized, amended with profiling code, assembled, and link edited.  Files whose names do not end  in  .c, ..cc, .cpp, .C, .s, .i, or .ii are passed to the link editor, which produces an executable whose name by default is a.out

-Hansi
 Cause the compiler to only accept programs that strictly conform to the ANSI C standard.  It is recommended that the -Xc option be used in place of -Hansi (see  below). This flag has no effect when C++ source files are being
compiled.  (High  Performance C/C++ only)
-g
 Cause the compiler to generate additional information needed for the use of sdb, gdb, debug, or other debuggers.  Unless -O is also specified, -g  turns off several optimizations that the  compiler  otherwise performs to maximize object to source  code  mapping, which  makes debugging  more  reliable. Debugging  a program compiled with both the -g and -O options is not recommended unless the user understands the behavior of optimizations and
the impact on debugging.
-o path_name
Produce an executable output file path_name, instead of the default a.out.  High Performance C also adds the ability to specify the file name for unlinked relocatable objects  (-c -o name), or an assembler files (-s -o
name).
-c
Suppress the link editing phase of the compilation and do not remove any produced object files.
-S
Compile, optimize, but do not assemble or link edit the named C files.  The assembler-language output is left in corresponding files suffixed with .s.
-v
Cause the compiler to do stricter semantic checking, and enable lint-like checks on the named C files.  The results are more detailed warning diagnostics and error checks  similar to the lint(1) output for a file,
which may help to identify errors in a program. 
-A-  Cause all predefined macros (other than those that begin   with   __) and predefined assertions to be forgotten.

FILES
          file.c                C source file
          file.i                preprocessed C source file
          file.o                object file
          file.s                assembly language file
          a.out                 link-edited default output



lint [options] files
Ex: lint hello.c

lint detects features of C program files which are likely to be bugs, non-portable, or wasteful.  It also checks type usage more strictly than the compiler. lint issues error and  warning messages.

