Sei sulla pagina 1di 93

TO C OR NOT TO C, SOME WAYS TO TAME THE BEAST

*********************************************
The C Programming Language, following on a dialect called B, which
incidentally did not descend from A (and certainly not A Programming
Language, better known as APL), has taken increasing prominence in the
Nineteen Eighties and early Nineties. Were it not for the vast legacy
of COBOL Applications still used in business Data Processing, it would
be without doubt the most common Programming paradigm.
It now underlies all sorts of computing, from Operating Systems, in
particular UNIX, but also the Microsoft Windows family, to commercial,
mathematical and scientific Packages. For the luddites, it has
definitely supplanted BASIC in games Programming. Finally, it forms the
base on which the Object Programming Language C++ was built. In fact,
C++ represents a straight superset of C, so that its own explosion
in the late eighties in no way implies the demise of C itself.
Despite this huge success, the Language betrays its origins as a Systems
programming tool. It was meant to reduce the need for Assembler Coding,
and its designers did not really consider its suitability for other
purposes. The Language goes against several general features of its
contemporaries. At times this simply runs against established instincts,
but in other areas, I can only describe C as a large retrograde step.
So, my first suggestion has to be do you truly need it ?. If youve
heard its much better than Fortran or Pascal, and you are a competent
Programmer in these, than you could do much worse than carry on with
them or look into Fortran 90. Certainly, your productivity will not be
exposed to the severe drop that accompanies a transition to C, at the
very least for an extended learning curve period.
For the brave who feel they must become acquainted with this widespread
Programming language, this set of lectures will present the key features
in the Language, together with advice on avoiding some common pitfalls.

TO C OR NOT TO C - THE PROBLEMS WITH C - Part 1


=================================================
Difficult Areas and Limitations in C :
---------------------------------------- 1/ Program Units

- No Subroutines as in Fortran, COBOL or BASIC,


C Sub-Programs only of the Function type,
that is, Returning a Single Value.

- 2/ Arrays

- C only supports Single Dimensional Tables.


So, multi Dimensional Arrays are implemented
as Arrays of one Dimensional Arrays,
which become a Data Type for this purpose.

- 3/ Array Bounds

- Array overflows (or underflows) not reported,


by C Compilers or Run Time Diagnostics.

- 4/ Character Strings - No Blank Padding of Strings, Terminators used,


many problems arise when theyre missing.
- 5/ Input/Output

- Formatting is difficult,
Robust Input Validation forces lots of Code.

- 6/ Standards

- K&R (Kernighan & Ritchie) or Traditional C


not fully compatible with later ANSI Standard.

Some good features nevertheless :


--------------------------------- 1/ O/S Integration

- Blends very well with UNIX Operating System,


likewise Microsoft C with PC Platform.
Extensive Libraries of pre-coded Routines.

- 2/ Argument Passing

- Great mechanism to pass Arguments to Programs,


much reduces need for small Parameter Files.

- 3/ Dynamic Storage

- Dynamic allocation or Memory available.

TO C OR NOT TO C - THE PROBLEMS WITH C - Part 2


=================================================
Beside the difficulty of the Language, and its departure from the
paradigms of its contemporaries, another major problem with Programming
in C lies in the terrible quality of the Compilers.
Deficiencies in C Compilers :
------------------------------- 1/ Syntax Checking

- Often, incorrect Syntax not detected.


Input/Output Statements in particular to watch.

- 2/ Consistency

- Often, arrangements of main Load Module Blocks


varies depending on hardware,
so a Module running well on one Computer might
hit File Buffer or Memory faults elsewhere.

- 3/ Poor Diagnostics

- Few Warning or Error Messages generated.


Compilers poor aids to initial debugging.

- 4/ Interfacing

- Mixing C and other Code, (Fortran, COBOL)


forces weird Naming and Argument conventions.
Only Routines adhering to them can interface
correctly. Few books care to mention this.

To C or not to C - C Data Representation - Part 1


=================================================
- 1/ Basic Types

- 2/ Type Prefixes

- char

- Character (Single Char, one Byte).

- int

- Integer

(may be only 2 Bytes,


so for Flags or Options).

- long

(at least 4 Bytes,


so ok for Calculations).

- float

- Real

(limited Precision).

- double

(normally 8 Bytes,
best for Calculations).

- long

- double (may be same as double).


- int
(long alone same).

- short

- int

(may be same as int).

- signed

- char
- int

(Range -127 to +127).


(Default for Integers).

"

"

- unsigned - char
- int

(Range 0 to 255),
(always Positive,
all Bits make Value).

To C or not to C - C Data Representation - Part 2


=================================================
- 3/ Scope Prefixes

- auto

- Local to Unit (inside { } set),


Default for in { } Declarations,
Transient to given Run of Unit.

- const

- Initialised Variable may be changed,


but not those, so, effectively,
same as static and of fixed Value.

- extern

- Default on out of { } Declarations,


but Prefix needed if in other File.
Note auto with same Name in a Unit
takes precedence (hides extern).

- register - Not for Applications Code.


- static

- as auto for locality,


but Value Saved between Unit Runs.

- In Data Declarations,
place Scope before Variable Type and Prefix,
like
or
- 4/ Conversions

extern long ll,


static long double dd.

- Called casts or Coercions in C,


quote Target Type in () Brackets as prefix,
like

(long) ll to force a long Integer.

To C or not to C - C Data Representation - Part 3


=================================================
- 5/ Pointers

- Reserve memory for an Address of given Data Type.


Generally not a Data quantity, so virtual,
and any actual Data at Address held in Pointer.
Quote without * to use Address in Pointer,
or with * to get Data Value,
so called dereferencing or indirection,
like
and

long *ll
ll
*ll

to hold an Integer Address,


to get that Address,
"
" Value at that Address.

- Can Add or Subtract off Pointers,


with resulting arithmetic increment,
of Unit Size of Type attached to Pointer,
and implicit if not explicit use of sizeof,
so

ll + 1 = ll + sizeof ( long ).

- Conversions (Casts) off Pointers possible,


with * Mark after Type in () Brackets,
like

(long *) name to get Pointer to long.

- Additional Type of void for Generic Pointers,


for which increments by singly Byte like char.
- Pointers used to address Data Items in Memory,
to get Address of dynamically allocated Memory,
to hold Positions (current, start) in open Files,
but not to move existing Data Items in Memory.

To C or not to C - C Data Representation - Part 4


=================================================
- 6/ Data Addresses

- To get Address of Variable, quote &name,


which gives Location in Memory, not Value there,
like
or

&name to get Address of name,


ll = &name to assign addr. to Pointer.

Memory atomically addressed in Bytes,


containing 8 Binary Bits on modern hardware.
Addresses got via & Prefix may be incremented,
like Pointers, with similar Increment Size rules,
like

ll = ( &name + 4 ), effectively,
ll = ( &name + 4 * sizeof ( long ) ),
for address 4 Logical Units off &name.

Note this cannot be used to relocate a Data Item,


so
or

&name_1 = &name_2,
&name
= ll
illegal,

thus Addresses of explicitly declared Data items


may only show on right hand side of = Signs,
of assignments involving Pointers or Addresses.

To C or not to C - C Data Representation - Part 5


=================================================
- 7/ Simple Arrays

- Single Dimensional only,


Append [NN] to Declaration (for NN Items),
or
[] = { List of Values between Commas };,
like
or

long
long

ll [NN];
ll []
= { 1, 2, 3, 4 };

Note when Values list numbers less than Array,


rest of Items made Zero (or 0.0).
- for Character Arrays only, can also write
char cc [] = "Set or Chars. in Array";.
Note Null (\0) Added at end of Array.
- Items picked by Offset, from Zero to NN - 1,
not by Subscript, ranging from 1 to NN,
as used in many other Programming Languages,
so First Item = name [0],
and Last "
= name [NN - 1].
- 8/ Strings

- Special form of Character Arrays,


where Memory reserved for Data and its Address,
like

char *cc = "String_Data";,

where
and
so
unlike

tail Null (\0) added,


extra Memory Location holds Address cc,
cc may receive another char Address,
char c_fixed [] = "String_Data";.

To C or not to C - C Data Representation - Part 6


=================================================
- 9/ Structures

- In effect, an association of Data Items,


possibly composite and of different Types.
- Introduced via Named Template,
establishing a Data (Variable) Type,
for one or more Declarations of that Type,
each then including all Contents (Items),
like

struct

stdata { char [20] stname , ,


long
stfnum , ,
char [40] stfldt };.

or directly via List of Contents,


followed by Name of Structure Variable,
or list of Names separated by Commas,
like

struct

{ char [20] stname ,


,
long
stfnum ,
,
char [40] stfldt } stinst ;.

Template Format may be followed by Names too,


named Template allowing more later Declarations,
of extra Structures with same Items, or Pointers,
like
or

struct
struct

stdata stdt01, stdt02 ;,


stdata *stpt01, *stpt02 ;.

- Initialise Structures like Arrays,


Item Values following Structure Declaration,
like

struct

stdata

stdt01 = { "Nstr",
,
20
,
,
"Data" } ;.

- Arrays of Structures possible,


declared with Size following Declaration,
like

struct

stdata

stdt01 [NN] ;.

Put Offset after Structure Name,


to access Items of an Arrays Structure,
like

stdt01 [nn].stname = "Struct. 1 Data" ;.

To C or not to C - C Data Representation - Part 7


=================================================
-10/ More Dimensions

- Writing type name [N1] [N2] ;


set up a One Dim. Array of N1 Arrays,
each a One Dim. Array of N2 Basic Types.
- Writing type name [N1] [N2] [N3] ;
set up a One Dim. Array of N1 Arrays,
of N2 One. Dim Arrays of N3 Basic Types.
Can get hard to manipulate,
and can be emulated with single Dimension Array,
like

long

ll [ N1 * N2 * N3] ;,

with Items referenced via [ n1 * N2 * N3


+ n2
* N3
+ n3
] ;.
- Initialising, note difference between
Single { } Set (as if whole Array One Dim.),
and one { } Set per Basic (One Dim.) Array,
like

long

ll [3] [2] = { 1, 2, 3, 4 };,

giving

ll [0] [0] = 1, ll [0] [1] = 2,


ll [1] [0] = 3, ll [1] [1] = 4,
ll [2] [0] = 0, ll [2] [1] = 0,

not

long

giving

ll [0] [0] = 1, ll [0] [1] = 0,


ll [1] [0] = 2, ll [1] [1] = 0,
ll [2] [0] = 3, ll [2] [1] = 4.

ll [3] [2] = { { 1 },
{ 2 }, { 3, 4 } };,

10

To C or not to C - C Data Representation - Part 8


=================================================
-11/ Pointer on Arrays - Array Name quoted with no Offset acts as Pointer,
so with long

or

ll [NN]; Integer Array,

ll
= Address of ll [0],
ll + 1 =
"
" ll [1].

that is ll
= &ll [0],
and
ll + 1 = &ll [1], or ( &ll [0]) + 1.
- Can equate Pointer to Array, but not contrary,
or can use [] Offsets with Pointers,
but only to get Values (in effect dereferencing),
like

long
long_pt

*long_pt;,
= ll;,

or

long_val =
long_pt [2];
= *(long_pt + 2);,

