Title: Introduction to C Programming Module 5 C Stream I/O and Exception Handling
1Introduction to C ProgrammingModule 5 C
Stream I/O and Exception Handling
- Yaodong Bi, Ph.D.
- Department of Computing Sciences
- University of Scranton
- (717)941-6108
- bi_at_cs.uofs.edu
2Outline
- Module 1 - An Overview of C and OO Programming
- Module 2 - Classes and Operator Overloading
- Module 3 - Inheritance and Dynamic Binding
- Module 4 - Function and Class Templates
- Module 5 - C Stream I/O and Exception Handling
3Review of Module 4
- Function Templates
- Function Template Definition
- Function Template Instantiation
- Template Explicit Specialization
- Overloading Function Templates
- Template Compilation Models
- Class Templates
- Class Template Definition
- Class Template Instantiation
- Members of Class Templates
- Friend Declarations in Class Templates
- Class Template Compilation Model
4Outline of Module 5
- Exception Handling
- Throwing an Exception and the Try Block
- Catching an Exception
- Exception Specifications
- Advanced Topics
- C Stream I/O
- Input/Output of Built-in Types
- Formats
- Overloading the I/O Operators ltlt and gtgt
- File Input and Output
- Condition States
5Example 1 Stack with Exceptions
- // except.cpp
- include "except.h"
- CPopOnEmptyCPopOnEmpty(int sz)
- m_nStackSize(sz)
- void CPopOnEmptyPrint() const
-
- cout ltlt "Exception Pop on empty stack!\n"
- cout ltlt "Stack Size " ltlt m_nStackSize ltlt endl
-
- CPushOnFullCPushOnFull(int sz)
- m_nStackSize(sz)
- void CPushOnFullPrint() const
-
- cout ltlt "Exception Push on Full stack!\n"
- // except.h
- include ltiostream.hgt
- class CPopOnEmpty
-
- public
- CPopOnEmpty(int sz 0)
- void Print() const
- private
- int m_nStackSize
-
- class CPushOnFull
-
- public
- CPushOnFull(int sz 0)
- void Print() const
- private
6Ex 1 Stack with Exceptions - contd
- // stack.cpp
- include ltiostream.hgt
- include "Stack.h"
- include "except.h"
- void CStackPush(int item)
-
- if (IsFull()) throw CPushOnFull(m_nSize)
- m_Arraym_nTop item
-
- int CStackPop()
-
- if (IsEmpty()) throw CPopOnEmpty(m_nSize)
- return m_Arraym_nTop--
-
- bool CStackIsEmpty() const
- return (m_nTop lt 0)
- bool CStackIsFull() const
- return (m_nTop m_nSize - 1)
- // Stack.h
- const int maxSize 10
- class CStack
-
- public
- CStack(int sz maxSize)
- CStack(const CStack)
- CStack operator
- (const CStack)
- void Push (int item)
- int Pop()
- bool IsEmpty() const
- bool IsFull() const
- CStack()
- private
- int m_Array
- int m_nTop
7Ex 1 Stack with Exceptions - contd
- // stack.cpp -- contd
- CStackCStack(int sz)
- m_Array new intsz
- m_nSize sz
- m_nTop -1
- CStackCStack(const CStack stack)
- m_nSize stack.m_nSize
- m_nTop stack.m_nTop
- m_Array new intm_nSize
- for (int i0 iltm_nTop i)
- m_Arrayi stack.m_Arrayi
- CStack
- CStackoperator(const CStack stack)
- if (stack ! this)
- delete m_Array
- m_nSize stack.m_nSize
- m_nTop stack.m_nTop
- m_Array new intm_nSize
- for (int i0 iltm_nTop i)
m_Arrayi stack.m_Arrayi
- // class.cpp
- include ltiostream.hgt
- include "Stack.h"
- include "except.h"
- void main()
-
- CStack stack
-
- try
-
- for ( int i 1 i lt maxSize3 i)
- stack.Push(i100)
-
- catch (CPushOnFull pushExcept)
-
- pushExcept.Print()
-
8Ex 1 Stack with Exceptions - contd
- // class.cpp -- contd
- try
-
- for ()
- cout ltlt stack.Pop() ltlt endl
-
- catch (CPopOnEmpty popExcept)
-
- popExcept.Print()
-
-
- The first for-loop tries to push three more items
than the capacity of the stack. - The second infinite for-loop pops until the stack
is empty
- Exception objects
- class CPopOnEmpty
- class CPushOnFull
- The throw expression
- void CStackPush(int item)
- if (IsFull()) throw CPushOnFull(m_nSize)
- .
- The try - catch block
- try
-
- for ()
- cout ltlt stack.Pop() ltlt endl
-
- catch (CPopOnEmpty popExcept)
-
- popExcept.Print()
-
9Exception Handling
- Problem Statement
- The designer of a library can detect run-time
errors, but does not in general know what to do
with them. The user of the library may know how
to cope with such errors but cannot detect them. - Ex. The user of a math library may not know when
a expression may have a divide-by-zero operation.
The math library can detect it and the user
program may know how to handle it. - A Solution -- Exception handling
- Exceptions provide a way for code that detects a
problem from which it cannot recover to pass the
problem on to some part of the system that might
be able to recover. - C implementation on Exception handing
- A function that finds a problem it cannot handle
throws an exception, and its (direct or indirect)
caller that can handle the problem catches the
exception. - Ex. The math library throws a divide-by-zero
exception, the user program catches the exception
and handles it.
10Throwing an Exception and the Try Block
- Throwing an Exception -- by the detector
- Syntax throw An_Exception
- ex throw 2
- throw CPopOnEmpty(m_nSize) // call a
constructor - An exception must be an object it cannot be a
class type. - throw CPopOnEmpty // illegal - not an object
- The Try Block -- by the caller
- The caller that can handle the exception executes
the try block. - try
- // statements that can cause exceptions
-
- catch (Exception_1)
-
- // handle exception1
-
- .
- catch (Exception_n)
- // handler exception_n
11Throwing an Exception and the Try Block
- Control flow of the try block
- If no exception occurs, the code in the try-block
is executed and its handlers are ignored. The
next statement after the last catch clause is
executed. - If an exception is thrown,
- the statements following the throw statement are
ignored and the try-block exits (the stack is
unwound.). - The catch clauses are checked in order. The first
matched catch is executed. After a catch clause
is completed, the program continues at the
statement following the last catch in the list. - If no catch clause can catch the exception, the
exception is passed to the next caller along the
calling chain. - Once an exception is thrown, the program does not
resume where the exception was originally thrown
even after the exception is handled. - A try block introduces a local scope -- a
variable declared within the block cannot be
referred to outside the block, including the
catch clauses. - try int x
- catch (exception) cout ltlt x // error x is
undefined - It is possible to include the entire body of a
function in the try block. - int main()
- try // the body of main() catch (exception)
12Catching an Exception
- Exception objects
- The exception declaration of a catch clause can
be either a type declaration or an object
declaration. - try catch (int) // type delcaration.
- try catch (int x) cout ltlt x ... //
object delcaration. - try catch (CPopOnEmpty x) x.Print()
... // object delcaration. - An exception object is always created at the
throw point. - Type X // a global variable
- int main ()
- try ...throw X
- // an exception object is created and
initialized with X - catch (Type EX) EX Y
- // EX is copied from the exception object.
The assignment // changes the local EX, not
the exception object, not the global X - catch (Type EX) EX Y
- // EX is a reference to the exception
object, not the global X - // the assignment changes the exception
object -
13Catching an Exception
- Stack Unwinding
- When an exception cannot be handled, the search
is continued to the calling function. This is
continued until the exception can be handled or
the program terminates. - Ex try foo(x) void foo(x) void
foobar() - catch (Type1) try foobar()
. - //handler Type1 catch (Type2) throw
Type1() - .
- As the stack being unwound, the local objects at
each unwound level end and their destructors are
called. - In the above example, when throw Type() is
completed, - 1. all local variables in foobar() are destroyed
with their destructors. - 2. All local variables in foo() are destroyed
with their destructors. - The Catch-all handler -- ellipsis.
- Ex try // should be used as the last catch
clause. - catch () // enter for any type of exception
14Catching an Exception
- Rethrow
- A catch clause can pass the exception further up
the list of function calls by re-throwing the
exception. - Ex try foo(x)
- catch (Type1 EX)
- if (cannothandle(EX)) throw //
re-throw the exception - .
- The exception that is re-thrown is the original
exception object. - Type X // a global variable
- int foo ()
- try ...throw X catch (Type EX) EX
y throw - int main ()
- try foo()
- catch (Type EX1) EX1 z
-
- // EX1 references to the original except. object
copied from the global X - // it doesnt reference to EX in foo(), not to
the global X either.
15Exception Specifications
- An exception specification follows the function
parameter list. - class CStack
- ...
- void Push (int item) throw (CPushOnFull)
- int Pop() throw (CPushOnFull)
-
- An empty exception specification guarantees that
the function doesnt throw any exception. - void foo(int item) throw () // foo() will not
throw any exception - If a function declaration does not specify an
exception specification, it may throw exceptions
of any type. - void foo(int item) // foo() can throw an
exception of any type - If a function throws an exception that is not in
the specification list, the function unexpected()
in the standard library is invoked, which in
turn, by default, terminates the program. - MS VC 6.0 doesnt seem to support exception
specifications.
16Advanced Topics Grouping of Exceptions
- Grouping of Exceptions Put exceptions into
families
class Matherr // virtual void
debug_print() class Overflow public Matherr
// virtual void debug_print() class
ZeroDivide public Matherr // virtual void
debug_print() class IntOverflow public
Overflow // virtual void debug_print()
int add(int x, int y) // .. if (overflow())
throw IntOverflow() void foo() try
int i add(INT_MAX, 2) catch (Matherr
m) m.debug_print() // IntOverflows
debug_print()
17Advanced Topics Resource Management
- Resource Acquisition is initialization
class File_ptr FILE p public File_ptr(const
char n, const char a) p fopen(n, a)
File_ptr() fclose(p) void
use_file(const char fn) File_ptr f_ptr(fn,
r) // use file f_ptr is a local object of
use_file(). If an exception occurs in
use_file(), the file pointed by f_ptr would be
closed when use_file exits and File_ptrs
destructor is called automatically.
class Acquire File_ptr ff Lock_ptr
ll public Acquire(const char n, const char
m) ff(n, r), // acquire ff ll(m)
//acquire ll // constructor body If an
exception occurs in ll(m), the destructor of ff
will be invoked. If the Acquire constructors
body has an exception, the destructors of ff and
ll will be invoked. gt resources are released.
18Input/Output of Built-in Types
- Input/Output classes
- istream input stream class
- ostream output stream class
- iostream bidirectional input/output class
- Standard Input/Output objects
- cin an istream class object for standard input
- cout an ostream class object for standard output
- cerr an ostream class object for standard error
output - The output operator ltlt.
- It accepts argument of any of the built-in data
types. - cout ltlt int_var ltlt double_var
- cout ltlt this is a string!\n ltlt char_ptr
- cout ltlt int_var // print the address
of int_var in hexadecimal. - cout ltlt true ltlt false // print 1 and 0
respectively, by default. - Operator ltlt associates left to right
- cout ltlt x ltlt y // is equivalent to
- ( cout ltlt x ) ltlt y
19Input/Output of Built-in Types
- The input operator gtgt.
- It accepts argument of any of the built-in data
types. - cin gtgt int_var gtgt double_var
- cin ltlt char_var // all white spaces are
skipped - Operator gtgt associates left to right
- cin gtgt x gtgt y // is equivalent to
- ( cin gtgt x ) gtgt y
- By default, the operator gtgt discards any
intervening white space ( blank, tab, newline,
formfeed, and carriage return). - Input sequence 123 1
- b c d
- cin gtgt int_var gtgt ch1 gtgtch2 gtgt ch3 gtgtch4
- cout ltlt int_varltltch1ltltch2ltltch3ltltch4
- // prints 1231bcd
- To process every input character including white
spaces - while (cin.get(char_var)) cout.put(char_var)
- // read every char in input and print char by
char
20Formats
- Integer outputs
- cout.setf(ios_baseoct, ios_basebasefield)
- cout ltlt 1234 //print octal 2322
- cout.setf(ios_basedec, ios_basebasefield)
- cout ltlt 1234 //print decimal 1234 -- decimal is
the default - Floating-point output
- cout ltlt 1234.56789 // default output 1234.57
- cout.setf(ios_basescientific,
ios_basefloatfield) - cout ltlt 1234.56789 // scientific format
1.2345678e003 - cout.setf(ios_basefixed, ios_basefloatfield)
- cout ltlt 1234.56789 // fixed point format
1234.567890 - cout.setf(0, ios_basefloatfield) // reset
default - cout.precision(8) // set precision to 8
- cout ltlt 1234.56789 // print 1234.5679
- Above print results were generated with MS VC
6.0 and its standard iostream.
21Formats
- Output fields
- cout.width(4) // only affect the immediate ltlt
operation - cout ltlt 12 //print with two space in front of
12 - cout.width(4) cout.fill()
- cout ltlt 12 //print 12
- cout.width(0) // print as many as needed
- Field adjustment
- cout.width(4) cout.fill()
- cout.setf(ios_baseleft, ios_baseadjustfield)
// left - cout.width(4) cout ltlt -12 // print -12
- cout.setf(ios_baseright, ios_baseadjustfield)
// right -- default - cout.width(4) cout ltlt 12 // print 12
- cout.setf(ios_baseinternal, ios_baseadjustfiel
d) // between sign and - cout.width(4) cout ltlt -12 // print -12
- Above print results were generated with MS VC
6.0 and its standard iostream.
22Formats
- Manipulators -- must include ltiomanipgt
- cout ltlt x ltlt flush ltlt y ltlt flush
- // explicitly request that the buffer be
flushed. - cin gtgt noskipws gtgt x
- // dont skip white spaces.
- cout ltlt 1234 ltlt , ltlthexltlt 1234 ltlt, ltlt oct
ltlt 1234 - // prints 1234, 4d2, 2322.
- cout ltlt setw(6) ltlt setfill() ltlt 12
- // prints 12.
- When using manipulators that dont take
arguments, dont add (). - cout ltlt hex() ltlt 12 // error hex doesnt take
arguments - make sure include ltiomanipgt in your program
- Users may define their own manipulators
- The manipulators shown here are only some
examples. For more comprehensive descriptions,
read Lippmans and Strousptrups books. - Above print results were generated with MS VC
6.0 and its standard iostream.
23Overloading the I/O operators ltlt and gtgt
- General skeleton of an overloaded output operator
- ostream operatorltlt(ostream os, const ClassType
obj) -
- // actual output of the members.
- os ltlt //
-
- // return ostream object
- return os
-
- General skeleton of an overloaded input operator
- istream operatorgtgt(istream is, ClassType obj)
-
- // actual input to the members.
- os gtgt //
-
- // return istream object
- return is
24Overloading the I/O operators ltlt and gtgt
- An Example
- class complex
- friend ostream operatorltlt(ostream os, const
complex obj) - friend istream operatorgtgt(istream is, complex
obj) - Private
- int real, image
-
- ostream operatorltlt(ostream os, const complex
obj) - os ltlt lt ltltobj.real ltlt, ltltobj.imageltlt
gt\n - return os
-
- istream operatorgtgt(istream is, complex obj)
- is gtgt obj.real gtgt obj.image
- return is
-
- int main()
- complex cmplx
- cin gtgt cmplx
- cout ltlt cmplx
25Overloading the I/O operators ltlt and gtgt
- Virtual output functions
- The ostream members are not virtual.
- Since the exact type of a subclass may not be
known yet, correct output cannot be achieved
simply by defining a ltlt for each new type. - Implementation
- Design a virtual put function in the base and
subclasses. - virtual ostream put(ostream s)
- Call the virtual function in ltlt from a reference
to the base - ostream operatorltlt
- (ostream s, base b)
-
- return b.put(s)
-
- ltlt doesnt need to be a friend of the classes in
this example.
- include "stdafx.h"
- include ltiostream.hgt
- class base
- public
- virtual ostream put(ostream s)
- return s ltlt"Base\n"
-
- class derived public base
- public
- virtual ostream put(ostream s)
- return s ltlt"Derived\n"
-
- ostream operatorltlt(ostream s, base b)
- return b.put(s)
- int main(int argc, char argv)
-
- base bs derived dr
- cout ltlt bs ltlt dr
26File Input and Output
- To use file input and output, include
- include ltfstreamgt
- using namespace std
- To open a file for output only.
- ofstream outfile(filename, ios_baseout)
- ofstream outfile(filename) // output is
default - // when the file does not exist, it would be
created. - // if an file is opened for output, all data in
the file is discarded. - if (!outfile) //open failed.
- cerr ltlt file cannot be opened!\n
- exit(-1)
-
- ofstream is derived from ostream. All the ostream
operations can be applied to ofstream objects. - char ch
- outfile.put(1).put()).put(ch)
- outfileltlt11 ltlt 11 ltlt endl
- // insert 1) 11 2 to outfile.
- To open a file for append.
- ofstream outfile(filename, ios_baseapp)
27File Input and Output
- To open a file for input only.
- ifstream infile(filename)
- if (!infile)
- cerr ltltinput file open failed\n
- exit(-1)
- infile gtgt int_var
- while (infile.get(ch)) cout.put(ch)
- An fstream object can open a file for either
input and output. - fstream file
- file.open(filename, ios_basein) // open the
file for input - file gtgt wd
- file.close()
- file.open(filename, ios_baseapp) // open the
same file for output - file ltlt endl ltlt wd ltlt endl
- file.close()
- An fstream object can open a file for both input
and output. - fstream file
28Condition States
- Condition flags.
- eof() return true if end-of-file has been
encountered. - if (cin.eof() ) // ok, input complete.
- bad() return true if an invalid op. has been
attemped -- file corrupted. - if (cin.bad() ) // file corrupted in some
undefined way. - fail() return true if an o.p has been
unsuccessful. Ex. Invalid input format - ifstream infile(filename)
- if (infile.fail() ) // file open failed.
- good() return true if previous operation was
successful - file in good cond. - If (infile.good() ) // continuing processing
the file. - Two methods for modifying the condition states.
- clear() resets the condition state to an explicit
value - cin.clear(ios_basegoodbit) // reset cin to
good condition - setstate() add a condition tot he existing
condition of the object. - if ((ch is.get()) ! lt) cin.setstate(ios_bas
efailbit) - // if the current char is not lt, mark the
fail state. - To set multiple states,
- cin.setstate(ios_basebadbit
ios_basefailbit) - // set both bad state and fail state.
29Summary of Module 5
- Exception Handling
- Throwing an Exception and the Try Block
- Catching an Exception
- Exception Specifications
- Advanced Topics
- C Stream I/O
- Input/Output of Built-in Types
- Formats
- Overloading the I/O Operators ltlt and gtgt
- File Input and Output
- Condition States
30Advice
- Dont use exceptions where more local control
structures will suffice. - Use the resource acquisition is initialization
to manager resources. - Not every program needs to be exception safe.
- Avoid throwing exceptions from copy constructors.
- Avoid throwing exceptions from destructors.
- Throw an exception to indicate failure in a
constructor. - Develop an error-handling strategy early in the
design. - Overload ltlt and gtgt for user-defined types with
values that have meaningful textual
representations. - Remember that by default gtgt skips white spaces
- Remember to include ltiomanipgt when using
standard manipulators. - Remember that the width manipulator applies to
the following I/O operation only. - Define virtual input/output functions.
31Programming Assignments
- Exception -- CDate
- Modify the CDate example so that it throws
exceptions when a value is out of valid range. - Group the exceptions in CDate into a class
hierarchy. Use virtual functions to print
offensive values (year, month, or day). - Write a main() to test those exceptions.
- Exception -- An array class
- Design an array class that throws OutOfRange when
the subscript is of range. OutOfRange can print
the size of the array and the offensive
subscript. - Overload Operators ltlt and gtgt
- Design virtual input and output functions for the
CPerson-CManager-CEngineer inheritance example. - File Input/output
- Design a program that counts the number of words
and the number of white spaces in the input file.
32(No Transcript)