7.8. C

7.8. THE C LANGUAGE

7.8.1. INTRODUCTION TO C

This chapter follows the ANSI - C standard. Following this standard should allow C code to be portable to many machines, but, not all.

7.8.1.1. GETTING STARTED

	A first C Program 

#include <stdio.h>

main()

{

printf("Hello, world!\n");

return 0;

}

7.8.1.1.1. INCLUDE FILES

Several library functions require certain definitions be included in the file for them to compile properly. These files are defined in some standard include files and can be included with a user's program. To include these files use a line like:

#include <stdio.h>

The less than (<) and greater than (>) symbols indicate that the include file is in the standard library directory. The file indicated (in this case stdio.h) is inserted into the file by the C preprocessor when the program is compiled.

It is also good practise to put any macro definitions, function header prototypes, and struct templates in include files. These are included in a program by using a line like:

#include "myfile.h"

The quotation marks (") indicate that the file is in the user's current directory. These include files should not contain any executable C code. A user's include file can include other include files, from their own directory or the standard library.

7.8.1.1.2. COMPILING SEPARATE FILES

Large programs are best maintained in separate files. When different functions are defined in separate files each file can be compiled separately and linked together to form the program.

Separate files give the advantage that when one file is changed the program can be recreated faster because only the changed file has to be recompiled. Functions that are in their own files are also easier to reuse on other projects since the file need only be linked instead of having to extract the function and any global information from a large file.

7.8.1.1.3. #DEFINE MACROS

C uses a preprocessor (cpp on Unix systems) to perform macro substitutions just prior to compiling programs. These macros can be used to abstract constants and common C statements. These macros can also be used to "hide" the C code. The former is strongly encouraged while the latter is strongly discouraged.

Examples:

#define MAX 512 This is useful because if you want to change to value of MAX it only has to be changed once.

#define SWAP(a,b) {int temp; temp=a;a=b;b=temp}

This example simplifies five statements of C code:

{

int temp;

temp = x;

x = y;

y = temp;

}

To one line SWAP (x,y);

For a more complete description see one of the books listed in the reference section.

NOTE: To link C programs on Meena:

Meena does not automatically include the libraries necessary to link C programs. The following lines can either be added to your login.com file or can be typed at the command line before compiling.

$ define lnk$library sys$library:vaxccurse.olb screen management

$ define lnk$library_1 sys$library:vaxcrtlg.olb floating point instruction.

$ define lnk$library_2 sys$library:vaxcrtl.olb regular C library.

7.8.1.2. OPERATORS

7.8.1.2.1. ARITHMETIC OPERATORS
+          addition                      
-          subtraction                   
/          division                      
*          multiplication                
%          modulus                       
++         increment (++i => i+1)        
--         decrement (i-- => i-1)        

Example:

#include <stdio.h>

int main(void)

{

int c,d,a=6,b=6;

c = (a++); [a will be incremented after the assignment]

d = (++b); [b will be incremented before the assignment]

printf("c = %d, d = %d\n", c, d);

}

Output:

c = 6, d = 7

7.8.1.2.2. COMPARISON

These operators are for performing comparisons; they return either a TRUE (non zero) or a FALSE (zero).

==       equal                              
!=       not equal                          
<        less than                          
<=       less than or equal                 
>        greater than                       
>=       greater than or equal              
||       logical inclusive OR operator      
&&       logical inclusive AND operator     

7.8.1.2.3. LOGICAL

The logical operators perform operations on each bit in the operands and return the result.

|        bit wise inclusive OR operator     
&        bit wise inclusive AND operator    
^        bitwise exclusive OR operator      

Example

510 | 1210 = 01012 | 11002 = 11012 = 1310

510 | | 410 = 01012 | | 01002 = TRUE

{nonzero}||{nonzero} = TRUE

7.8.1.2.4. ASSIGNMENT

These operators are used to assign the value on the right side of the operator to the left side. C provides some operators that allow arithmetic operations to be incorporated into an assignment.

symbol     operation        example   equivalent  
=          equal            a = 1     a = 1       
+=         increment by     a += 12   a = a+12    
-=         decrement by     a -= 5    a = a-5     
/=         divide by        a/ = 6    a = a/6     
*=         multiply by      a *= 4    a = a*4     
%=         modulus by       a %= 7    a = a%7     
<<=        shift left by    a << 4    a = a<<4    
>>=        shift right by   a >> 4    a = a>>4    
&=         and with         a &= 4    a = a&4     
^=         exclusive or     a^= 4     a = a^4     
           with                                   
|=         inclusive or     a |= 4    a = a|4     
           with                                   

NOTE: Assignment and comparison operators are not interchangeable,

e.g.: a = b is not the same as a == b

7.8.1.2.5. SHIFT OPERATORS
<<       bit wise shift left      
>>       bit wise shift right     

Example:

a = 1 << 4 gives 16

ie: 00012 << 01002 gives 10002

7.8.1.2.6. UNARY OPERATORS
* value at address (pointer) & address of variable

example:

#include <stdio.h>

int main(void)

{

char string[10]; [string is a pointer to ten bytes of storage]

strcpy(string, "Hello");

printf("The string contains: %s\n",string);

*(string+2) = 'x'; [the third element of the string is changed]

[NOTE: This is the same as: string[2]='x';]

printf("The string now contains: %s\n",string);

return 0;

}

Output:

The string contains: Hello

The string now contains: Hexlo

Example 2:

#include <stdio.h>

int main(void)

{

char letter='a'; [letter has the ascii value of the character a]

char *str1;

str1 = &letter;

printf("This is a letter: [%c] at address: %d\n", *str1, str1);

return 0;

}

Output:

This is a letter: [a] at address: 20056

Example 3:

#include <stdio.h>

int main(void)

{

int number;

printf("Please enter a number\n");

scanf("%d", &number); [Scanf requires an address (pointer)]

printf("You typed %d for a number\n", number);

[printf requires a value]

return 0;

}

7.8.1.2.7. CONDITIONAL OPERATOR

exp1 ?exp2 : exp3

Example:

#include <stdio.h>

int main(void)

{

int c,d,a=6,b=8;

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

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

printf("c = %d,d = %d\n",c,d);

return 0;

}

Output:

c = 8,d = 6

7.8.1.2.8. OPERATOR EVALUATION ORDER

C evaluates expressions depending on their precedence and their associativity. The following table shows the C operators in order of precedences from highest [() [] -> .] to lowest and their associativity. Use simple expressions or parentheses to avoid complicated expressions that rely on precedence and associativity. This will prevent errors and confusion.

Operator                                Associativity      
() [] -> .                              left to right      
! ~ ++ -- - (type) * & sizeof           right to left      
* / %                                   left to right      
+ -                                     left to right      
<< >>                                   left to right      
< <= > >=                               left to right      
== !=                                   left to right      
&                                       left to right      
^                                       left to right      
|                                       left to right      
&&                                      left to right      
||                                      left to right      
?:                                      right to left      
= += -= etc.                            right to left      
,                                       left to right      

Example:

a = (16 + 8*7)/6 + 3

a = (16 + 56)/6 + 3

a = (72)/6 + 3

a = 12 + 3

a = 15

Note: The highest precedent operator, the parentheses, is evaluated first, then the highest operator within the parentheses and so on. The final operator, the assignment, is performed right to left.

7.8.1.3. DATA TYPES

Storage types                                          
int                  integer                           
short int            smallest range of integer         
long int             double precision integer          
unsigned int         non-negative integer              
float                floating point                    
double               double precision floating point   
char                 character                         
unsigned char                                          
void                 does not return a value           
Storage classes                                        
register             use a register instead of memory  
extern               reference to a global variable    
static               causes a variable to exist for    
                     the duration of a programs        
                     execution                         

Ex:

register int a; A register is allocated for the variable a

static char flag; The variable flag will exist as long as the program is running.

7.8.1.3.1. VARIABLE SCOPE

The scope of a variable is determined by where it is defined. A variable can be global, so that any function can access it. There are also several variations of local variables.

Example:

	[These variables will be accessible to all functions in this file]

int a;

extern int b; [This variable is defined in another file.]

[i.e.: no storage is allocated]

int main(int argc, char *argv[])

{

int b; This variable can only be used with in main()

.

.

.

while(b != 0)

{

int c; This variable can only be used within this block.

. . . i.e.: between the two braces.

}

return 0;

}

7.8.1.4. ENUMERATION

Enumeration allows symbolic names to be used when a variable is restricted to a value from a small set.

Example:  	enum boolean {false, true};

enum boolean completed;

. . .

completed = false;

while (completed == false)

{

. . .

if( . . . ) completed = true;

}

Example 2: enum color {red, brown, green, blue};

enum color BoatColor, CarColor;

CarColor = blue;

Each item in the list is equivalent to an integer. Normally the values start at zero and increase by one; ie: in the previous example red = 0, brown = 1, green = 2, and blue = 3,. If these variables are printed, their integer value would be printed.

7.8.1.5. DEFINING DATA TYPES

The C language provides the typedef command to name new data types created from the existing one.

Example 1: typedef int BOOLEAN;

BOOLEAN myflag, done, return_code;

myflag = (BOOLEAN) 27;

Example 2: typedef enum

{ red, orange, yellow, green, blue,

violet, indigo, pink

} COLOR;

COLOR CarColor = blue;

Example 3: typedef struct

{

int a;

char flag;

}NODE;

NODE *example;

Typedef is commonly used to define more complicated data types using structures, unions, or pointers.

7.8.1.6. CONTROL STRUCTURES

Definition: A block of code is a collection of valid C statements surrounded by braces. A compound statement is a block of code and can be used anywhere a simple statement can be used:

example:

{

printf ("hello world\n");

a = b / 6;

}

7.8.1.6.1. IF
 

Format:

if (expression)

Statement

[else

Statement ]

The code following an if statement is only executed if the expression is true.

Example:

if (flag_a == 10) <-[note that there is no semicolon]

{

printf("resetting flag a\n");

flag_a = 0;

}

else

flag_a++;

C stops evaluating conditional expressions as soon as any further evaluation is redundant. The order of evaluation of an expression depends on its associativity.

Example:

int vec[MAX_SIZE];

. . .

i = MAX_SIZE;

[first] [second]

if (i < MAX_SIZE && vec[i] != key)

[vec[i] is outside of the allocated memory area]

. . .

If i < MAX_SIZE evaluates to be false then vec[i]!=key will not be evaluated. This is important because vec is allocated only MAX_SIZE elements, and if i is not less than MAX_SIZE then an error would result if vec[i] is accessed. The given condition avoids this problem.

7.8.1.6.2. WHILE

	while(expression)

Statement

A while loop is executed while the expression is true.

7.8.1.6.3. FOR

Format:

for(initalizor; expression; incrementor)

Statement

This is equivalent to:

	

initalizor

while(expression)

{

statement

incrementor

}

example:

	for(a = 0,b = 0; b < 6 && a > 0; a++,i++)

{ This loop will execute as long as b is less than 6

. . . and a is greater than 0. a and i will be incremented

} each time through the loop.

Note: it is a good idea to initialize variables close to the place they are used (ie: initialize a and b at the start of the loop they are used in). This allows the code segment to be moved more easily.

7.8.1.6.4. SWITCH

switch ( char_or_int )

{

case constant_expression_1:

Statement

case constant_expression_2:

Statement

. . .

case constant_expression_n:

Statement

default: [Default is optional]

Statement

}

Execution of each case will continue into the next case unless an exit, break or return is encountered.

Example:

switch(c)

{

case 'o':

oflag = TRUE;

break; [This will prevent this case from]

[running into the next]

case 'P': [These two cases will give the same result]

case 'p':

pflag = TRUE;

break;

case 'r':

rflag = TRUE;

break;

default :

(void) fprintf(stderr,"Unknown option\n");

exit(2);

}

7.8.1.7. OTHER C STATEMENTS

7.8.1.7.1. BREAK

The break statement causes execution of the current loop or switch structure to be terminated. Execution continues after the end of the loop or switch statement.

while(...)

{

. . .

break;

}

. . . [Execution will continue here after the break]

7.8.1.7.2. CONTINUE

The continue statement forces the next iteration of the current loop.

Examples:

	

while (. . . ) for ( . . . )

{ {

. . . . . .

continue; continue;

. . . . . .

[execution continues from here]

} }

NOTE: Structured programming dictates that there should be one entry point and one exit point. Therefore, where possible the use of break and continue should be avoided.

7.8.1.7.3. RETURN

The return statement returns execution to the calling function (or the operating system if in main() ). A value can be returned. The type of value returned by a function is defined in the function's prototype. For example: char *func() returns a pointer to a character. If the function is not typed then it can only return int.

Example:

return; [the return value is undefined]

return a; [the value of a is returned]

return(a); [the value of a is returned]

7.8.2. C FUNCTIONS

7.8.2.1. I/O

FILE *fopen( char *filename, char *type)

fopen opens the file filename and returns a pointer to a FILE structure associated with it. Type refers to the type of actions allowed on the file.

Mode          operation           
"r"           read                
"w"           write               
"a"           append              

int fclose( FILE *stream)

fclose closes the file associated with stream. It is a good idea to close files that you have finished with since there is a limit to the number of files that can be kept open at one time.

7.8.2.1.1. BASIC I/O

char *gets(char *s)

gets reads a string into s from the standard input stream stdin. gets reads up to a newline character, and replaces the newline by a null character. gets returns its argument. For example:

gets(msg);

char *fgets(char *s, int n, FILE *stream)

fgets reads n - 1 characters, or up to a newline character, whichever comes first, from the stream into the strings. The last character read into s is followed by a null character. fgets returns its first argument. Newline characters are not replaced by null characters. For example:

fgets(msg, strlen(string)+1, stream);

int getc(FILE *stream)

getc returns the next character from the named input stream. For example:

ch = getc(stdin);

int fgetc(FILE *stream)

fgetc behaves like getc, but is a genuine function, not a macro; it may be used to save object text. For example:

ch = fgetc(stream);

int getchar()

getchar() is identical to getc(stdin). For example:

ch = getchar();

puts(char *s)

puts writes the null-terminated string s to the standard output stream stdout and appends a newline character. It does not write the terminating null character. For example:

puts("this is a string : %s",msg);

fputs(char *s, FILE *stream)

fputs writes the null-terminated string s to the named output stream. It does not append a new line character and It does not write the terminal null character. For example:

fputs("this is a string: %s",stdout);

int putc(char c, FILE *stream)

putc appends the character c to the named output stream. It returns the character written. For example:

putc(msg[i], stdout);

int fputc(char c, FILE *stream)

fputc behaves like putc, but is a genuine function, not a macro. For example:

fputc(msg[i], stdout);

int putchar(int c)

putchar(c) is defined as putc(c, stdout). For example:

putchar(ch);

Example 1:

#include <stdio.h>

main()

{

int c; [EOF is defined in <stdio.h>]

while((c=getchar())!=EOF)

if('a'<=c&&c<='z')

[convert lower case to upper case]

putchar( c - 'a' + 'A');

else

putchar( c );

}

Example 2:

#include <stdio.h>

#include <ctype.h>

main()

{

in = fopen("input_file","r");

out = fopen("output_file","w");

while((c=getc(in))!=EOF)

putc((islower(c)?c-'a'+'A':c),out);

}

7.8.2.1.2. FORMATTED I/0

int printf (char *format [, arg ]... )

int scanf (char *format [ , pointer ] ... )

int sscanf (char  *s, char *format [ , pointer] ... )

int sprintf (char *s, char *format [ , arg] ... )

All these functions are similar:

Example:

static char buffer[] = " a 3.14 12 a-string\n";

char ch;

float f;

char str[80];

int num;

scanf("%s,%d",str,&num);

printf("The number =%d, the string is= %s",num, str);

sscanf(buffer,"%c %f %d %s", &ch, &f, &num, str);

sprintf(str,"An approximation of pi is %f\n",f);

This program segment will accept a string and a number, separated by a comma, from the keyboard, and print them in the reverse order. Scanf's parameters are the format string ("%s,%d") and a list of pointers (str,&num ) to variables that it can put the results in. Printf uses the format string passed to it, to print its argument list in the desired format. The format can include text. The sscanf command will scan the string called buffer pulling from it a character, a floating point number, a decimal number and finally a string. They are then stored in the variables ch, f, num, and str respectively.

7.8.2.1.1.1. FORMAT SPECIFIERS
Format item   type                                                  
%d            decimal int      treats numbers as decimal            
%o            octal            treats numbers as octal              
%x            hexadecimal      treats numbers as hexidecimal        
%c            character        Used with a single character         
%s            string           Used with a string of characters     
%f            floating point   The number is printed in the form:   
                               12.123                               
%e            floating point   The number is printed in the form:   
                               1.2123e-001                          
%g            floating point   The shorter form of %e or %f         
%*                             ignore this field                    

These format items can be further modified to specify how the output will look. The syntax is: % <flags><width> <. precision> <letter>

Examples:

C statement                             output               
printf(":%d:", 14);                     :14:                 
printf(":%4d:", 14);                    :  14:               
printf(":%04d:", 14);                   :0014:               
printf(":%-4d:", 14);                   :14  :               
printf(":%f:", 14.0);                   :14.000000:          
printf(":%.2f:", 14.0);                 :14.00:              
printf(":%12.4e:", 14.0);               :1.4000e+001:        
printf(":%.4g:", 14.121212);            :14.12:              
printf(":%.4s:","string");              :stri:               
printf(":%.4s:","st");                  :st  :               

7.8.2.1.1.1. FORMAT SPECIFIERS FOR SCANF

Scanf uses the format specifiers to decide how to convert input ASCII characters to a data type compatible with the variable it is to be assigned to. Scanf only receives pointers to each variable it is passed; therefore it It does not know what type of variable it is dealing with. If an integer is assigned to a float, or a double to a float the result will be nonsense. To prperly perform these conversions scanf uses the same format specifiers as printf with the addition of: %lf, %le, %lg, %ld for double values. These specifiers are the same as their single precision specifiers with the addition of the flag "l" ( lower case el not one)

7.8.2.1.2. FORMATTED FILE I/0
int fprintf (FILE *file_desc, char *format [, arg ...] )

int fscanf (FILE *file_desc, char *format [ , pointer ] ... )

Example:

#include <stdio.h>

...

char str[80];

int num;

FILE *in,*out;

...

in = fopen ("input.file","r");

out = fopen ("output.file","w");

fscanf(in,"%s,%d",str,&num);

fprintf(out,"The number =%d, the string is= %s",num, str);

These operations use the same format descriptors as the screen I/O functions, in fact, the file I/O functions are a generalization of the screen I/O functions.

printf("hello world\n"); <=> fprintf(stdout,"hello world\n");

scanf("%d",&variable); <=> fscanf(stdin,"%d",&variable);

Here stdin is the file pointer for the keyboard and stdout is the file pointer for the screen defined in <stdio.h>. A third file pointer, stderr, is also created when a program is run. This pointer is used to print error messages to the screen. The reason for having two pointer for the screen is that the stdout pointer can be redirected to a file by the operating system; thus a separate pointer, that can also be redirected, is needed to ensure that error messages are sent to the screen for the user to see. (see also 4.6 UNIX).

7.8.2.2. STRING MANIPULATION

Synopsis:

int strlen (char *s)

strlen returns the number of characters in s, not including the terminating null character. For example:

length = strlen("abcd"); [Returns a value of 4]

char *strcat (char *s1, char *s2)

strcat appends a copy of string s2 to the end of string s1, and returns a pointer to the resulting null-terminated resultant string. For example:

strcat(string1,"ing");

char *strncat (char *s1, char *s2, int n)

strncat appends at most n characters and returns a pointer to the null-terminated result. For example:

strcat(string1, string2, 3);

int strcmp (char *s1, char *s2)

strcmp compares its arguments and returns an integer less than, equal to, or greater than 0, depending of if s1 is lexicographically less than, equal to, or greater than s2. For example:

strcmp("mass", "massive"); [returns a negative result]

strcmp("massive", "mass"); [returns a posative result]

int strncmp (char *s1, char *s2, int n)

strncmp makes the same comparison but looks at most at n characters. For example:

strncmp("massive", "mass", 4); [returns zero]

int strcasecmp(char *s1, char *s2)

strcasecmp is identical in function to strcmp but is case insensitive. The returned lexicographic difference reflects a conversion to lower-case.

int strncasecmp(char *s1, char *s2, int n)

strncasecmp is identical in function to strncmp, but is case insensitive. The returned lexicographic difference reflects a conversion to lower-case.

char *strcpy (char *s1, char *s2)

strcpy copies string s2 to s1, stopping after the null character has been copied. For Example:

strcpy(destination, source);

char *strncpy (char *s1, char *s2, int n)

strncpy copies exactly n characters, truncating s2 or adding null characters to s1 if necessary.The result will not be null-terminated if the length of s2 is n or more. For Example:

strncpy(destination, source, 7);

7.8.2.3. MEMORY ALLOCATION

char *malloc(unsigned size)

malloc and free provide a general-purpose memory allocation package. malloc returns a pointer to a block of at least size bytes beginning on a word boundary. For example:

pointer = (int*)malloc(sizeof(int));

char *calloc(unsigned nelem, unsigned elsize)

calloc allocates space for an array of nelem elements of size elsize. The space is initialized to zeros. For example:

pointer = (char*)calloc(number, sizeof(char));

free(char *ptr)

free makes the address pointed to by ptr available for further allocation, but its contents are left undisturbed. For example:

free(pointer);

Malloc and calloc return a null pointer (0) if there is no available memory or if the arena has been detectably corrupted by storing outside the bounds of a block. malloc may be recompiled to check the arena very stringently on every transaction; those sites with a source code license may check the source code to see how this can be done.

7.8.2.4. CONVERSION

double atof(char *nptr)

atof converts an ASCII string into a double floating point number. It recognizes an optional string of spaces, then an optional sign, then a string of digits optionally containing a decimal point, then an optional `e' or `E' followed by an optionally signed integer. For example:

double_Number = atof("-3.1415926");

atoi(char *nptr)

atoi converts a string to a decimal integer, It recognizes an optional string of spaces, an optional sign, a string of digits. For example:

intNumber = atoi("3200");

long atol(char *nptr)

atol recognizes an optional string of spaces, then an optional sign, then a string of digits. For example:

longNumber = atol(longstr);

char *itoa(int value, char *string, int radix)

itoa converts value to a null-terminated string and stores the result in string. With itoa, value is an integer. Radix specifies the base to be used in converting value; it must be between 2 and 36, inclusive. If value is negative and radix is 10, the first character of string is the minus sign (-). For example:

#include <stdlib.h>

itoa(number, string, 10);

char *ltoa(long value, char *string, int radix)

ltoa converts value to a null-terminated string and stores the result in string. value is a long integer. Radix is the same as in itoa above. For example:

#include <stdlib.h>

ltoa(value, string, 10);

7.8.2.5. MATH

All the commands bellow unless specified use the #include <math.h> library call.

int abs(int i)

abs returns the absolute value of its integer operand. For example:

positive = abs(-57);

double fabs(double x)

fabs returns the absolute value of a double operand. For example:

positive = fabs(-57.4);

double exp(double x)

exp calculates the exponential function ex. For example:

result = exp(x);

double log(double x)

log calculates the natural logorithm of x, a double data type. For example:

result = log(x);

double log10(double x)

log10 returns the logarithm of x to base 10 for double data types. For example:

result = log10(x);

double pow(double x, double y)

Pow calculates xy. For example:

result = pow(x, y);

double pow10(double x)

Pow10 calculates 10x. For example:

result = pow10(4); [returns 10000]

double sqrt(double x)

float fsqrt(float x)

Sqrt(x) and fsqrt(x) returns the square root of x for double and float data types respectively. For example:

result = sqrt(x);

double cbrt(double x)

Cbrt(x) returns the cube root of x. For example:

result = cbrt(x);

double sin(double x)

double cos(double x)

double tan(double x)

float fsin(float x)

float fcos(float x)

float ftan(float x)

Sin, cos and tan return trigonometric functions of radian arguments x for double data types. Fsin, fcos and ftan do the same for float data types. For example:

result = sin(x);

double asin(double x)

float fasin(float x)

Asin and fasin returns the arc sine in the range -[[pi]]/2 to [[pi]]/2 for double and float data types respectively. For example:

result = asin(x);

double acos(double x)

float facos(float x)

Acos and facos returns the arc cosine in the range 0 to [[pi]] for double and float data types respectively. For example

result = acos(x);

double atan(double x)

float fatan(float x)

Atan and fatan returns the arc tangent in the range -[[pi]]2 to [[pi]]/2 for double and float data types respectively. For example:

result = atan(x);

rand()

rand uses a multiplicative congruential random number generator with period 232 to return successive pseudo-random numbers in the range from 0 to (231)-1 For example:

#include <stdlib.h>

printf("%d", rand() % 100);

7.8.3. ADVANCED C

7.8.3.1. COMMAND LINE ARGUMENTS

Parameters, such as file names and user options can be passed to a program on the command line.

7.8.3.2. USING #ifdef DEBUG FOR DEBUGGING

It is often useful to include extra statements in your code for debugging. When the code is working, normally the programmer is left with the task of removing all these extra statements. If other errors pop up some of these statements may have to be put back. To make this process easier, these debugging statements can be placed inside #ifdef blocks. #ifdef is a C preprocessor statement that is used to include or exclude code segments based on weather or not a preprocessor label is defined.

Example:

#ifdef DEBUG

printf("The variable x = %d",x);

#endif

To include this segment with in the code either include the line:

#define DEBUG

with in the file containing the statement or compile the file with the -D option.

Example:

cc -DDEBUG myprog.c

If several things are being debugged, different labels can be used (ie DEBUG_MAIN, DEBUG_FUNC1) or the DEBUG label can be define in only the files where the debug statements are required.

7.8.3.3. CURSES

On many machines there is a package called "curses" that provides functions for doing screen manipulation.

7.8.3.3.1. CURSES THEORY

To use curses the programmer first has to create a window. This is done using the newwin() command. This "window" is then used by curses commands. When an updated screen is to be drawn on the terminal the refresh() command is used.

/*

* display -

* a simple version of 'more' using stream file i/o

* and the curses.c library

*

* cc display.c -lcurses -ltermlib

*/

#include <curses.h> [Contains some important macros]

#include <stdio.h>

#define NEWLINE '\n'

#define BLANK ' '

#define TAB '\t'

int main(int argc,char *argv[])

{

FILE *fp;

int x, y, n;

char c, cmd;

WINDOW *win1;

if (argc < 2)

{

printf("error: you must specify a file to print\n");

exit();

}

if ((fp = fopen(argv[1], "r")) == NULL)

{

printf("error: cannot open specified file\n");

exit();

}

initscr(); [Initializes the curses routines]

crmode(); [enable [[ctrl] c]

noecho(); [Disable character echo]

win1 = newwin(0,0,0,0); [Create a new window]

clear();

do

{

wclear(win1); [Clear the new window]

x = 0;

y = 0;

while ((c = getc(fp)) != EOF)

{

if (c == NEWLINE || x >= 80)

{

x = 0;

if (++y >= 23) break;

}

else if (c == TAB)

x += 8 - x%8;

if (c != NEWLINE && c != TAB)

mvwaddch(win1, y, x++, c);[write to the window]

}

wmove(win1,23,0);

wrefresh(win1); [Draw the updated screen]

while (((cmd = getch()) != 'q') && (cmd != '\n'));

} while ((cmd != 'q') && (c != EOF));

endwin(); [Reset the terminal]

fclose(fp);

}

7.8.3.3.2. CURSES FUNCTIONS

Output Functions:

waddch(WINDOW *win, ch)

Add the character ch on the window at the co-ordinates (y,x).

waddstr(WINDOW *win, char *str)

Add the string str to the screen at the current (y, x) co-ordinates.

box(WINDOW *win, char vert, char hor)

Draw a box around the window using vert and hor as the characters for drawing the vertical and horizontal lines.

clear()

wclear(WINDOW *win)

Reset the entire window to blanks and move the (y,x) co-ordinates to (0,0).

wclrtobot(WINDOW *win)

Clear from current (y, x) to the bottom of the screen.

wclrtoeol(WINDOW *win)

Clear from current (y, x) to the end of the line.

wdelch(WINDOW *win)

Delete the character at the current (y, x) position, all following characters are shifted left and the last character becomes blank.

wdeleteln(WINDOW *win)

Delete the current line., all following lines are shifted up and the last line becomes blank.

winsertln(WINDOW *win)

Insert a line above the current one. All lines bellow are shifted down and the last line will disappear.

wmove(WINDOW *win, int y, int x)

Change the current (y,x) co-ordinates of win.

overlay(WINDOW *win1, WINDOW *win2)

Overlay win1 on win2. The contents of win1, insofar as they fit, are placed on win2 starting at the current (y, x). Blanks on win1 leave the contents of win2 intouched.

overwrite(WINDOW *win1, WINDOW *win2)

Overwrite win1 on win2. The contents of win1, insofar as they fit, are placed on win2 starting at the current (y, x). Blanks on win1 become blanks on win2.

wrefresh(WINDOW *win)

Display the contents of win on the terminal. If win is not the whole screen only the part shown is updated.

Input Functions

cbreak() (used to be crmode())

nocbreak() (used to be nocrmode())

enable/disable [[ctrl]c].

echo()

noecho() Normal mode

Sets the terminal to echo or not echo characters.

char wgetch(WINDOW *win)

Get a character from the terminal.

wgetstr(WINDOW *win, char *str)

Get a string from the terminal.

Miscellaneous Functions

endwin() This function MUST be executed before a program exits

Restores the terminal to its state before initscr().

getyx(WINDOW *win, int y, int x)

Returns the current value of y and x. This is a macro, not a function, therfore the addresses of x and y are not needed.

initscr()

Initialize the screen routines. This must be used before any screen routines are used.

WINDOW *newwin(int lines, int cols, int begin_y, int begin_x)

Create a new window with lines lines and cols columns starting at position (begin_y, begin_x). If newwin(0,0,0,0) is used then a window is created that fills the screen.

scrollok (WINDOW *win, bool boolf)

If boolf is FALSE, scrolling is not allowed; this is the default.

Details

scroll(WINDOW *win)

Scroll the window upward one line. This command is slow and its use is therefore usually avoided.

Note:

many commnads can be combined with wmove() so that the cursor is first moved then the desired action is taken.

example:

mvwaddch(win, y, x, ch) is the same as wmove(win, y, x)

waddch(win, ch)

7.8.3.3.3. COMPILING CURSES

On UNIX machines

cc [flags] filename[s] -lcurses

On VMS machines (MEENA)

To compile curses programs on VMS first type:

$define lnk$library sys$library:vaxccurse.olb

Then compile normally, or include this line in your login.com file.

7.8.3. ADVANCED C

7.8.3.1. COMMAND LINE ARGUMENTS

Parameters, such as file names and user options can be passed to a program on the command line.

7.8.3.2. USING #ifdef DEBUG FOR DEBUGGING

It is often useful to include extra statements in your code for debugging. When the code is working, normally the programmer is left with the task of removing all these extra statements. If other errors pop up some of these statements may have to be put back. To make this process easier, these debugging statements can be placed inside #ifdef blocks. #ifdef is a C preprocessor statement that is used to include or exclude code segments based on weather or not a preprocessor label is defined.

Example:

#ifdef DEBUG

printf("The variable x = %d",x);

#endif

To include this segment with in the code either include the line:

#define DEBUG

with in the file containing the statement or compile the file with the -D option.

Example:

cc -DDEBUG myprog.c

If several things are being debugged, different labels can be used (ie DEBUG_MAIN, DEBUG_FUNC1) or the DEBUG label can be define in only the files where the debug statements are required.

7.8.3.3. CURSES

On many machines there is a package called "curses" that provides functions for doing screen manipulation.

7.8.3.3.1. CURSES THEORY

To use curses the programmer first has to create a window. This is done using the newwin() command. This "window" is then used by curses commands. When an updated screen is to be drawn on the terminal the refresh() command is used.

/*

* display -

* a simple version of 'more' using stream file i/o

* and the curses.c library

*

* cc display.c -lcurses -ltermlib

*/

#include <curses.h> [Contains some important macros]

#include <stdio.h>

#define NEWLINE '\n'

#define BLANK ' '

#define TAB '\t'

int main(int argc,char *argv[])

{

FILE *fp;

int x, y, n;

char c, cmd;

WINDOW *win1;

if (argc < 2)

{

printf("error: you must specify a file to print\n");

exit();

}

if ((fp = fopen(argv[1], "r")) == NULL)

{

printf("error: cannot open specified file\n");

exit();

}

initscr(); [Initializes the curses routines]

crmode(); [enable [[ctrl] c]]

noecho(); [Disable character echo]

win1 = newwin(0,0,0,0); [Create a new window]

clear();

do

{

wclear(win1); [Clear the new window]

x = 0;

y = 0;

while ((c = getc(fp)) != EOF)

{

if (c == NEWLINE || x >= 80)

{

x = 0;

if (++y >= 23) break;

}

else if (c == TAB)

x += 8 - x%8;

if (c != NEWLINE && c != TAB)

mvwaddch(win1, y, x++, c);[write to the window]

}

wmove(win1,23,0);

wrefresh(win1); [Draw the updated screen]

while (((cmd = getch()) != 'q') && (cmd != '\n'));

} while ((cmd != 'q') && (c != EOF));

endwin(); [Reset the terminal]

fclose(fp);

}

7.8.3.3.2. CURSES FUNCTIONS

Output Functions:

waddch(WINDOW *win, ch)

Add the character ch on the window at the co-ordinates (y,x).

waddstr(WINDOW *win, char *str)

Add the string str to the screen at the current (y, x) co-ordinates.

box(WINDOW *win, char vert, char hor)

Draw a box around the window using vert and hor as the characters for drawing the vertical and horizontal lines.

clear()

wclear(WINDOW *win)

Reset the entire window to blanks and move the (y,x) co-ordinates to (0,0).

wclrtobot(WINDOW *win)

Clear from current (y, x) to the bottom of the screen.

wclrtoeol(WINDOW *win)

Clear from current (y, x) to the end of the line.

wdelch(WINDOW *win)

Delete the character at the current (y, x) position, all following characters are shifted left and the last character becomes blank.

wdeleteln(WINDOW *win)

Delete the current line., all following lines are shifted up and the last line becomes blank.

winsertln(WINDOW *win)

Insert a line above the current one. All lines bellow are shifted down and the last line will disappear.

wmove(WINDOW *win, int y, int x)

Change the current (y,x) co-ordinates of win.

overlay(WINDOW *win1, WINDOW *win2)

Overlay win1 on win2. The contents of win1, insofar as they fit, are placed on win2 starting at the current (y, x). Blanks on win1 leave the contents of win2 intouched.

overwrite(WINDOW *win1, WINDOW *win2)

Overwrite win1 on win2. The contents of win1, insofar as they fit, are placed on win2 starting at the current (y, x). Blanks on win1 become blanks on win2.

wrefresh(WINDOW *win)

Display the contents of win on the terminal. If win is not the whole screen only the part shown is updated.

Input Functions

cbreak() (used to be crmode())

nocbreak() (used to be nocrmode())

enable/disable [[ctrl]c].

echo()

noecho() Normal mode

Sets the terminal to echo or not echo characters.

char wgetch(WINDOW *win)

Get a character from the terminal.

wgetstr(WINDOW *win, char *str)

Get a string from the terminal.

Miscellaneous Functions

endwin() This function MUST be executed before a program exits

Restores the terminal to its state before initscr().

getyx(WINDOW *win, int y, int x)

Returns the current value of y and x. This is a macro, not a function, therfore the addresses of x and y are not needed.

initscr()

Initialize the screen routines. This must be used before any screen routines are used.

WINDOW *newwin(int lines, int cols, int begin_y, int begin_x)

Create a new window with lines lines and cols columns starting at position (begin_y, begin_x). If newwin(0,0,0,0) is used then a window is created that fills the screen.

scrollok (WINDOW *win, bool boolf)

If boolf is FALSE, scrolling is not allowed; this is the default.

Details

scroll(WINDOW *win)

Scroll the window upward one line. This command is slow and its use is therefore usually avoided.

Note:

many commnads can be combined with wmove() so that the cursor is first moved then the desired action is taken.

example:

mvwaddch(win, y, x, ch) is the same as wmove(win, y, x)

waddch(win, ch)

7.8.3.3.3. COMPILING CURSES

On UNIX machines

cc [flags] filename[s] -lcurses

On VMS machines (MEENA)

To compile curses programs on VMS first type:

$define lnk$library sys$library:vaxccurse.olb

Then compile normally, or include this line in your login.com file.

7.8.5. REFERENCES

* UNIX in a Nutshell for BSD 4.3, O'Reilly & Associates inc, Sebastopol, CA, 1990

* Brian W. Kernighan, Dennis M. Ritchie, The C Programming Language, Prentice-Hall inc., New Jersey, 1978

* David A. Curry, Using C on the UNIX System, O'Reilly & Associates inc, Sebastopol, CA, 1988

* W. Richard Stevens, UNIX Network Programming, Prentice-Hall inc., New Jersey, 1990

* James Wilson, Berkeley UNIX, A simple and comprehensive Guide, John Wiley & Sons, 1991