but not ll
=
long_pt,
or
*long_pt [2] (use *(long_pt + 2).
- Key Array/Pointer difference is former fixed,
and represent actual Memory Locations with Data,
whilst latter can change but holds no Memory.

11

To C or not to C - Assignments and Operations - Part 1


======================================================
- 1/ Assignment (1)

- Statement Syntax Target = Value,


where Value may be absolute, or an Expression,
involving several Operands and Variables.
Data Types on Left and Right sides should match,
but when not, Right hand Side force casted,
to Type on Left. When Left hand Variable smaller,
in terms of number of Bytes (Memory Length),
resulting Value unpredictable.
Conversions of Integer Variables to Floating
give a Zero Mantissa (Decimal Part) to Result,
but Floating to Integer conversion delete Decimals,
so round down Absolute Value of Real Variable,
like
and

long

double
double

lneg
lpos
dneg
dpos

= -10
= 15
= -25.75
= 25.25

,,
;,
,,
;,

give
and

lneg
lpos

= dneg ; as -25,
= dpos ; as +25,

but
and

dneg
dpos

= lneg ; as -25.00,
= lpos ; as +25.00.

When Right hand Side exceeds Left in Byte Count,


and Absolute Value within Bounds for Left,
conversion will succeed. Otherwise, unpredictable,
like
and

int
long
float
double

ii
ll
ff
dd

=
15
= -75000
=
25.75
= -85000.85

;,
;,
,,
;,

give

ii
ii

= ll ;,
= dd ; both uncertain,

and

ff

= dd would be uncertain,
when dd very large,
in terms of Exponent.

12

To C or not to C - Assignments and Operations - Part 2


======================================================
- 1/ Assignment (2)

- For clarity in reading and checking Code,


can code Casts implicit in assignments explicitly,
without incurring computational penalties,
so with int
long
double

ii ;,
ll ;,
dd ;,

assign. ll =
becomes ll = (long)

ii ;,
ii ;,

and
dd =
ll ;,
becomes dd = (double) ll ;,
or with
int
unsigned int
double

ii ;,
iu ;,
dd ;,

assign. ii =
iu ;,
becomes ii = (signed) iu ;.
- 2/ Arithmetic
Operators

- Arithmetic Operations allowed, at least in part,


on all basic Data Types, as well as Pointers,
with : Add
Subtract
Multiply
Divide
Modulus

:
:
:
:
:

+ (allowed on Pointers),
- (
"
"
"
),
*,
/,
% (remainder in Integer Divide).

Note Integer Division truncates result,


to highest Integer Value less than Real quotient,
while Modulus given by equivalent Numerator Value,
subtracted off actual Numerator.

13

To C or not to C - Assignments and Operations - Part 3


======================================================
- 3/ Implicit Casts
in Arithmetic

- When computing Operations, Data Types equalised,


to that of Operand highest in Hierarchy given by :
Top

: double
float,
long
int
Bottom : char

(long then Standard),


(int being implied),
(signed above unsigned),
(
"
"
"
).

Like for Left hand side of Assignments,


can code such implicit Casts explicitly,
for clarity in reading and checking Code,
without incurring computational penalties,
so with

int
long
double

ii ; ,
ll ; ,
dd ; ,

expr.
becomes

(long)

ii * ll ,
ii * ll ,

and
becomes

ii * dd ,
(double) ii * ll .

Pointer Variables always of same fixed Byte size,


on a given computer system (commonly 4 or 8 Bytes),
but Unit Value in additions or subtractions
as per size of Data Type associated with pointer,
so with

long
double

*lp ; ,
*dp ; ,

expr.
becomes

lp
lp

+ 4
,
+ 4 * sizeof (long) ,

and
becomes

dp
dp

- 5
,
- 5 * sizeof (double) ,

but
becomes

dp
dp

+ ip
,
+ ip * sizeof (double) .

14

To C or not to C - Assignments and Operations - Part 4


======================================================
- 4/ Operator
Precedence

- Multiply, Divide and Modulus processed first,


before Add and Subtract, when computing Expressions,
with operations of same Level handled left to right,
but Operations after any Casts or Function Calls.
Use Parenthesis to alter order of execution,
like
rr = aa +
bb * cc * dd
ee / ff ;,
same as rr = aa + ( bb * cc * dd ) - ( ee / ff );.
In long Expressions,
can make Code clearer by grouping operand anyway,
so no doubt as to order of execution of operations.

- 5/ Operator
Overload

- Note Asterisk Symbol (*) in dual roles,


as Multiply Operator and Pointer Prefix,
so good to always separate Operators and Operands,
with at least one space, to avoid confusion,
so

long
long
long

la ; ,
lb ; ,
*lp ; ,

mean
la
same as la

=
=

la*lb
; ,
la * lb ; ,

but
la
same as la

=
=

la*lp
; ,
la * lp ; ,

with

lp

Address Value, not Data (*lp).

Note, with Pointers, **pp and so on legal,


for "Pointer to Pointer" and so on,
so spacing Arithmetic Operators strongly advised.

15

To C or not to C - Assignments and Operations - Part 5


======================================================
- 6/ Increment (1)

- For Variable as well as Pointers,


Auto Increment or Decrement Operators available,
to add or subtract a Unit from Variable or Pointer.
Operator must be juxtaposed to Variable Acronym,
without any Spaces or Separators in between.
Position on left or right of Acronym important,
with

ll++ : Add 1 to ll,


after computing any expression,
where ll involved,
called "postfix" Mode,

++ll

: Add 1 to ll,
before computing any expression,
where ll involved,
called "prefix" Mode,

ll-- : Subtract 1 off ll,


after computing any expression,
where ll involved,
as for ++, "postfix" Mode,

--ll

: Subtract 1 off ll,


before computing any expression,
where ll involved,
as for ++, "prefix" Mode.

So, in expressions,
Prefix Mode Increments take precedence,
while Postfix Increments computed after all of rest.
Note Increments can result in multiple Assignments,
in one Assignment Statement (Result = Expression),
with some to Variables in Right hand side,
and not always of same Type as Left hand side,

16

To C or not to C - Assignments and Operations - Part 6


======================================================
- 6/ Increment (2)

- Increments possible as stand alone Statements,


with Equal (=) Sign and Left hand side deleted.
Postfix Mode should be used in such situations.
Increment and Decrement examples :
with

long
long
long

la ; ,
lb ; ,
*lp ; ,

assign.
same as la =

la++
; ,
( la + 1 ) ; ,

assign.
same as la =
but

--la
; ,
( la - 1 ) ; ,
la-; clearer here,

and
lp =
same as lp =
that is lp =

--lp
; ,
( lp - 1
) ; ,
( lp - sizeof (long) ) ; ,

but
lb =
same as la =
then
lb =

++la + 5
; ,
( la
+ 1 ) ; ,
la
+ 5
; ,

and
lb =
same as lb =
then
la =

la-- + 5
; ,
la
+ 5
; ,
( la
- 1 ) ; .

17

To C or not to C - Assignments and Operations - Part 7


======================================================
- 7/ Self Operation

- When Assignment Target also in Left hand side,


may write Assignment as Operator=,
and omit Target Variable from Left hand side,
so

long
long
long

la ; ,
lb ; ,
lc ; ,

give
same as la =

la += 3
; ,
( la + 3 ) ; ,

and
same as la =

la *= 7
; ,
( la * 7 ) ; ,

and
la -=
same as la =

lb / lc
; ,
( la - ( lb / lc ) ) ; .

Add and Subtract may be used thus with Pointers.

18

To C or not to C - Flow Control and Logic - Part 1


===================================================
- 1/ Conditions

- Normally presented as Expression Operator Value,


where Value may itself form an Expression,
or the result of executing one or more Statements,
and Logical or Relational Operators specific,
in Set : Equal
Not Equal

: == (not same as =),


: !=,

Strictly Greater : >,


Greater or Equal : >=,
Strictly Less
Less or Equal

: <,
: <=.

Note Parenthesis around Condition(s) compulsory,


and Conditions often called Logical Expressions,
so with

long
long

Test

(la != lb + 5 ),

means

lb Value incremented 5 Units,


and matched against la Value,
neither being actually changed,

However

( la == lb++ + 5 ),

means

lb incremented 1 Unit after match,

Likewise ( la
means
and

la ; ,
lb ; ,

= printf ( "Test" ) > 0 )

printf Message Output attempted anyway,


Value returned tested against Zero,
usual Return Code from successful Call.

19

To C or not to C - Flow Control and Logic - Part 2


===================================================
- 2/ Implicit Casts
in Conditions

- When testing Conditions, Data Types equalised,


as when computing Value of Expressions,
to that of Operand highest in Hierarchy given by :
Top

: double
float,
long
int
Bottom : char

(long then Standard),


(int being implied),
(signed above unsigned),
(
"
"
"
).

Like for case of Expression computations,


can code such implicit Casts explicitly,
for clarity in reading and checking Code,
without incurring computational penalties,
so with

int
long
double

ii ; ,
ll ; ,
dd ; ,

cond.
becomes

(
( (long)

ii == ll ),
ii == ll ),

and
becomes

(
ii >
( (double) ii >

20

dd ),
dd ).

To C or not to C - Flow Control and Logic - Part 3


===================================================
- 3/ Composite
Conditions

- Basic Conditions may be combined into Composites,


with
and

&&
||

for
for

"And" Logic,
"Or"
" .

Composite Conditions evaluated Left to Right,


unless Parenthesis used to enforce different Order,
so with

long
long

la ; ,
lb ; ,

cond.
same as

(
la
( ( la

meaning

la same as lb or above lb + 12,

but

( ( la
( lb

means

individual basic Conditions evaluated,


in left to right Order to answer each "Or",
and, last, "Or" outcomes tested for "And".

== lb
||
la >
== lb ) || ( la >

== lb
>= 56

21

||
||

lb + 12
),
lb + 12 ) ),

la > lb + 12 ) &&
lb < -24
) ) ,

To C or not to C - Flow Control and Logic - Part 4


===================================================
- 4/ Basic
Conditionals

- Basic Conditional execution of Statements with if,


where syntax if ( Condition ) { Statements },
resuming unconditional execution at Blocks end,
so with

long
long

Block

if

la

la ; ,
lb ; ,
la != lb + 5 ) { ,

lb

+=

5 ;

,
,

*=

12 ;

means
when
and

la incremented 5 Units,
la not same as lb,
lb anyway doubled afterwards.

However

if

la

means
but

+=

5 ;

,
,

la incremented 5 Units likewise,


lb then incremented by 1 Unit anyway.

Likewise if

}
means
when

la == lb++ + 5 ) { ,

( la

= printf ( "Test" ) > 0 ) { ,

printf ( "Error in Printing" ) ;

,
,

Message Output from inside if Block,


Output attempt of String "Test" fails,
and non Zero Value returned by printf.

Braces ({ } Pair) optional when single Statement,


to execute Code when Condition satisfied,
otherwise, carry on with Statements after if.

22

To C or not to C - Flow Control and Logic - Part 5


===================================================
- 5/ Alternate
Conditionals

- Basic Conditional execution of Statements with if,


Optionally, else Block may be added to an if,
like else { Statements }, where, like for if,
Braces ({ } Pair) optional when single Statement,
to execute Code when if Condition not satisfied,
so either Code with if or with else executed,
before following with Statements after both.
so with

long
long

write

if

la ; ,
lb ; ,

( la = printf ( "%d", lb ) > 0 ) { ,

printf ( "Error in Printing" ) ;


}
else {

,
,
,

printf ( "Value lb shows OK" ) ; ,


,

so as to pick between Diagnostic Output Options.


Finally, else Clauses can be juxtaposed to if,
in effect giving one or more elseif Blocks,
with their own Entry Conditions,
and else Block still possible last, so,
can test if

( la = printf ( "%d", lb ) > 0 ) { ,


printf ( "Error in Printing" ) ;

else
if ( lb

,
,

,
< 0 ) { ,

printf ( "Value lb negative" ) ; ,


}
,
else {
,

printf ( "Value lb positive" ) ; ,


.

23

To C or not to C - Flow Control and Logic - Part 6


===================================================
- 6/ Nested
Conditionals

- Basic if Conditionals may be Nested in each other,


and Braces ({ } Sets) may be used around them,
to Nest if Blocks in else or else if Blocks.
so with

long
long

can test if

la ; ,
lb ; ,

( la = printf ( "%d", lb ) == 0 ) { ,
if

lb >=

1 )

printf ( "lb above


else
if (

lb ==

,
0" ) ;

,
,

0 )

printf ( "lb exactly 0" ) ;


else
printf ( "lb below

,
,

0" ) ;

Note, this same as 3 separate if Blocks,


with Composite Conditions for Entry,
written if ( Value Test && Print Test ),
so appropriate Message printed in response.

24

,
.

To C or not to C - Flow Control and Logic - Part 7


===================================================
- 7/ Iterative
Conditionals

- When Conditional Code Block may be run many times,


use

: while to test Condition before Entry,


and before next Iteration, Reentry,
that is, before executing Block,
which may thus never be executed,
when Entry Condition false,
do
and, after Conditional Block,
while to test Condition after Block,
and after each Iteration, Reentry,
so Block always run at least once,

so with

long
long

*la ; ,
*lb ; ,

Block

while (

printf

la++

la < lb ) {
( "Data

%d", *la ) ; ,
; ,
,

prints Data Value at Address la,


but only when that below Address lb,
but,

do

printf

la++
}
while (

( "Data

la < lb )

%d", *la ) ; ,
; ,
,
; ,

prints Data Value at Address la once,


and then again when la still below lb.

25

To C or not to C - Flow Control and Logic - Part 8


===================================================
- 8/ Loops

- As an alternative to while or do while,


Loop Statement for available, in general form :
for

( Statements to execute before first run ; ,


Entry Condition for Run of Block
; ,
Statements to execute after each run
) ,

{ Block of Statements controlled by Loop } .

When more than single Initial or Post run Statement,


separate individual Statements with Commas,
making exception to normal termination with ;.
Note, when Entry Condition not initially met,
Loop only results in execution of pre run Code,
and Block inside never executed, as in while,
when Entry Condition not true.
Most commonly, some Counter set before first run,
tested against some final Value for repeat runs,
and incremented or advanced after each run,
so for while Block in above examples,
Loop

: for ( la = lb - 100 ;

la < lb ;

la++
; ) {

printf

( "Data

,
,
,

%d", *la ) ; ,
,

gives same effect, assuming la = lb - 100 ;,


before la < lb Condition tested in while.
Loop constructs clearer than while or do while,
when iterated Value used in Conditional test,
to control execution, but while, or do while,
better when Entry Condition not regularly updated.

26

To C or not to C - Flow Control and Logic - Part 9


===================================================
- 9/ Loop Control

- Given iterations of Conditional Entry Blocks,


or whole iterative Conditional execution,
may be abandoned part way,
with
to

continue ,
abort current iteration,
and proceed to test whether more needed,

or
to

break ;,
abort current iteration,
and any other iterations in Loop,

so with

long
long

Loop

*la ; ,
*lb ; ,

: for ( la = lb - 100 ;

la < lb ;

la++
; ) {

if

,
,
,

( *la < 0 )

; ,

break

; ,

elseif

( *la == 0 )

continue
printf

( "Data

; ,
; ,

%d", *la ) ; ,
,

terminates Loop when either la same as lb,


or Value addressed by la becomes Negative,
and only execute printf when Value non Zero.

27

To C or not to C - Flow Control and Logic - Part 10


===================================================
- 9/ Exit Control

-10/ Branches

- At level of current Routine (Program or Function),


immediate termination forced by exit ( Retcode ),
where Retcode Optional, but Parenthesis needed.
Seldom seen in modern practise, goto Label ;,
forces unconditional Jump to a given Statement,
where Label : prefixed to desired Statement,
like

goto lab
; ,
...
lab : la++ ; .

-11/ Case Conditions - As an alternative to serial else if Blocks,


may use switch Block, with Integer Expression,
and case Clauses testing it against set Values,
like

switch ( ex ) {

case

,
ex_val_1 :

... Statements ... break;


case

ex_val_2 :

... Statements ... break;


default

... Statements ... break;

,
,
,
,
,
,
.

Note, Once a case Blocks entered,


need a break; to force completion of switch,
as when omitted, next case Block executed,
irrespective of Entry condition, and so on,
till a break; found. Using serial if else,
and else for default thus safer usage.

28

To C or not to C - Program Units - Part 1


==========================================
-

1/ Programs

- Termed and labelled main in C,


with so named initial Entry Statement,
like

rtpe

main ( ) { Program Code },

where

rtpe Type of Return Code,


sent back to Operating System,
or void when none returned.

{ } Brackets enclose all Statements (Code).


Statements ended by ;, can span several Lines,
and generally include any number of Spaces.
- Can use exit ( nn );, at any stage,
to leave a Program there and then,
and provide Return Code nn to Calling Unit,
likely to be Operating System for Programs,
where nn Type should match rtpe above.
- Comments may show anywhere,
between /* Start and */ End Markers,
which may span several Lines in File,
like

/* Variable Declarations */,

or

/* Variable Declarations ,
*/
.

29

To C or not to C - Program Units - Part 2


==========================================
-

2/ Directives

- Pre-Compiler Directives, flagged with # Prefix,


may show anywhere, preferably near top of Files.
- Most common Pre-Compiler Directives :
include, like #include src_file.c,
to expand additional Source Files,
at this position in Code,
define,

like #define

MEMBK 1024,

normally with Mnemonics in Capitals,


so given Value placed in Code proper,
whenever Mnemonic (Constant) appears,
like long
or
long
-

3/ Prog. Arguments

- Can present Command


in special Array of
leading it with its
of which argv [0]

l1
[MEMBK] ;,
l2 = MEMBK ;.

Line Arguments to Programs,


(char) Strings argv [ ],
Item Count (int) argc,
File Name of Module.

In that case, Syntax differs between ANSI C,


and Traditional, Kernighan & Ritchie (K&R) C,
ANSI C : void

main ( int
argc,
char *argv [ ] )

K&R

main (

C : void

argc
argv
int
char

,
)

,
{ } ,
,
,

argc
;
,
*argv [ ] ; { } .

Once argv and argc included in main,


any number of Arguments allowed on Command Line,
but main Code need not use any of them,
or can selectively use or ignore some of them.

30

To C or not to C - Program Units - Part 3


==========================================
-

4/ Sub-Programs

- Internal (nests of) Pairs of { }


define Local (Inline) Sub-Program Units,
as distinct from Function Sub-Programs,
where Variable Declarations allowed,
local to Statements in Unit (not advised).
Bracing statements executed in Loops,
or as result of if and else Clauses,
represents case of this. When Blocks long,
may detach them into separate Functions,
though this implies computational overheads.
Conversely, Function may be turned inline,
to simplify Code and improve execution time,
an optimisation called "Procedure Inlining".
- External Programs invoked from Main, or "called",
always of Function form in C,
in schematic terms, a "Many to One" Mapping,
where "Many" may be Zero, and "One" optional,
so Functions allowed with no passed Arguments,
or (and) no Value returned to calling Unit.
- Functions can call themselves in C,
called "Recursion", needing careful coding,
to avoid infinite self call series.
- Many tasks implemented via Functions in C,
often substituting for Intrinsic facilities,
as found in other Programming languages,
like Fortran or COBOL.
For instance, all Data Input, Output and display,
or basic Character String manipulations,
effected via (standard) Function Call,
as well as all common Mathematical Functions.

31

To C or not to C - Program Units - Part 4


==========================================
-

5/ Function Entries
and Prototypes
- Entry and First Statement to a Function,
sets Type of returned Value, names Function,
and Declares any (Optional) passed Arguments.
Syntax same as for main Program Entries,
thus differs in ANSI Standard C and K&R C,
ANSI C : long

func ( int
double

arg_1,
,
arg_2 ) { } ,

K&R

func (

arg_1,
arg_2 )

C : long

int
double

,
,

arg_1 ;
,
arg_2 ; { } ,

- Called Functions require a Header, or "Prototype",


a Declaration making them known to Compiler,
in all Source Files where they get invoked.
Prototypes same as Entry Statement to Function,
but with { } and Code therein replaced by ;,
so effectively forming stand alone Statements.
- Prototypes should show outside all Routines,
in Source File(s) where used, including main.
Often copied by #define Pre-Compiler Directives,
from Outside "Header" Files with h Extensions.
- Prototype Syntax differs in ANSI Standard C,
and Traditional, Kernighan & Ritchie (K&R) C,
ANSI C : long

func ( int
double

K&R

func ( );

C : long

32

arg_1,
,
arg_2 ); ,
.

To C or not to C - Program Units - Part 5


==========================================
-

6/ Ending Functions - Can use return ( nn );


to leave a Function there and then,
where nn optional Returned Value or Code,
passed back to calling Program or Function,
though Function Type should be void when none.
Likewise, exit ( nn );,
stops whole Program (main) and any Functions,
providing Return Code nn to Calling Unit,
likely to be Operating System for Programs.
- After Function completes Execution,
Resumption of execution of calling Unit,
at Statement following Function call,
unless exit invoked from inside Function,
to terminate itself, and all Functions,
back up call path to main Program.
- When End of Code (trailing } Brace) reached,
without a return or exit Statement in Path,
Function terminates, and Calling Unit resumes,
as usual at Statement following Function call,
but with Return Code of unpredictable nature,
unless Function was of void Type,
where no Return Code then expected.

33

To C or not to C - Program Units - Part 6


==========================================
-

7/ Libraries

- With Functions providing most facilities in C,


sets, or "Standard Libraries" available,
so via single include Pre-Compiler Directive,
entire Function sets made known to Programs.
Such include Directives make Prototypes
for all Functions in a Library available,
with no need to enter them explicitly.
Four major Function Libraries exist, for :
Character String handling (string) :
Quite often, but not necessarily,
distinct from lone char operation.
Allow whole String copying,
or finding Lengths of Strings.
Mathematical Functions

(math) :

Include Exponentiation (pow),


and Trigonometric Functions.
Standard Input and Output (stdio) :
Include all File related operations,
as well as Screen Input and Output.
General Functions

(stdlib) :

Any Function not found in above.


These Libraries may need flagging,
on Command Line, when compiling Source Code,
for example -lm frequently required,
to enable use of Mathematical Library.
Programmers may set additional Libraries,
specific to given Programs, or Packages,
which always need being flagged to Compilers.

34

To C or not to C - Program Units - Part 7


==========================================
-

8/ Lib. Inclusion

- With basic tasks implemented with Functions,


and no computational cost involved,
useful to provide all Standard Libraries,
with include Directives, in any Program,
for example with Code :
/*
*
*
*
*
*
*
*/

Called Functions Prototypes ,


--------------------------- ,
,
Standard Libraries :
,
,
For Maths, Input - Output, ,
Generics and Char. Strings. ,
,

#include
#include
#include
#include

<math.h>
<stdio.h>
<stdlib.h>
<string.h>

/*
*
*
*
*
*/

Specific Libraries :

,
,
,
,

,
,
Note Names Double Quoted,
,
rather than between < >, ,
reserved for Standard Libs. ,
,

#include "inacn_.h"

/* Program Itself Begins.


*/

,
,

void main

,
,
,

( int
char

argc
,
*argv [] )

Declarations and Source Code }

35

To C or not to C - Program Units - Part 8


==========================================
-

9/ Func. Arguments

- Functions usually expect a set total Arguments,


that is, passed Values, when invoked (called),
and these cannot be changed inside Functions,
so called "by value" passing.
However, Arguments may be Pointers (Addresses),
as well as Values of actual Data Variables.

- 10/ Function Result

- Functions not forced to return a Result,


with special Type of void used when no Result,
ANSI C : void

func ( long

K&R

larg ) ,
{ Code } ,

C : void

func (

larg ) ,
long

arg_1; ,
{ Code } .

- Functions Returned Result may go to Variable,


be ignored, or examined in a Conditional Test,
in which case no later use of it possible :
Storing Function Result in Variable pw2,
leaving pw1 unchanged :
pw2 = pow

( 2.0, (double) pw1 ).

Testing and discarding Function Result,


(Code from fprintf,
checking Output failure) :
if

( fprintf ( stderr, "Data :" ) != 0 ).

As above ignoring and discarding Result


fprintf

( stderr, "Data :" ).

36

To C or not to C - Program Units - Part 9


==========================================
- 11/ Pointer usage

- To achieve many to many Argument Assignments,


Pass Pointers (Addresses) rather than Values,
so called "by reference" Argument Passing,
where Arguments, that is, Data Addresses fixed,
but contents can be changed inside Function :
so, for Single Arguments :
like

int
double
long

arg_1 ;
arg_2 ;
retv ;

,
,
,

Header :
ANSI long

func ( int
*arg_1,
double *arg_2 );

K&R

func ( );,

Call

long

: retv = func (

or, for Array

&arg_1,
&arg_2 );

,
,

,
.

Arguments :

like

int
*arg_1 ;
double *arg_2 ;
long
retv ;

or

int
double
long

,
,
,

arg_1 [NN] ; ,
arg_2 [NN] ; ,
retv
; ,

Header :

Call

ANSI long

func ( int
*arg_1,
double *arg_2 );

,
,

K&R

func ( );

long

: retv = func (

37

arg_1,
arg_2 );

To C or not to C - Program Units - Part 10


==========================================
- 12/ Memory, Files

- Even with Pointers declared in calling Unit,


and presented by reference, with &pntr,
any Memory obtained from Dynamic Allocations,
or Arrays locally declared in a Function,
or Data Files opened inside a Function,
remain purely local to that Function.
So, best to handle Memory Allocations,
and opening and closing Files in Main Programs,
or lower level nested Routines (Functions),
possibly passing attached Pointers to Functions,
where storage or Files to be accessed by them.

- 13/ Array Bounds

- When Array bound checks, or Loop processing,


to be carried in called Functions,
should pass Array Size, as well as Data Pointers.
like

and

int
double
long
: retv = func (

38

arg_1 [NN] ; ,
arg_2 [NN] ; ,
retv
; ,
arg_1,
arg_2,
NN
);

,
,
.

To C or not to C - Dynamic Memory Handling - Part 1


===================================================
- 1/ Pointers only

- Memory, by definition is allocated at an Address,


so Targets of Calls must be Pointers.

- 2/ Test outcome

- NULL Valued Pointer Returned when Calls fail.


Must be tested as Location Zero Reserved,
so attempting to set it would fails Program.
When Memory request call successful,
Pointer with Address of allocated Memory Slice.

- 3/ Scope

- Same rules as Variables,


only available in Local Routine ({ } Set)
where Memory obtained, and for that given Run,
unless Pointer static or extern.

- 4/ Size

- Dynamic
involve
as well
so only

Memory allocation requests (Calls)


large Operating System overhead,
as programming complications,
worthwhile for sizable amounts.

Operating System reserves Memory in Pages,


with a minimum ranging from 512 to 4096 Bytes,
so any lesser request still means a Page given,
though end not formally allocated to Program.
Picking Power of two a good default scheme,
so would have 512, 1024, 2048, 4096 and so on.
On these lines, can pick such multiples,
but of Size of appropriate Data Element,
say a Double Variable, as in examples below,
or a higher level Structure, like an Array.

39

To C or not to C - Dynamic Memory Handling - Part 2


===================================================
- 5/ Functions

- 6/ General Method

- calloc

- Gets Continuous Slice,


Initialised to Binary Zeros.

- free

- Releases Allocated Slice.

- malloc

- Gets Memory, may be in many Extents.

- realloc

- Can extend Slice off malloc Call,


in effect free then malloc,
but copies old contents over.

- Best to Declare Pointer of appropriate Data Type,


for receiving actual Address of allocated Memory,
and Integer for size, at start of Source Code,
before any logic or Executable Statements.
This makes it easier to later change them.
- Nevertheless, in Memory request Call,
present Pointer as a Cast (like (type *)),
so reader in no doubt, and additional safety.
- Best code request as an if Logic Clause,
testing Value of Pointer after Function Call,
entering Conditional when request fails,
and gives Null (Binary or Hexadecimal Zero).
Normal Code execution can thus continue after.
- When request fails,
and this means processing cannot continue,
should Terminate complete Program Unit,
back to Operating System, passing non Zero Value,
often called Return Code. In Programs involving
Data Files, these should be closed, and that
operation checked before abandoning Execution.
- Allocated but not released Memory freed at end,
by Operating System.

40

To C or not to C - Dynamic Memory Handling - Part 3


===================================================
- 6/ Function calloc - Memory, Continuous Slice Allocation, like :
/* Double Precision typed Pointer, to get Address of Storage,
* and (long) Integer to hold actual Units of Memory Allocation.
*/
double *mat
long

tot_mat = 512 ;

/* Eventual other Declarations, before executable Statements ...


*/
/* Test Result of attempting Contiguous Memory Allocation.
* Pointer Cast here redundant, as Pointer declared as Double,
* but informative for reader, and additional safety.
*/
if

( ( mat = (double *)
calloc
( tot_mat, sizeof (double) ) ) == NULL ) {
/* Send Error Message to Default Output Unit (usually Screen).
*/
fprintf ( stderr,
"\n\nProgram : %s, Contig. Memory Allocate failed",
argv [0]
);
/* Terminate complete Program Unit, back to Operating System,
* usually with a non Zero Value (often called Return Code),
* eventually attempting to Close any Data Files still open.
*/
exit ( 9 );

}
/* Normal execution of Program continues from here ...
*/

41

To C or not to C - Dynamic Memory Handling - Part 4


===================================================
- 7/ Function free

- Memory, Previously allocated Slice release.

/* Double Precision typed Pointer, for Address of Storage,


* which must be non Null, and result of previous Allocation.
*/
double *mat ;
/* Eventual other Declarations, before executable Statements ...
*/
/*
*
*
*
*
*
*
*/

Free previous allocation (result of calloc or malloc).


Note return value implementation dependent, not worth testing,
as System should anyway recover Memory at Program completion.
Allocated but not released Memory also released at Completion,
or upon abnormal termination, again via Operating System.

(double *)

free

( mat );

/* Execution of Program continues from here anyway ...


*/

42

To C or not to C - Dynamic Memory Handling - Part 5


===================================================
- 8/ Function malloc - Memory, Slice allocation.
/* Double Precision typed Pointer, to get Address of Storage,
* and (long) Integer to hold actual Units of Memory Allocation.
*/
double *mat
long

tot_mat = 512 ;

/* Eventual other Declarations, before executable Statements ...


*/
/*
*
*
*
*
*/

Test Result of attempting Memory Allocation.

if

( ( mat = (double *)
malloc
( tot_mat * sizeof (double) ) ) == NULL ) {

Note allocated Memory need not be contiguous, but,


most likely to be when up to a Page and no more asked.
Use calloc Function for guaranteed continuous allocation.

/* Send Error Message to Default Output Unit (usually Screen).


*/
fprintf ( stderr,
"\n\nProgram : %s, Memory Allocate failed",
argv [0]
);
/* Terminate complete Program Unit, back to Operating System,
* usually with a non Zero Value (often called Return Code),
* eventually attempting to Close any Data Files still open.
*/
exit ( 9 );
}
/* Normal execution of Program continues from here ...
*/

43

To C or not to C - Dynamic Memory Handling - Part 6


===================================================
- 9/ Funct. realloc

- Memory, Slice reallocation (amendment).

/* Double Precision typed Pointer, for Address of Storage,


* and (long) Integer to hold revised Units of Memory Allocation.
*/
double *mat
long

tot_mat = 512 ;

/* Eventual other Declarations, before executable Statements ...


*/
/*
*
*
*
*
*
*
*/

Test Result of attempting Memory Reallocation.


Note Memory Address either previously allocated and non Null,
or Null, to in effect make call same as malloc (new Memory).

if

( ( mat = (double *)
realloc ( mat,
tot_mat * sizeof (double) ) ) == NULL ) {

Like for malloc allocation, need not be contiguous.


Existing Memory contents kept (truncated when reduction).
Use calloc Function for guaranteed continuous allocation.

/* Send Error Message to Default Output Unit (usually Screen).


*/
fprintf ( stderr,
"\n\nProgram : %s, Memory Reallocate failed",
argv [0]
);
/* Terminate complete Program Unit, back to Operating System.
*/
exit ( 9 );
}
/* Normal execution of Program continues from here ...
*/

44

To C or not to C - Files And I/O (Input/Output) - Part 1


=========================================================
- 1/ Functions needed

- All File handling, Input and Output (I/O),


to Files or otherwise, effected via Functions.
Programs require Standard Libraries,
made known with Pre-Compiler Directives,
before calling I/O Functions possible,
like

#include <stdio.h>,
#include <stdlib.h>,
#include <string.h>.

Strictly, only stdio (Standard I/O) needed,


but in practice many useful Functions elsewhere.

45

To C or not to C - Files And I/O (Input/Output) - Part 2


=========================================================
- 2/ Files

- Files accessed via FILE Data Type,


always attached to Pointer Variables,
representing current Position in open Files,
or result of last operation on File otherwise.
like

FILE

*pfname ;.

Name given to a FILE Pointer local to Program,


need not relate to File Name in Operating System,
as these linked when File actually opened.
- Any access to contents, or writing to Files,
conditional on successfully opening Files,
with appropriate Access Mode(s),
except Default Files described below.
On some systems, File Access Rights,
as set on Operating System, may prevent opening,
even when Program not directly violating Rights,
for example "Read Only" Files, may not open,
when "Read Write" specified or implied,
even when Program makes no attempt at Writing.
- Once no more access expected for Files,
good practice to explicitly close them,
this eventually releasing them for other use.
Operating System closes all Files left open,
when Program completes normally or otherwise.
- Once Files opened, Access Modes fixed,
so closing and reopening required to change them.
Any File may be opened and closed many times,
in any given Program run, either explicitly,
or using special reopen File Function.

46

To C or not to C - Files And I/O (Input/Output) - Part 3


=========================================================
- 3 Default Files

- As an exception to Files needing opening,


before operations on, or insertion of, contents,
three Default Files (Channels) always available :
stdin
stdout
stderr

= "Standard Input",
= "Standard Output",
= "Standard Error".

- Standard Input usually from User Terminal,


Standard Output and Error to User Terminal,
from which Program itself run when Interactive,
or Batch (Job control) Script controlled Files.
Some Operating Systems allow Channel Redirection,
where a File may be used instead, in which case,
Operating System will open File as required.
- Standard Channels may be assumed open,
Input in "Read" Mode, Output and Error in "Write",
whenever Programs begin execution.
- Standard Channels may be closed,
and sometimes, but not always easily, reopened.
Rewind Operations, and likely repositioning,
illegal, and attempts should produce Error.
- As both Standard Output and Error go to Terminal,
systems which send data via a buffering relay,
only when a given buffer has filled up,
may show Data out of Program sending sequence.
Facilities exist to force Buffer emptying,
or bypassing Buffers when writing to Channels,
but these can prove cumbersome, so using one,
but not both of Standard Output and Error simpler.

47

To C or not to C - Files And I/O (Input/Output) - Part 4


=========================================================
- 4/ Basic File
Functions

- All File handling Functions use File Pointer,


as first Argument, with eventual Access Code,
as second Argument, when opening File :
fopen

- Open File with desired Access Mode,


to get File Pointer to Data Records,
giving File Name as Argument 1,
and Access Mode as Argument 2,
both Char. Strings, where latter :
r
w
a

for Read
(not allowing Write),
" Write (extant Data lost),
" Append (Write Data at Tail),

r+ for Update (Read and Write),


w+ " Update, Read back possible,
a+ " Append, Read and Write,
but only at Tail.
Sometimes, b Suffix Modes supported,
for raw Binary (unformatted) Access,
appended to any of above Modes.
Pointer Value NULL back when Error,
Data Pointer returned when successful,
like

pfinp = fopen
pfout = fopen

( file_name, "r" ) ;,
( "out.dat", "w" ) ;.

- freopen - Close and immediately reopen File,


with same Syntax and Args. as fopen.
- fclose

- Close and release File.


Status Value EOF back when Error,
Zero when operation successful,

like

irtc

48

fclose ( pfinp ) ;,
= fclose ( pfout ) ;.

To C or not to C - Files And I/O (Input/Output) - Part 5


=========================================================
- 5/ File Position
Functions (1)

- Functions allow changes in place of next access,


or query on current Position (Offset) in File,
in terms of Byte Counts from a given Reference :
- fseek

- Set current Position (Offset) in File,


thus allowing Random Access.
Two Arguments following File Pointer,
namely an Offset (possibly Negative),
and a Base Position, which may be :
SEEK_CUR for Current Pos. in File,
SEEK_SET " Top (Start) of Data,
SEEK_END " End (Tail) "
" .
Offset (Bytes) added to Base Position,
File Pointer moved, and Zero returned,
or -1 sent back after Error detected,

like

irtc

irtc

- rewind

like

like

fseek
( pfinp,

10, SEEK_CUR ) ;,

fseek
( pfinp, -10, SEEK_END ) ;.

- Rewind File to Top,


as in fseek ( fpt, 0, SEEK_SET ) ;,

rewind

irtc

- ftell

( pfinp ); , or,

fseek
( pfinp, 0, SEEK_SET ) ;.

- Obtain current Offset in Bytes,


from Zero at beginning (Top) of File,
for eventual use as fseek Offset,
offs

ftell

( pfinp ) ;,

to save current Byte Offset to offs,


but -1 returned when not possible.

49

To C or not to C - Files And I/O (Input/Output) - Part 6


=========================================================
- 5/ File Position
Functions (2)

- Similarly to fseek, rewind and ftell,


Function allow changes in place of next access,
but in terms of File Pointer Absolute Value :
- fgetpos - Get Absolute Pos. (Pointer) in File.
One Argument following File Pointer,
which must be Long (Integer) Pointer,
to receive File Pointer Value,
like

irtc

fgetpos ( pfinp, fptr ) ;,

with Zero returned when Pos. obtained,


or a Non Zero Code otherwise.
- fsetpos - Set Absolute Pos. (Pointer) in File,
for instance to Value from fgetpos,
in effect allowing raw Level Access.
One Argument following File Pointer,
which must be Long (Integer) Pointer,
as provided by fgetpos Function,
containing Value to set Pointer to,
like

irtc

fgetpos ( pfinp, fptr ) ;,

with Zero returned when Pos. achieved,


or a Non Zero Code otherwise.

50

To C or not to C - Files And I/O (Input/Output) - Part 7


=========================================================
- 6/ File Status
Functions

- Functions allow tests against File states :


- feof

like

- Checks last Read or Write attempt,


effectively last File Data access,
left File Position at Bottom,
irtc

feof

( pfinp ) ;,

sending back Non Zero Code when so,


or Zero when not at Tail, or Error.
- ferror

like

- Checks status of last Data Access,


that is Record Read or Write attempt,
irtc

ferror

( pfinp ) ;,

giving Non Zero Code when failed,


or Zero when no error in Data I/O.
File Error State, and End Flag,
can be reset with clearerr Function,
called with clearerr ( file_ptr );,
but this not normally recommended,
unless confident problem resolved.
- fflush

like

- Force any Buffers to be written out,


that is, Data being sent to Hardware,
irtc

fflush

( pfout ) ;,

giving Error Code EOF when failed,


or Zero when Buffer(s) emptied out.

51

To C or not to C - Files And I/O (Input/Output) - Part 8


=========================================================
- 7/ I/O Categories
and Modes

- 8/ Raw Character
I/O Functions

- I/O Function allow Data exchange, with Files,


either a Byte (Character) at a time, or in Batch,
in Raw (Binary) and Formatted Modes with latter.
In Formatted Mode, Char. Strings can act as Files,
allowing Internal Conversions and Data movements.

- In Raw Character I/O, Data handled Byte by Byte,


getting or sending out Data via a Char. Variable.
- fgetc
getc
like

: Read
fgetc

1 Character from File,


(

"stdin"

) ;,

to pick 1 Byte (Char.) from stdin.


- fputc
putc
like

: Write 1 Character to File (at End),


fputc

( a,

"stdout" ) ;,

to send Character a to "stdout".


- getchar : As per fgetc ( "stdin"

) ;.

- putchar : As per fputc ( "stdout" ) ;.


- For all Character I/O, Integer Value may be given,
instead of Char. Variable, or Quoted Character,
and Integer Value of Bits in Byte, unsigned,
returned when operation successful, otherwise,
Zero or End of File (EOF) results.

52

To C or not to C - Files And I/O (Input/Output) - Part 9


=========================================================
- 9/ Raw Batch
I/O Functions

- In Raw or Binary Mode, Data handled as Arrays,


or Character Strings of consecutive Bytes (Block),
obtained off, or sent to File without conversion.
- fread

like

: Obtain Block of Bytes from File,


and assign them to Array, or String,
at Address given as First Argument,
fread

( pntr, itln, totl, file ) ;,

to pick Block of Length itln * totl,


of totl Array Items of Size itln,
assigned to Array at Address pntr.
Item Size and Total must be Integers,
and no Data conversions carried out.
- fwrite

like

: As per fread, but sending out Data,


so copying Array or String to File,
fwrite ( pntr, itln, totl, file ) ;,
to send Block used in above fread.

- Raw (Binary) I/O Functions return Total Items,


either obtained or sent, which, in case or Error,
becomes less than expected (totl) Total.

53

To C or not to C - Files And I/O (Input/Output) - Part 10


=========================================================
-10/ String Batch
I/O Functions

- In String Character I/O, Data handled with Arrays,


effectively getting or sending out Char. Arrays.
- fgets

like

: Read ( nn - 1 ) Characters off File,


or to an End of Line or End of File,
whichever comes first,
and append Null String Terminator,
after eventual End of Line or File,
fgets

( pntr, nn, file ) ;,

to fill Array at pntr from file.


- gets

like

: Read Characters from Standard Input,


to first End of Line or End of File,
and append Null String Terminator,
returning Number of Characters read,
fgets

( pntr

) ;,

to fill Array at pntr from stdin.


- fputs

like

: Write Chars. in Array or String,


to first Null which is not sent.
fputs

( pntr, file ) ;,

to send off pntr Array to file.


- puts

like

: Write Characters in Array or String,


to Standard Output, till first Null,
but send End of Line Mark instead,
puts

( pntr

) ;,

to send Array at pntr to stdout.

54

To C or not to C - Files And I/O (Input/Output) - Part 11


=========================================================
-11/ Formatted Batch
I/O Functions

- In Formatted Mode, Data conversions possible,


with assignments to some Variables when reading,
or from Values of some Variables, or Strings,
when writing, in both cases via special Flags,
one for each Variable in Data List.
- fscanf

: Extract Data at current File Position,


where Data Items must be Pointers :

fscanf

( FILE, "Consts and Format", *List ) ;,

like

fscanf

( fileptr,
"%d %d", *dat1, *dat2 ) ;,

- fprintf : Send Data at End of File :


fprintf
like

- sscanf

( FILE, "Consts and Format", List


fprintf ( fileptr,
"%d %d",

dat1,

) ;,

dat2 ) ;,

: As per fscanf but off Char. String,


given as Arg. 1, instead of File.

- sprintf : As per fprintf but to Char. String,


given as Arg. 1, instead of File.

55

To C or not to C - Files And I/O (Input/Output) - Part 12


=========================================================
-12/ Data Format
Descriptors (1)

- In Formatted Mode, describe each Variable Value,


and its position in Record sent or read in File,
where Verbatim Text can be intermixed.
Descriptors consist of Percent Prefix,
then one of more Code letters and digits,
telling Data Type (required) and Field layout :
Type Codes : c
d

= Single Character,
= Decimal Integer,

e, E = Floating Point Number,


with Exponent,
f
= Floating Point Number,
without Exponent,
g, G = Floating Point Number,
shorter of e or f,
i
o
u
x

=
=
=
=

p
s

= Pointer (Address) Value,


= Character String,

= Percent Sign itself.

56

Decimal Integer,
Octal Integer,
Unsigned Decimal Integer,
Hexadecimal Integer,

To C or not to C - Files And I/O (Input/Output) - Part 13


=========================================================
-12/ Data Format
Descriptors (2)

- Field layout set by 3, all optional Flags :


Sign Codes : +

0
-

= Prepend Plus Sign,


to any Positive Number,
= Prepend Space,
to any Positive Number,
= Zeros, not Spaces,
leading small Numbers,
= Left Align Numbers.
Minus signs always mark
all Negative Numbers.

Size Codes : w.p

w
.p
Long Codes : l
L
Examples

= Field Width at least w,


at least p Digits sent,
= As above, without p,
= "
" ,
"
w.
= Long Octal, Int. or Hex,
= Long Float (Double).

: %+6.3d = Sign, at least 6 Chars,


and at least 3 Digits,
% 10Lf = Minus or Space,
and 10 Space Double,
so 9 Digit and Dec. Point,
%.12s

= First 12 Chars of String.

Special facilities exist to restrict input,


using Character Sets in Square Brackets ([ ]),
to only those Characters. Can be confusing,
and best left to special Filter Function.

57

To C or not to C - Files And I/O (Input/Output) - Part 14


=========================================================
-13/ Character String
Functions
(1)

- String Copy, comparison and searches possible,


and also length queries and data transformations.
- strcat

like

: Concatenates two Strings,


just like appending Arg. 2 to Arg. 1,
strcat

( chst1, chst2 ) ;,

where chst1, chst2 Char. Pointers.


- strcmp

like

: Compares two Character Strings,


returning Zero when both same,
Negative when Arg. 1 less than Arg. 2,
in Systems lexicographical terms,
Positive when the reverse.
strcmp

( chst1, chst2 ) ;,

to test String chst1 versus chst2,


relative to Collating Sequence.
- strcpy
like

: Copy Second String Arg. to First one,


strcpy

( chst1, chst2 ) ;,

to copy chst2 Data over to chst1.


- Length limited Functions for above tasks exist,
with strn Prefixes, to pick at most nn Chars,
as set by third (Integer) Arg. to Syntax above,
like

strncat ( chst1, chst2, nn ) ;,


strncmp ( chst1, chst2, nn ) ;,
strncpy ( chst1, chst2, nn ) ;,
to use only nn Chars. from chstr2.

58

To C or not to C - Files And I/O (Input/Output) - Part 15


=========================================================
-13/ Character String
Functions
(2) - strchr
like

: Get Address of a Character in String,


strchr

( chst1, c ) ;,

for Address of first c in chst1,


or a Null when no Char. c found.
- strlen

like

: Obtain Data Length in String,


not counting Terminating Null,
strlen

( chst1

) ;,

to get Total Chars. up to first Null,


in String at Address Pointer chst1.
- strpbrk : Get Address of first of a Char. Set,
like

strpbrk ( chst1, chst2 ) ;,


for Addr. of first Char. from chst2,
whatever its position, in chst1.

- strspn
like

: Length in String with Chars. in Set,


strspn

( chst1, chst2 ) ;,

for Length of chst1 portion,


with only Chars. found in chst2,
or Pos. of first Char. not in chst2,
with 1 subtracted.
Use strcspn to get same as strspn,
but considering Chars. not in a Set.
- strstr
like

: Check one String found in another,


strstr

( chst1, chst2 ) ;,

for Addr. of first chst2 in chst1,


or a Null when chst2 not in chst1.

59

To C or not to C - Files And I/O (Input/Output) - Part 16


=========================================================
-14/ I/O Redundancies

- Lots of redundancy, and Formats in I/O Functions,


so better to use File (f Prefixed) Functions,
even for Standard Channels, to retain consistency.
Also, invoke only one of stdou and stderr,
to avoid eventual synchronisation problems,
which equates scanf and printf to :
fscanf
fprintf
like

( stdin, "Consts, Format", *List ) ;,


( stderr, "Consts, Format", List ) ;,
fscanf

( stderr,

%ld",

&irtc ) ;.

fprintf ( stderr,
"\nRet = %ld",

irtc ) ;.

Note even with Standard Channel (stdin),


Data input Variable(s) List must be Pointers.
- Note fscanf locks in loop with invalid Numerics,
so Input Data as char String(s),
then invoke sscanf against Validated Data.
-15/ Data Validation

- Numeric Data first Input to Character Strings,


then Converted, once checked for validity.
In File I/O Example below, Data file scanned,
for expected Double Precision (double) contents.
Additionally, basic File Statistics computed.
Each Field checked to hold Numerics,
and to contain only valid Characters.
When no more Fields, check File Pointer at End,
then Rewind File for eventual use in calling Unit.

60

To C or not to C - Files I/O Example - Part 1


=============================================
/* Function : Scan and Basic Statistics for Real Data File
* *******************************************************
*
* Function reads through Data File passed in Open State at call,
* checking all Data of expected Floating Point (Real) Format,
* and then computing Basic Statistics (Average, Sample Variance,
* Minimum and Maximum), of which Addresses part of Call Args.
*
* End of File consistency check carried out, before rewinding,
* so File Pointer returned as found, at beginning of Data File.
* When no more Data can be read, but File not found at Bottom,
* direct Termination of Program, with Negative Code to System.
*
* When File not found at beginning Offset before Data checks,
* warning issued, and Rewind to Top then attempted by Function.
* Message sent to Standard Error Channel, at first Data Error,
* or when Rewind fails, before ending with Negative Ret. Code.
*
* Arguments :
Values
from Calling Unit :
*
*
- 11/ *pfinp
= Data File Pointer,
*
- 12/ *descrip = String for File description,
*
to identify File in Messages.
*
*
Pointers
for Values set in Function :
*
*
- 21/ *tot_val = Count of Values in File,
*
*
- 22/ *val_min = Minimum Value found in File,
*
- 23/ *val_max = Maximum
"
"
"
" ,
*
- 24/ *avg_val = Average of File Data Values,
*
- 25/ *var_val = Sample Variance of File Data,
*
*
- 26/ **mess
= Error Message Address.
*
* Function conforms to ANSI Standard C definition,
* but for "Traditional" (K. and R. C) style, sole change,
* in Entry Line, to Arg. specifications before opening {.
*/

61

To C or not to C - Files I/O Example - Part 2


=============================================
/* Constant and Library Directives :
* --------------------------------*/
/* Constant, for Input String Length and Messages.
*/
#define

LL

80

/* Standard C Libraries for Input/Output.


*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

62

To C or not to C - Files I/O Example - Part 3


=============================================
/* Function : Scan Real Data File, for Format and Range checks
* ----------------------------------------------------------*/
int

fckdou

( FILE
char

*pfinp
,
*descrip ,

long

*tot_val ,

double
double
double
double

*val_min
*val_max
*avg_val
*var_val

char

**mess

,
,
,
,
)

{
/*
*
*/

Local Variables for File Check Function :


-----------------------------------------

/*
*/

Error Message and Data Input Strings.

char

errms
inpt

/*
*
*
*/

Local Variables for File Statistics,


namely Sum and Sum of Squares of Data Values,
current Value and transient for computations.

double

in_sum
in_ssq
in_val
tv_dou

/*
*/

Return Code for Local I/O Function Calls.

int

irtc

[LL] ,
[LL] ;

,
,
,
;

63

To C or not to C - Files I/O Example - Part 4


=============================================
/* Executable Part for Data File Check Function :
* ---------------------------------------------*/
/* Find out Current (Byte) Offset in Data File,
* which should be Zero when at Top, as expected,
* and when different, report with Message, then,
* attempt Rewind of File to beginning of Data.
*/
if

( irtc

= ftell ( pfinp ) != 0

fprintf

( stderr,
"\n\nData File not at start (Zero Offset)" );

fprintf

( stderr,
"\n\nData File repositioned to beginning"

if

) {

);

( irtc

= fseek ( pfinp, 0L, SEEK_SET ) != 0 ) {

fprintf

( stderr,
"\n\nPre-check File Rewind failed" );

return

( 01

);

}
}
/* Initialise Total (number of) Values Input from File.
*/
*tot_val

= 0;

64

To C or not to C - Files I/O Example - Part 5


=============================================
/* Request and Check single String, and check valid Number,
* exiting verification process when error or end of file.
*/
while ( irtc = fscanf

( pfinp, "%s", inpt

) == 1

) {

/* First, get Pointer to First Digit in Data String,


* in effect checking some Digits present in Data,
* and implying Value not Numeric when no Digits found.
*/
if

( strpbrk

( inpt, "0123456789" ) == NULL

) {

sprintf

( errms,
"%s : Non numeric data at value %ld",
descrip, ( *tot_val + 1 )
);

*mess
return

= errms;
( 11
);

}
else {
/* Once (some) Digits found in Input Data String,
* check no invalid Characters mixed in, that is,
* no non Digits, Sign, Dec. Point, Space or Tabs.
*/
if

strspn ( inpt, "0123456789-. \t" )


< ( strlen ( inpt ) - 1
)

) {

sprintf

( errms,
"%s : Illegal chars in value %ld",
descrip, ( *tot_val + 1 )
);

*mess
return

= errms;
( 12
);

}
}
/* while Loop continued on next Page ...
*/

65

To C or not to C - Files I/O Example - Part 6


=============================================
/* while Loop continued from previous Page ...
*/
/* Valid Numeric Data converted to (Double) Floating Point.
*/
sscanf

( inpt, "%lf", &in_val );

/* With valid numeric value, increment total, then,


* add to sum and squares sum, and check for Range extremes,
* but when only on First Value in File, initialise these.
*/
(*tot_val)++;
if

( *tot_val
in_sum
in_ssq
if
if

( in_val
( in_val

> 1

) {

+= in_val;
+= in_val

* in_val;

> *val_max )
< *val_min )

*val_max = in_val;
*val_min = in_val;

}
else {
in_sum
in_ssq

= in_val;
= in_val

*val_max

= *val_min = in_val;

}
}

66

* in_val;

To C or not to C - Files I/O Example - Part 7


=============================================
/* Once all Data input, must be at end of File.
* Direct Termination when not, as File inconsistency.
*/
if

( irtc

= feof

( pfinp ) == 0

fprintf ( stderr,
"\n\nData File not at end after all Input\n"
exit

( -1

) {

);

);

}
/* Once all Data Points input, rewind Data File,
* by placing pointer, with offset zero, at top of File.
* When Error, send Error signal back to calling Routine,
* which may reattempt Rewind, or Terminate Program.
*/
if

( irtc

= fseek ( pfinp, 0L, SEEK_SET ) != 0

fprintf ( stderr,
"\n\nData File Rewind error after Data Check"
return

( 21

);

67

) {

);

To C or not to C - Files I/O Example - Part 8


=============================================
/* Compute Mean and Sample Variance of values in Data File.
*/
if

( *tot_val

> 0

) {

tv_dou

= (double) *tot_val;

*avg_val

= ( in_sum / tv_dou

);

/* Variance only computed when several Values in File.


*/
if

( *tot_val

> 1

*var_val

= (

) {
(

in_ssq
- tv_dou * *avg_val * *avg_val )
/ (
tv_dou - 1.0
) );

}
else {
*var_val

= 0.0;

}
}
else {
/* All File Statistics Zero when no Data in File.
*/
*val_max

= *val_min
= *avg_val
= *var_val

= 0.0;

}
/* Return to calling Routine once File processed.
*/
return

( 0

);

68

To C or not to C - Program Example - Part 1


============================================
/* Program reformats Yield Curve Points Data.
*
* Yield Curve Data from U.S. Federal Reserve Board shows Dates,
* and gives associated Maturities of U.S. Government Bonds (debt),
* but only in computationally inconvenient plain text Headings.
* So, delete those Dates and write out Maturities in Output File,
* in numeric decimal format and preceding each interest rate Value,
* as read in second Input File. Heading Lines Input also cleared.
*
* Program, first passes through Data to check Format as expected,
* operation being carried with special Check Routine fckdou,
* which also presents basic Data Statistics when all Data valid.
*
* Output then in form usable by graphics or statistical utilities.
*
* Files
: -1/ Input (Federal Reserve) Interest Rate Data,
*
-2/ Output reformatted Maturities and Rates Data,
*
-3/ U.S. Bond Maturities Data (Input).
*
* Routines : fckdou = Pass and Check Double Precision Data,
*
and compute basic File Statistics.
*
* Standard : Program written as per ANSI (1989) C Standard,
*
but so only Entry (main) Statement needs changing,
*
to compile under "Traditional" ("K & R") C Style.
*/

69

To C or not to C - Program Example - Part 2


============================================
/*
*
*/

Definitions and Libraries :


---------------------------

/*
*/

Default Input, Maturities and Output File Names.

#define
#define
#define

DEF_INP "ycvinp.dat"
DEF_MAT "ycvmat.dat"
DEF_OUT "ycvout.dat"

/*
*/

Default Input and other Text String Length (Bytes).

#define

LL

/*
*/

Standard C Programming Libraries.

#include
#include
#include
#include
/*
*/

80

<math.h>
<stdio.h>
<stdlib.h>
<string.h>
Called Functions Prototypes (Headers).

#include "fckdou.h"

70

To C or not to C - Program Example - Part 3


============================================
/* Program : Yield Curve Data reformat
* ***********************************
*/
void main ( int
char
{

argc
,
*argv [] )

/* File Pointers for Input, Maturities and Output.


*/
FILE

*pfinp
*pfmat
*pfout

,
,
;

/* File Name Strings for Input, Maturities and Output.


*/
char

finp_name [LL] ,
fmat_name [LL] ,
fout_name [LL] ;

/* Generic File Name Input, Prompt Reply and Error Strings.


*/
char

*fptr_name ,
inpt
*mess

[LL] ,
= "" ;

71

To C or not to C - Program Example - Part 4


============================================
/* Maturities Array Pointer and individual Yield Variable.
*/
double

*mat
yel

,
;

/* Input (Interest Rate) Data File Basic Statistics,


* with Average, Maximum and Minimum and Sample Variance.
*/
double

avg_mat
max_mat
min_mat
var_mat

,
,
,
;

/* Generic Function Return Code (for checking for Errors).


*/
int

irtc

/* Generic Loop Counter, Total Maturities and Yield Curves.


*/
long

ii

tot_mat
tot_yel

= 0 ,
= 0 ;

72

To C or not to C - Program Example - Part 5


============================================
/* Mark beginning of execution.
*/
fprintf ( stderr, "\n\nYield Curve Data reformat"
);
fprintf ( stderr,
"\n*************************"
);
fprintf ( stderr,
"\nTo Quit at any point Hit CTRL/C" );
/* When first Command Argument, Input Data File Name.
* Otherwise, request name Entry and check for Default.
*/
if

( argc

> 1

) {

fptr_name = argv [1];


}
else {
fprintf
fprintf

( stderr, "\n\nEnter Input Data File Name "


);
( stderr,
"\n
(Default = "DEF_INP") : " );

fgets

( inpt, LL, stdin );

if

( strlen

( inpt ) <= 1 ) {

fptr_name = DEF_INP;
}
else {
fptr_name = strtok ( inpt, " \t\n" );
}
}
/* Assign Input File Name off Generic Name Input String.
*/
sprintf

( finp_name, "%s", fptr_name );

73

To C or not to C - Program Example - Part 6


============================================
/* When second Command Argument, Output Data File Name.
* Otherwise, request name Entry. Then open named File.
*/
if

( argc

> 2

) {

fptr_name = argv [2];


}
else {
fprintf
fprintf

( stderr, "\n\nEnter Output Data File Name "


);
( stderr,
"\n
(Default = "DEF_OUT") : " );

fgets

( inpt, LL, stdin );

if

( strlen

( inpt ) <= 1 ) {

fptr_name = DEF_OUT;
}
else {
fptr_name = strtok ( inpt, " \t\n" );
}
}
/* Assign Output File Name off Generic Name Input String.
*/
sprintf

( fout_name, "%s", fptr_name );

74

To C or not to C - Program Example - Part 7


============================================
/* When third Command Argument, Maturities Data File Name.
* Otherwise, request name Entry. Then open named File.
*/
if

( argc

> 3

) {

fptr_name = argv [3];


}
else {
fprintf
fprintf

( stderr, "\n\nEnter Maturities File Name "


);
( stderr,
"\n
(Default = "DEF_MAT") : " );

fgets

( inpt, LL, stdin );

if

( strlen

( inpt ) <= 1 ) {

fptr_name = DEF_MAT;
}
else {
fptr_name = strtok ( inpt, " \t\n" );
}
}
/* Assign Maturities File Name off Generic Name Input String.
*/
sprintf

( fmat_name, "%s", fptr_name );

75

To C or not to C - Program Example - Part 8


============================================
/* Attempt opening Input Data File,
* with immediate termination when Error.
*/
if

( ( pfinp = fopen ( finp_name, "r" ) ) == NULL

) {

fprintf
fprintf

( stderr, "\n\nInput Data File Open failed,"


( stderr,
" check File exists\n"

);
);

exit

( 01

);

}
/* Attempt opening Output Data and Maturities Files,
* with Input closure and immediate termination when Error.
*
* Once Termination Block entered, Input File closed directly,
* while Output File needs no closure as opening failed.
*/
if

( ( pfout = fopen ( fout_name, "w" ) ) == NULL

) {

fprintf
fprintf

( stderr, "\n\nOutput Data File Open failed," );


( stderr,
" check creation possible\n"
);

fclose

( pfinp );

exit

( 02

);

76

To C or not to C - Program Example - Part 9


============================================
/* Attempt opening Input Maturities File,
* with other Files closed and immediate termination when Error.
*/
if

( ( pfmat = fopen ( fmat_name, "r" ) ) == NULL

) {

fprintf
fprintf

( stderr, "\n\nMaturities File Open failed,"


( stderr,
" check File exists\n"

);
);

fclose
fclose

( pfinp );
( pfout );

exit

( 03

);

}
/* Scan and check Maturities (expected in Years) before input,
* with outside Function (all values must be valid numbers).
* Total values, min. max. average and variance returned, but,
* Output message and quit when non Zero Code flags an Error.
*/
irtc = fckdou ( pfmat
, "Maturities File",
&tot_mat, &min_mat, &max_mat,
&avg_mat, &var_mat, &mess

);

if

) {

( irtc

!= 0

fprintf
fprintf

( stderr, "\n\nMaturities File Data error : " );


( stderr, "\n\n%s",
mess
);

fclose
fclose
fclose

( pfinp );
( pfout );
( pfmat );

exit

( 04

);

77

To C or not to C - Program Example - Part 10


============================================
/* Get Memory for Maturities.
*/
if

( ( mat = (double *)
malloc
( tot_mat * sizeof (double) ) ) == NULL ) {
fprintf

( stderr, "\n\nMaturities Memory Alloc. error\n" );

fclose
fclose
fclose

( pfinp );
( pfout );
( pfmat );

exit

( 11

);

}
/* Copy valid Maturities from File to Local Array.
*
* Note use of Array Notation with Pointer to Array.
*/
for ( ii = 0;
if

ii < tot_mat; ii++

) {

( ( irtc

= fscanf ( pfmat, "%lf", &mat [ii] ) ) != 1

fprintf

( stderr,
"\n\nMaturity Value No. %ld input error\n",
( ii + 1 )
);

fclose
fclose
fclose

( pfinp );
( pfout );
( pfmat );

exit

( 12

);

}
}

78

) {

To C or not to C - Program Example - Part 11


============================================
/* Once Data held in array, release Maturities File.
*/
if

( ( irtc

= fclose ( pfmat ) ) == EOF

) {

fprintf

( stderr, "\n\nMaturities File close failed\n"

);

fclose
fclose

( pfinp );
( pfout );

exit

( 13

);

}
/* Present Maturities summary after successful scan and Input.
*/
fprintf
fprintf

( stderr, "\n\nMaturities Summary :" );


( stderr,
"\n--------------------" );

fprintf

( stderr, "\n\nFile
: %s
",
fmat_name
);
( stderr,
"\nTotal Values : % 6ld",
tot_mat
);

fprintf

/* When no valid Maturities, exit with error message.


*/
if

( tot_mat <= 0

) {

fprintf

( stderr, "\n\nNo valid Maturity Values found\n" );

fclose
fclose

( pfinp );
( pfout );

exit

( 14

);

79

To C or not to C - Program Example - Part 12


============================================
/* Bypass Header Lines in Input Yield Data File.
*/
for ( ii

= 0; ii < 2; ii++

irtc

) {

= ;

while ( irtc != \n
irtc

= fgetc

) {
( pfinp );

}
}
/* Pick successive Yield Curves (one per Line).
*
* End of File used as Loop repeat Condition,
* but exit likely with trying Input of fresh Line,
* so at stage of discarding unwanted Date Field.
*/
while ( irtc

!= EOF

) {

/* Bypass DD/MM/YY Date Field, by picking Char. String,


* which Date Field represents due to Slashes (/) present,
* and not assigning it, thus merely advancing File Pointer,
* ready to read in Numeric (Interest) Values following.
* Hitting End of File forces File Input Loop to end.
*/
if

( ( irtc

= fscanf

( pfinp, "%*s" ) ) == EOF ) {

break;
}
/* Loop (while) continued ...
*/

80

To C or not to C - Program Example - Part 13


============================================
/* ... Yield Curves processing, continued Loop (while).
*/
/* Pick each Yield Curve Data Point from File,
* and copy Maturity and Yield to Output File.
*/
for ( ii
if

= 0; ii < tot_mat; ii++

) {

( ( irtc

= fscanf ( pfinp, "%lf", &yel ) )

fprintf

( stderr,
"\n\nYield Curve point input error\n"

fclose
fclose

( pfinp );
( pfout );

exit

( 21

( ( irtc

= fprintf ( pfout,
"% 6.2lf % 6.2lf
mat [ii], yel

!= 1

) {

);

);

}
if

",
) ) < 0

) {

fprintf

( stderr,
"\n\nYield Curve point output error\n" );

fclose
fclose

( pfinp );
( pfout );

exit

( 22

);

}
}
/* Loop (while) continued ...
*/

81

To C or not to C - Program Example - Part 14


============================================
/* ... Yield Curves processing, continued Loop (while).
*/
/* Output Carriage Return on Completed Yield Curve Line.
*/
if

( ( irtc

= fprintf ( pfout, "\n" ) )

fprintf

( stderr,
"\n\nYield Curve Line end output error\n"

fclose
fclose

( pfinp );
( pfout );

exit

( 23

< 0

) {

);

);

}
/* Once Current Yield Curve successfully written to Output,
* add to Total Curves processed (and Current Curve number).
*/
tot_yel++;
}

82

To C or not to C - Program Example - Part 15


============================================
/* Once Yield Curve Data copied to output with Maturities,
* close and (thus) release Input Data and Output Files.
*/
if

( ( irtc

= fclose

( pfinp ) ) == EOF

) {

fprintf

( stderr, "\n\nInput

fclose

( pfout );

exit

( 31

( ( irtc

= fclose

fprintf

( stderr, "\n\nOutput File close failed\n" );

exit

( 32

File close failed\n" );

);

}
if

( pfout ) ) == EOF

) {

);

}
/* Present Data summary after successful copy to Output File.
*/
fprintf
fprintf

( stderr, "\n\nInput Yield Curve Data Summary :" );


( stderr,
"\n--------------------------------" );

fprintf

( stderr, "\n\nInput File : %s


finp_name
( stderr,
"\nOutput File : %s
fout_name
( stderr,
"\nTotal Lines : % 6ld
tot_yel

fprintf
fprintf

",
);
",
);
",
);

/* Send completion message before exit.


*/
fprintf

( stderr, "\n\n**** Reformat completed ****\n\n" );

83

To C or not to C - Program Example - Part 16


============================================
Input (Interest Rates in per cent) Data File to Program :
---------------------------------------------------------

Date
01/02/91
01/03/91
01/04/91
01/07/91
01/08/91
01/09/91
01/10/91
01/11/91
01/14/91
01/15/91
01/16/91
01/17/91
01/18/91
01/22/91
01/23/91
01/24/91
01/25/91
01/28/91
01/29/91
01/30/91
01/31/91

3-mo
6.66
6.64
6.73
6.71
6.64
6.44
6.40
6.34
6.24
6.23
6.22
6.30
6.24
6.24
6.32
6.31
6.35
6.44
6.41
6.39
6.37

TREASURY YIELD CURVE


6-mo
1-yr
2-yr
6.73
6.74
7.08
6.71
6.72
7.08
6.82
6.83
7.17
6.84
6.84
7.20
6.74
6.75
7.15
6.61
6.68
7.10
6.57
6.64
7.14
6.55
6.62
7.14
6.47
6.60
7.18
6.44
6.60
7.16
6.46
6.61
7.21
6.56
6.66
7.19
6.51
6.61
7.14
6.48
6.59
7.13
6.49
6.59
7.08
6.47
6.54
7.04
6.52
6.61
7.10
6.55
6.64
7.12
6.55
6.59
7.10
6.53
6.56
7.07
6.49
6.51
7.05

RATES FOR JAN


3-yr
5-yr
7.30
7.59
7.27
7.56
7.37
7.65
7.43
7.75
7.39
7.74
7.46
7.81
7.39
7.76
7.40
7.79
7.44
7.82
7.43
7.79
7.47
7.83
7.42
7.71
7.38
7.68
7.37
7.70
7.36
7.67
7.32
7.61
7.36
7.67
7.38
7.67
7.35
7.64
7.34
7.64
7.30
7.62

84

1991
7-yr
7.90
7.86
7.94
8.04
8.06
8.12
8.02
8.06
8.09
8.07
8.09
7.93
7.92
7.94
7.91
7.88
7.93
7.93
7.90
7.90
7.89

10-yr
7.97
7.93
8.02
8.13
8.16
8.25
8.16
8.20
8.23
8.22
8.24
8.05
8.03
8.07
8.04
8.00
8.06
8.06
8.03
8.05
8.03

30-yr
8.14
8.11
8.20
8.32
8.37
8.46
8.37
8.39
8.41
8.41
8.40
8.18
8.17
8.23
8.21
8.18
8.24
8.23
8.20
8.23
8.21

To C or not to C - Program Example - Part 17


============================================
Input (Bond) Maturities (in Years) Data File to Program :
--------------------------------------------------------0.25
0.5
1
2
3
5
7
10
30
Output (Maturity and Rate Pairs) Data from Program
(only top 4 Lines shown, split after 3 Year Point for clarity) :
----------------------------------------------------------------------0.25

6.66

0.25

6.64

0.25

6.73

0.25

6.71

0.50
5.00
0.50
5.00
0.50
5.00
0.50
5.00

6.73
7.59
6.71
7.56
6.82
7.65
6.84
7.75

1.00
7.00
1.00
7.00
1.00
7.00
1.00
7.00

6.74
7.90
6.72
7.86
6.83
7.94
6.84
8.04

85

2.00
10.00
2.00
10.00
2.00
10.00
2.00
10.00

7.08
7.97
7.08
7.93
7.17
8.02
7.20
8.13

3.00
30.00
3.00
30.00
3.00
30.00
3.00
30.00

7.30
8.14
7.27
8.11
7.37
8.20
7.43
8.32

To C or not to C - Program Example - Part 18


============================================
Output Log (as sent to Screen) from Program :
--------------------------------------------Yield Curve Data reformat
*************************
To Quit at any point Hit CTRL/C
Enter Input Data File Name
(Default = ycvinp.dat) : ../msc/ycv/y91/ycv9101.dat
Enter Output Data File Name
(Default = ycvout.dat) :
Enter Maturities Data File Name
(Default = ycvmat.dat) : ../msc/ycv/matur09.dat
Maturities Summary :
-------------------File
: ../msc/ycv/matur09.dat
Total Values :
9
Input Yield Curve Data Summary :
-------------------------------Input File : ../msc/ycv/y91/ycv9101.dat
Output File : ycvout.dat
Total

Lines :

21

**** Reformat completed ****

86

To C or not to C - Program Example - Part 19


============================================
Observations, from top down through Source Code :
------------------------------------------------- 1/ Some Comments at Top can describe process.
Also good to give details of :-Input and Output (Disk) Files.
-Called Routines (Functions in C),
with Language when not C.
-Reports and Error or Run Logs.
-Standards (say ANSI) and limitations.
- 2/ After 1/ above, and before body of C Code itself in Source File,
set Defaults (File Names, Constants) with #define Directives,
for Pre-Compiler to replace all instances in Source Code proper,
an easy way to tell reader about them and eventually change them.
C Naming convention for Constants is Upper Case.
like
#define LL 80, sets up LL Line Length Constant,
so
if ( ii < LL )
becomes if ( ii < 80 ) before Compilation.
- 3/ Follow 1/ and 2/ above with #include Pre-Compiler Directives,
for all Libraries and Function Headers (prototypes),
Standard ones between < > Angled Brackets,
User ones (usually Functions) between " " Double Quotes.
like

#include <math.h>
#include "fckdou.h"

(Standard Mathematical Library),


(User Called Sub Program
).

- 4/ Include Argument Count (int argc) and Array (char *argv []),
in main Statement, so it takes a uniform syntax.
- 5/ Put all Data declarations at Top of Source Code,
best in Alphabetical Order of Types, and Names within Type,
Can Present one variable per line, in Column fashion,
Pointers * standing out, Array Sizes or Initial Values on Right.
Avoid Single Letter Names, overly long ones, clashes with Language,
like int if, and, possibly, common English and Mathematical terms.
Can be useful for first Letter to indicate Type (say i for int).

87

To C or not to C - Program Example - Part 20


============================================
- 6/ Mark start of Executable Statements with Screen Message or Header,
so user knows which Program Unit currently running.
- 7/ All Screen Output via fprintf and stderr,
so no Buffer caused disordering, likely when stdou also used,
or System generated Error Messages sent as well as Programs.
Likewise, all Screen Input via fscanf and stdin,
so common Syntax with Disk File I/O in all scenarios.
- 8/ Check Arguments (char Array *argv [ ] in main) in Order.
stopping process when no more (tested using argc Value).
- 9/ Request File Names in consistent way, with Prompt and Defaults.
When Default Disk Files used, indicate their Names,
so user can easily find them outside scope of Program.
-10/ All File fopen Calls should test Outcome (FILE Pointer NULL),
in following Statement, or encapsulating ( pntr = fopen ) in if.
Same for all Memory Allocations (calloc, malloc, realloc).
-11/ Validate all Numeric Variable Input, via char String Input,
and Copy off String to Numeric Fields with sscanf,
so Numeric % fscanf Descriptors not used when risk or Errors.
-12/ Check Outcome of Data File Output (write operations),
where Return Code of fprintf gives Number of Items sent out.
-13/ Present Screen and File ASCII Input/Output as laid in File,
that is one String of fprintf "... output ..." per Line,
and isolate Variable Names on separate Line at Bottom.
-14/ Release Disk File (with fclose) as soon as no more I/O to them,
and Check Outcome (EOF Return Code), at least for Output Files.

88

To C or not to C - Program Example - Part 21


============================================
-15/ Can use while ( ( irtc = fscanf ( ... ) ) != EOF ) { ...,
to run through Data File, leaving Loop upon hitting End of File.
-16/ Avoid Statements not controlling Loop Start or End in Loop Entries.
Like for ( ii = 0, xx = 0.0; ii < 100; ii++ ) { ....
Better to Nest Loops than use many Control Variables on same Loop.
-17/ Avoid switch/case : blocks, use if/else sequences instead.
Former requires Integer Variables, and omission of end break;,
after each case : Clause means next one entered, and so on.
-18/ Write any implicit Casts explicitly to clarify any conversions.
Like dres = dval * (double) ll; for double * long to double.
-19/ Give basic feedback (Results summary) Report at completion,
and send End of Program Note to Screen, to inform user of Exit.
-20/ Use common form for all Aborts, possibly calling Function,
passing it Message and Program (name in argv [0] at least) Details.
-21/ Indent Code at each Level of Nesting,
by 4 or 6 Spaces, not Tabs as these expand in non standard manner.
-22/ Space out Code Keywords, Symbols, Operators and Variable Names,
especially in Calculations, which can be spread over several Lines.
-23/ Shift Code fragments of potential value elsewhere to Functions,
unless too short (below 10 to 15 Statements) to warrant complexity.

89

To C or not to C - Program Example - Part 22


============================================
General Guidelines :
-------------------- 1/ Use consistent Style and Syntax,
in effect set up a C Coding Paradigm,
to minimise risks or errors and achieve clear, easy to read Code.
- 2/ Small (single or few Characters) Symbols can have great impact,
so space out items like ( ), { }, or Arithmetic Operators,
also enclosing secondary Calculations in nested Brackets.
- 3/ Use only a subset of Statements,
even at cost of more Source Code (but not necessarily less speed),
and keep them to their simplest form (like Loops with one Variable).
- 4/ Split Large Programs, or computations of potential outside use,
to separate Sub-Programs (Functions), unless very small.
- 5/ Avoid Extensions, and use one or other of ANSI Standard,
or K & R ("traditional" C) throughout a Program Module.
- 6/ Be generous with Comments.

90

TO C OR NOT TO C, THE LITERATURE


********************************
By the yardstick of numbers, the C literature is well endowed. Alas,
its scope hasnt quite expanded as far as the languages use. Most so
called general books present a view more suited to systems programmers
or database designers than to commercial or scientific applications. An
inordinate amount of pages explain linked lists, of little use in most
cases, and not many detail how to handle multi dimensional arrays.
Likewise, few titles suggest a simplified approach to programming in C,
where some performance and subtlety is sacrificed to legibility.
Still, it comes very useful to get a solid introductory tome, which
includes a formal list of the many functions in the standard libraries.
A Book on C (Kelly A.L. & Pohl I.) has proved quite useful.
The tome by H. Shildt, C: The Complete Reference (4th Edition),
has attracted some fine reviews, and seems to keep selling well.
However, the best remains in my mind the C Primer Plus by Prata,
with excellent explanations and examples on multi dimensional Arrays.
The Microsoft Code Complete by McConnell makes afine read on good
programming practise, and has attracted excellent reviews, from even
readers not particularly fanatical about its publisher. Discussing C,
Fortran, Pascal and generalities, Imperative Programming Languages,
the second volume of the Handbook of Programming Languages set,
offers an interesting discussion of the merits and faults in C,
together with a review of its development and usage. Well worth a
read for those after more than mere ability to write C Programs.

91

Some C (Book) Titles


======================
General Introductions and Descriptions :
---------------------------------------N. Barkakati,
The Waite Groups Microsoft C Bible (3rd Edition),
Howard W. Sams & Co. (Mc Millan), ISBN 0-672-22736-3, 1990.
A.L. Kelly, I. Pohl I.,
A Book on C, Programming in C (4th Edition),
Benjamin/Cummings Publishing Co., ISBN 0-2011-8399-4, 1997.
B.W. Kernighan, D.M. Ritchie,
The C Programming Language (2nd Edition),
Prentice Hall, ISBN 0-13-110362-8, 1988.
P. Prinz, T. Crawford,
C in a Nutshell,
OReilly & Associates, ISBN 0-596-00697-7, 2005.
P. Prinz, U. Kirch-Prinz,
C Pocket Reference,
OReilly & Associates, 0-596-00436-2, 2002.
S. Oualline,
Practical C Programming (3rd Edition),
OReilly & Associates, ISBN 1-56592-306-5, 1997.
S. Prata,
C Primer Plus (4 th Edition, 5th coming),
Howard W. Sams & Co. (Mc Millan), ISBN 0-672-32222-6, 2001.
H. Shildt,
C: The Complete Reference (4th Edition),
Osborne Mc Graw Hill, ISBN 0-07-212124-6, 2000.
C.L. Tondo, S.E. Gimpel,
The C Answer Book (2nd Edition),
Prentice Hall, ISBN 0-13-028277-4, 1988.

92

For General Programming and Interest :


-------------------------------------W. Brainerd, R. Cytron, R.E. Griswold, G. Grotzinger,
D.M. Ritchie, S. Summit,
Handbook of Programming Languages (P.H. Salus Editor),
Volume II, Imperative Programming Languages,
Macmillan Technical Publishing, ISBN 1-57870-009-4, 1998.
S. McConnell,
Code Complete (2nd Edition),
Microsoft Press, ISBN 0-735-61967-0, 2004.

93

Potrebbero piacerti anche