home *** CD-ROM | disk | FTP | other *** search
/ Shareware Supreme Volume 6 #1 / swsii.zip / swsii / 099 / IOSTREAM.ZIP / IOSTREAM < prev   
Text File  |  1993-01-07  |  92KB  |  3,137 lines

  1. ************************* INTRODUCTION *************************
  2.  
  3. This document is a tutorial on the use of the header file <iostream.h>, as
  4. implemented by Borland International, Inc. in its product Turbo C++.
  5.  
  6. There are 4 main sections:
  7.  
  8.    1) Header file
  9.    2) Output
  10.    3) Input
  11.    4) Manipulators
  12.    5) File I/O
  13.  
  14. These sections are actually just part of the complete set of notes on the C++
  15. language that I use in my programming classes here in Silicon Valley. Before
  16. you begin this tutorial, you must be familiar with C, know how to write simple 
  17. classes, have some knowledge of member functions, can create instances of
  18. classes, etc.
  19.  
  20. I have spent many hours putting this material together, and hope that it
  21. serves its intended purpose, which is to give CIS subscribers an understand-
  22. ing of <iostream.h> that none of the manuals or textbooks seem to provide. 
  23. I am deeply indebted to John Dlugosz, with whom many of you are already 
  24. familiar, for taking the time out of his busy schedule, to proof-read this 
  25. tutorial. Without his help and guidance, the information contained herein 
  26. would not be as accurate and complete as (I hope!) it is. Nevertheless, if 
  27. you find an error, or have a suggestion as to how this tutorial can be 
  28. improved, please let me know.
  29.  
  30. Eric Nagler         CIS 76357,1146
  31. P. O. Box 2483
  32. Santa Clara, California 95055-2483
  33.  
  34.  
  35. *********************** SECTION 1 --  HEADER FILE ***************************
  36.  
  37. All program examples in this tutorial include a file called <header.h>. It is
  38. my own creation (so don't call Borland!), and is tailored to accommodate
  39. all of the program examples. I suggest that you copy and use this header file 
  40. if you wish to execute the examples. But feel free to modify it according to 
  41. your own needs.
  42.  
  43. If the examples sometimes appear to be "scrunched" toward the left-hand side
  44. of the screen, it's because they are designed to be shown in 40-column mode,
  45. double height.
  46.  
  47. // header.h
  48. // for iostream tutorial by Eric Nagler
  49. //
  50. ////////////////////////////////////
  51. // My private header file for C++ programs
  52. ////////////////////////////////////
  53.  
  54. // There's also a #define ZORTECH in my Zortech header file so that I can
  55. // write different statements to print addresses.
  56.  
  57. #define BORLAND
  58.  
  59. // OLD is defined in the cc.bat file which I use to compile Turbo C++
  60. // using the old (version 1.2) style I/O. Therefore, use <stream.h>
  61.  
  62. #ifdef OLD
  63. #include <stream.h>
  64.  
  65. // Otherwise, it must be version 2.0, so use <fstream.h>, which also
  66. // includes <iostream.h>
  67.  
  68. #else
  69. #include <fstream.h>
  70.  
  71. // Any manipulators taking a parameter will also be accommodated
  72.  
  73. #include <iomanip.h>
  74. #endif
  75.  
  76. // I also need console I/O for the PAUSE() function
  77.  
  78. #include <conio.h>
  79.  
  80. // Include <stdio.h> for C style I/O
  81.  
  82. #include <stdio.h>
  83.  
  84. // Include these because they're used so frequently, and really don't add
  85. // that much to the compilation time
  86.  
  87. #include <string.h>
  88. #include <ctype.h>
  89. #include <stdlib.h>
  90. #include <time.h>
  91.  
  92. ///////////////////////////////////
  93.  
  94. // My private defines
  95.  
  96. #define FALSE               0
  97. #define TRUE                !FALSE
  98. #define AND                 &&
  99. #define OR                  ||
  100. #define NO                  0
  101. #define YES                 !NO
  102. #define EQUALS              ==
  103. #define IS_EQUAL_TO         ==
  104. #define NOT                 !
  105. #define IS_NOT_EQUAL_TO     !=
  106. #define NOT_EQUAL_TO        !=
  107. //
  108. #define BLANK               ' '
  109. #define SPACE               ' '
  110. #define ASTERISK            '*'
  111. #define DECIMAL             '.'
  112. #define NEW_LINE            '\n'
  113. #define NUL                 '\0'
  114. #define TAB                 '\t'
  115. #define BACKSPACE           '\b'
  116. #define BEEP                '\a'
  117. #define FORMFEED            '\f'
  118. #define RETURN              '\r'
  119.  
  120. ///////////////////////////////////
  121.  
  122. // My private PAUSE function
  123.  
  124. void PAUSE()
  125. {
  126.    cout << "Press any key to "
  127.         << "continue...\n" ;
  128.    getch() ;
  129. }
  130.  
  131. // My private flush-the-input-buffer manipulator until either EOF or
  132. // new-line is found.
  133.  
  134. istream& FLUSH(istream& strm)
  135. {
  136.    strm.clear() ;
  137.    char ch ;
  138.    while (!strm.get(ch).eof() AND ch != NEW_LINE)
  139.                          ;  // Empty body
  140.    return strm ;
  141. }
  142.  
  143. ////////////////////////////////////
  144. // This function prints the various I/O flags of an input stream.
  145. // Defaults to 'cin'
  146.  
  147. void IOFLAGS(istream& stream=cin)
  148. {
  149.    cout << "eof state is  " << (stream.eof()
  150.            ? "ON" : "OFF") << endl ;
  151.    cout << "good state is " << (stream.good()
  152.            ? "ON" : "OFF") << endl ;
  153.    cout << "fail state is " << (stream.fail()
  154.            ? "ON" : "OFF") << endl ;
  155.    cout << "bad state is  " << (stream.bad()
  156.            ? "ON" : "OFF") << endl ;
  157.    cout << "if (!instance) returns "<< (!stream ? "TRUE" : "FALSE") << endl ;
  158.    cout << "if (instance) returns " << (stream ? "TRUE" : "FALSE") << endl ;
  159. }
  160.  
  161. /////////////////////////////////////
  162. // This function prints the format flags of an output stream.
  163. // Defaults to 'cout'
  164.  
  165. void FORMATFLAGS(ostream& stream=cout)
  166. {
  167.    static char* message[] =
  168.    {
  169.      "skipws" ,
  170.      "left" ,
  171.      "right" ,
  172.      "internal" ,
  173.      "dec" ,
  174.      "oct" ,
  175.      "hex" ,
  176.      "showbase" ,
  177.      "showpoint" ,
  178.      "uppercase" ,
  179.      "showpos" ,
  180.      "scientific" ,
  181.      "fixed" ,
  182.      "unitbuf" ,
  183.      "stdio"
  184.    } ;
  185.  
  186.    cout << "FORMAT FLAGS\n" ;
  187.    long f = stream.flags() ;
  188.    for (int i = 0 ; i < 16 ; ++i)
  189.    {
  190.      if (f & 0x0001)
  191.        cout << message[i] << endl ;
  192.      f >>= 1 ;
  193.    }
  194. }
  195.  
  196. ///////////////////////////////////
  197.  
  198. // Define a global instance of the
  199. // class 'ofstream' called POUT that
  200. // is tied to the printer
  201.  
  202. ofstream POUT("prn") ;
  203.  
  204. /////////////////////////////////////
  205.  
  206. // A manipulator that directs to the printer all subsequent output for
  207. // the one statement in which it is found
  208.  
  209. ostream& PRINTER(ostream&)
  210. {
  211.    return POUT ;
  212. }
  213.  
  214. // A manipulator that directs to the screen all subsequent output for
  215. // the one statement in which it is found
  216.  
  217. ostream& SCREEN(ostream&)
  218. {
  219.    return cout ;
  220. }
  221.  
  222. // A manipluator to set left justification
  223.  
  224. ostream& LEFT(ostream& str)
  225. {
  226.    str.setf(ios::left , ios::adjustfield) ;
  227.    return str ;
  228. }
  229.  
  230. // A manipluator to set right justification
  231.  
  232. ostream& RIGHT(ostream& str)
  233. {
  234.    str.setf(ios::right , ios::adjustfield) ;
  235.    return str ;
  236. }
  237.  
  238. // A manipluator to set internal justification
  239.  
  240. ostream& INTERNAL(ostream& str)
  241. {
  242.    str.setf(ios::internal , ios::adjustfield) ;
  243.    return str ;
  244. }
  245.  
  246. // A manipulator to show the decimal point
  247.  
  248. ostream& SHOWPOINT(ostream& str)
  249. {
  250.    str.setf(ios::showpoint) ;
  251.    return str ;
  252. }
  253.  
  254. // A manipulator to show the base on hex and octal output
  255.  
  256. ostream& SHOWBASE(ostream& str)
  257. {
  258.    str.setf(ios::showbase) ;
  259.    return str ;
  260. }
  261.  
  262. // A manipulator to suppress the showing of the base
  263.  
  264. ostream& NOSHOWBASE(ostream& str)
  265. {
  266.    str.unsetf(ios::showbase) ;
  267.    return str ;
  268. }
  269.  
  270. // A manipulator to show fixed point output
  271.  
  272. ostream& FIXED(ostream& str)
  273. {
  274.    str.setf(ios::fixed , ios::floatfield) ;
  275.    return str ;
  276. }
  277.  
  278. // A manipulator to show scientific point output
  279.  
  280. ostream& SCIENTIFIC(ostream& str)
  281. {
  282.    str.setf(ios::scientific , ios::floatfield) ;
  283.    return str ;
  284. }
  285.  
  286. // A manipulator to show uppercase output on hex and scientific
  287. // numbers
  288.  
  289. ostream& UPPERCASE(ostream& str)
  290. {
  291.    str.setf(ios::uppercase) ;
  292.    return str ;
  293. }
  294.  
  295. // A manipulator to show lowercase output on hex and scientific
  296. // numbers
  297.  
  298. ostream& LOWERCASE(ostream& str)
  299. {
  300.    str.unsetf(ios::uppercase) ;
  301.    return str ;
  302. }
  303.  
  304. // A manipulator to show a '+' on positive numbers
  305.  
  306. ostream& SHOWPOS(ostream& str)
  307. {
  308.    str.setf(ios::showpos) ;
  309.    return str ;
  310. }
  311.  
  312. // A manipulator to negate showing a '+' on positive numbers
  313.  
  314. ostream& NOSHOWPOS(ostream& str)
  315. {
  316.    str.unsetf(ios::showpos) ;
  317.    return str ;
  318. }
  319.  
  320. *********************** SECTION 2 -- OUTPUT *********************************
  321.  
  322. Introduction
  323.  
  324. Whenever data gets sent to a text output device, it takes on the form of a
  325. stream of characters. For example, the floating point number 1.234 is not
  326. stored internally as 5 characters ('1' , '.' , '2' , '3' , '4'), but rather 
  327. in a special format designed to accommodate floating point values. In character
  328. format, this value is meaningless. Yet, if you were to print this number,
  329. you certainly would want to have the aforementioned 5 characters appear
  330. on your output device.
  331.  
  332. The C++ input/output mechanism provided with AT&T release 2.0
  333. provides a series of classes that have been created to handle the problem of
  334. sending and receiving data. This mechanism consists of many classes, some
  335. derived from others, and some contained within others. At the lowest level,
  336. the most fundamental operation is to manipulate the characters within some
  337. buffer, also known as a stream. This is done by the class "streambuf".
  338.  
  339. Because input and output must be formatted to be legible, another class
  340. called "ios" contains functions and data to handle this task. When an instance
  341. of the class "ios" comes into existence, it receives a pointer to some
  342. "streambuf" area. To send the actual formatted output to the user, another
  343. class called "ostream" (which is derived from "ios") is used.
  344.  
  345. Classes, like built-in scalar types, don't occupy any memory. What is
  346. needed, then, is an instance, or object, of that class type. In the hierarchy 
  347. of derivation, the last class,  ostream , is the one that used to create the
  348. instance, as follows:
  349.  
  350.    ostream cout ;
  351.  
  352. Since the instance "cout" is an instance of a class that has been derived from
  353. parent classes, by definition it has inherited all of the data members of its
  354. parent classes, and has all of the functionality of those classes. Also, since
  355. this instance is defined at global scope, your program has unlimited access
  356. to it at all times. Output operations are initiated using the instance "cout".
  357.  
  358. In addition to data members, classes can contain functions to operate upon
  359. these members. In the class  ostream , the function you will use the most
  360. often is called the insertion operator, and its name is "operator<<". The
  361. argument to this function is the data item that you wish to output. The name
  362. 'insertion' comes from the fact that you are 'inserting' items into an
  363. output buffer.
  364.  
  365. In a manner similar to that of accessing a data member of a structure,
  366. function members of a class are also accessed using the direct member
  367. operator, also known as the dot operator (.). This is done by first writing
  368. the instance, followed by the dot operator, and then the function name with
  369. any arguments enclosed within parentheses. For example, to output a simple
  370. message, you would code:
  371.  
  372.    cout.operator<<("THE ANSWER IS ") ;
  373.  
  374. where "THE ANSWER IS " is the argument to the function "operator<<".
  375. Similarly, to output the number 65, you would code:
  376.  
  377.    cout.operator<<(65) ;
  378.  
  379. To output a new-line character, you would code:
  380.  
  381.    cout.operator<<('\n') ;
  382.  
  383. or, if you wish, a string containing nothing but a new-line character:
  384.  
  385.    cout.operator<<("\n") ;
  386.  
  387. If you really think about it, you should be asking the obvious question,
  388. "How can a function take a single argument of different types?" In other
  389. words, in the first call above a string (type "char*") was passed as the
  390. argument, in the second call an integer (type "int") was passed, and in the
  391. third a character (type "char") was passed. How can this be? The answer is
  392. that the function "operator<<" has been "overloaded", so that many versions
  393. of the "same function" exist within the class "ostream". The compiler is smart
  394. enough to distinguish one version from another, so that your function call
  395. correctly accesses the function specifically written to handle the type of
  396. argument that you provide.
  397.  
  398. The next obvious question you should be asking is whether you have to
  399. code a series of such function calls if more than one data item is to be
  400. output. In other words, in the examples above, are three separate function
  401. calls really necessary? Fortunately, the answer is no. The way the
  402. "operator<<" function is written, a reference (address) to the calling
  403. instance ( cout ) is returned by the function, and can therefore be used as the
  404. calling instance for a concatenated function call. That is, the three function
  405. calls can be written:
  406.  
  407.    cout.operator<<("THE ANSWER IS ")
  408.        .operator<<(65)
  409.        .operator<<('\n') ;
  410.  
  411. That's the good news. The bad news is that it's still too much coding and
  412. still too awkward. With this in mind, the designers of C++ allow the
  413. programmer to abbreviate the notation:
  414.  
  415.    cout.operator<<(argument1) ;
  416.  
  417. with the more convenient:
  418.  
  419.    cout << argument1 ;
  420.  
  421. and the notation:
  422.  
  423.    cout.operator<<(argument1).operator<<(argument2) ;
  424.  
  425. with the more convenient:
  426.  
  427.    cout << argument1 << argument2 ;
  428.  
  429. Note that the dot operator has been eliminated, and the function
  430. "operator<<" has been replaced with just the insertion operator "<<".
  431.  
  432. For stylistic purposes you could write each insertion operator on its own
  433. line. Try running this program.
  434.  
  435.   // EXAMPLE OUTPUT-01
  436.  
  437.  #include <header.h>
  438.  
  439.  int main()
  440.  {
  441.     cout << "THE ANSWER IS "
  442.          << 65
  443.          << "\n" ;
  444.  
  445.     return 0 ;
  446.  }
  447.  
  448. Only one such occurrence of "cout" needs to be written until the end of the
  449. statement is reached.
  450.  
  451. Of course, you could restrict each statement to having just one insertion
  452. operator. This program produces exactly the same output as before.
  453.  
  454.  // EXAMPLE OUTPUT-02
  455.  
  456.  #include <header.h>
  457.  
  458.  int main()
  459.  {
  460.     cout << "THE ANSWER IS " ;
  461.     cout << 65 ;
  462.     cout << "\n" ;
  463.  
  464.     return 0 ;
  465.  }
  466.  
  467. In addition to a string, an integer, and a character, the function
  468. "operator<<" has been overloaded to accept arguments of type "long", "float",
  469. "double", pointer, and so forth.
  470.  
  471. ******************************************************************
  472. Bit Format Flags
  473.  
  474. Now think about a "printf" function call. It usually consists of a control
  475. string argument and, optionally, a list of expressions to be output. The
  476. control string contains literals which will be output exactly as shown, and
  477. conversion specifications that indicate exactly how an expression from the
  478. list of expressions is to appear. Each conversion specification starts with a
  479. '%' and ends with a conversion character, e.g., 'd' for decimal format, 'c' for
  480. character format, 's' for a string, etc. Between the start and end you may
  481. enter various flags, the field width, base formatting, justification, floating
  482. point precision, and so forth. Each conversion specification stands on its
  483. own; there is no connection to any other one.
  484.  
  485. In the C++ version 2.0 stream I/O, all of the characteristics relating to how
  486. an expression should appear apply, not to each individual expression, but to
  487. the output stream as a whole . In other words, once you specify that decimal
  488. format is desired, ALL integer numbers from that point on are output in
  489. decimal format. No further action need be taken. If you decide to switch to
  490. hexadecimal output, then all integer numbers from that point on will be
  491. shown in their hex formats. The same is true for floating point precision.
  492. Once it is set, it stays set for all subsequent floating point numbers. (There
  493. is one important exception to the "set it and forget it" feature of C++
  494. streaming that will be discussed later).
  495.  
  496. Any binary characteristic of the output stream is stored in a long
  497. (protected) field in the class "ios". In Turbo C++ this field is called
  498. "x_flags". (The fact that it's  protected  means that you cannot access it
  499. directly.) Each characteristic occupies one bit of this field, which simply
  500. means that it's either true or false; on or off; set or not set. For example,
  501. the output state of decimal is either on or off. The same can be said for the
  502. output states of hexadecimal and octal. Also, the state of left-justification 
  503. is either set or not set, as is its opposite, right-justification. On the other
  504. hand, stream characteristics that require values, such as the field width and
  505. floating point precision, are stored in integer variables.
  506.  
  507. Each binary characteristic is represented by a unique value in a field that is
  508. part of an unnamed public enumerated type in the class "ios". This value is
  509. represented by exactly one bit in the field. Thus, no two characteristics will
  510. ever have the same bit position (ranging from 15 down to 0) set on. By
  511. ORing these bits into the field "x_flags", the different states can be set with
  512. no conflict. This allows someone examining the field "x_flags" to infer with
  513. no ambiguity which characteristics are on and which are off.
  514.  
  515. Each binary characteristic also has a name associated with it that you may
  516. reference. The complete list of all enumerated values is shown below.
  517. Because these names exist within the class "ios", the name of this class must
  518. be specified in conjunction with the scope resolution operator (::) to
  519. unambiguously access a specific value. These are the names and values for
  520. Turbo C++:
  521.  
  522.  NAME            VALUE    MEANING
  523.  
  524.  ios::skipws     0x0001   Skip whitespace on input
  525.  ios::left       0x0002   Left-justification of output
  526.  ios::right      0x0004   Right-justification of output
  527.  ios::internal   0x0008   Pad after sign or base indicator
  528.  ios::dec        0x0010   Show integers in decimal  format
  529.  ios::oct        0x0020   Show integers in octal format
  530.  ios::hex        0x0040   Show integers in hexadecimal format
  531.  ios::showbase   0x0080   Show the base for octal and hex numbers
  532.  ios::showpoint  0x0100   Ensure that the decimal point is shown for all
  533.                           floating point numbers
  534.  ios::uppercase  0x0200   Show uppercase hex numbers
  535.  ios::showpos    0x0400   Show + for positive numbers
  536.  ios::scientific 0x0800   Use exponential notation on floating point numbers
  537.  ios::fixed      0x1000   Use fixed decimal output on floating point numbers
  538.  ios::unitbuf    0x2000   Flush all streams after insertion
  539.  ios::stdio      0x4000   Flush stdout and stderr after insertion
  540.  
  541. Because we will be examining these bits very carefully in the coming
  542. examples, it is very useful to have a function to clearly display the status
  543. for us. This has been done in the function "FORMATFLAGS" which is
  544. contained in the file "header.h". This function takes one argument: an
  545. instance of an output stream. If no argument is supplied, then the function
  546. defaults to using the name "cout".
  547.  
  548. Try running this test. Are any of these enumerated bits in the field "x_flags"
  549. already on when your program first gets control? This little program will
  550. provide the answer.
  551.  
  552.  // EXAMPLE OUTPUT-11
  553.  
  554.  // TEST THE DEFAULT OF x_flags
  555.  
  556.  #include <header.h>
  557.  
  558.  int main()
  559.  {
  560.    FORMATFLAGS() ;
  561.  }
  562.  
  563. The output of this program is:
  564.  
  565. FORMAT FLAGS
  566. skipws
  567. unitbuf
  568.  
  569. The next item of concern is how to turn these settings on and off. Within
  570. the class "ios" there are several member functions provided that allow this to
  571. be done. The first of these functions is called "setf". Remember: to call it,
  572. you must first specify the instance name, "cout", the dot member operator,
  573. and then the function name. Thus, you would write:
  574.  
  575.    cout.setf
  576.  
  577. The function "setf" has been overloaded to accept either one or two
  578. arguments. In both cases, the first argument specifies which bits are to be
  579. turned on in the field "x_flags".
  580.  
  581. For example, to turn on the  ios::dec  bit, you would code:
  582.  
  583.    cout.setf(ios::dec) ;
  584.  
  585. The function "setf" works by ORing its first argument into the field
  586. "x_flags", thereby leaving any other bits in this field undisturbed. This means
  587. that it's possible to turn on more than one bit with just one call to "setf" by
  588. using an expression for the first argument that contains several bits ORed
  589. together. For example, to turn on the "ios::dec" and the "ios::right" bits, you
  590. would code:
  591.  
  592.   cout.setf(ios::dec | ios::right) ;
  593.  
  594. How can you turn the bits off? Use the member function "unsetf". This
  595. function takes exactly one argument: the bit pattern to be turned off. Thus,
  596. to turn off the bit "ios::dec", you would code:
  597.  
  598.   cout.unsetf(ios::dec) ;
  599.  
  600. Like "setf", more than one bit at a time can be turned off by ORing the
  601. enumerated values together in the argument field.
  602.  
  603. Unfortunately, the previous method of turning bits on and off is awkward
  604. because in many cases the bits are mutually exclusive, and it would
  605. normally take 2 function calls to (a) turn a bit off using "unsetf", and (b)
  606. turn another bit on using "setf". Fortunately, a better way exists by using the
  607. "setf" function with 2 arguments. In this case the second argument represents
  608. those specific bits which are to be turned OFF prior to having those bits
  609. turned ON that are specified by the logical AND of the first and second
  610. arguments. For example, to turn the bit "ios::dec" ON and ensure that the
  611. mutually exclusive bits "ios::oct" and "ios::hex" are OFF, you would code:
  612.  
  613.    cout.setf(ios::dec , ios::dec | ios::oct | ios::hex) ;
  614.  
  615. To prove this, run this program:
  616.  
  617.  // EXAMPLE OUTPUT-12
  618.  
  619.  // TEST TURNING ON FORMAT FLAG BITS
  620.  
  621.  #include <header.h>
  622.  
  623.  int main()
  624.  {
  625.     cout.setf(ios::oct | ios::hex) ;
  626.     FORMATFLAGS() ;
  627.     cout.setf(ios::dec , ios::dec | ios::oct | ios::hex) ;
  628.     FORMATFLAGS() ;
  629.  
  630.     return 0 ;
  631.  }
  632.  
  633. The output of this program is:
  634.  
  635. FORMAT FLAGS
  636. skipws
  637. oct
  638. hex
  639. unitbuf
  640. FORMAT FLAGS
  641. skipws
  642. dec
  643. unitbuf
  644.  
  645. Because "ios::dec", "ios::oct" and "ios::hex" are mutually exclusive bit fields
  646. (that is, you only want ONE of them on at any time), you would normally
  647. AND the one bit of the first argument of "setf" with the OR of all 3 bits, as
  648. shown above. The second argument can also be specified as "ios::basefield",
  649. where this value is pre-defined as: "ios::dec | ios::oct | ios::hex".
  650.  
  651. For example, program OUTPUT-12 can be re-written as:
  652.  
  653.  // EXAMPLE OUTPUT-13
  654.  
  655.  // TEST ios::basefield
  656.  
  657.  #include <header.h>
  658.  
  659.  int main()
  660.  {
  661.     cout.setf(ios::oct | ios::hex) ;
  662.     FORMATFLAGS() ;
  663.     cout.setf(ios::dec , ios::basefield) ;
  664.     FORMATFLAGS() ;
  665.  
  666.     return 0 ;
  667.  }
  668.  
  669. The output of this program is the same.
  670.  
  671. In a similar manner, the field "ios::adjustfield" represents the bit positions
  672. of "ios::left", "ios::right" and "ios::internal" ORed together, and the field
  673. "ios::floatfield" represents the bit positions of "ios::fixed" and
  674. "ios::scientific" ORed together.
  675.  
  676. Because the field "x_flags" in the class "ios" is protected, this means that
  677. you cannot access it directly. However, there is a public member function
  678. called "flags" that will return this field to you. If you provide a long integer
  679. as an argument to "flags", then the existing value of "x_flags" will be
  680. returned to you after your argument is used to provide a new setting for
  681. "x_flags".
  682.  
  683. For example:
  684.  
  685.  // EXAMPLE OUTPUT-14
  686.  
  687.  // TEST THE flags MEMBER FUNCTION
  688.  
  689.  #include <header.h>
  690.  
  691.  int main()
  692.  {
  693.     long value = cout.flags(0) ;
  694.     cout.setf(ios::hex , ios::basefield) ;
  695.     cout << "value is "
  696.          << value
  697.          << '\n' ;
  698.     FORMATFLAGS(cout) ;
  699.  
  700.     return 0 ;
  701.  }
  702.  
  703. The output of this program is:
  704.  
  705. value is 2001
  706. FORMAT FLAGS
  707. hex
  708.  
  709. Note that "value" is the old value of "x_flags", and is printed in hexadecimal.
  710. The '2' represents the "unitbuf" bit, and the '1' is the "skipws" bit. There is
  711. nothing shown under the heading "FORMAT FLAGS" except "hex" because
  712. all of the bits were turned off by the call to "flags", then the hex bit was
  713. turned back on.
  714.  
  715. Both the "setf" and "unsetf" functions return a value, which you are free to
  716. use or ignore. The value returned is a long integer representing the
  717. previous value of the field "x_flags". However, you will probably never
  718. have occasion to use this value.
  719.  
  720. ******************************************************************
  721. The Base Setting and Integer Output
  722.  
  723. Output formatting is important because you want to have complete
  724. flexibility in the manner in which your data appears. Let's start with the
  725. base in which integers will be shown. If a "printf" function call, you have 3
  726. choices: decimal, octal and hex. A decimal output can be obtained by using
  727. a conversion specification of "%d" or "%i", an octal by using "%o", and hex by
  728. using "%x" or "%X". (How to emulate lower vs. upper case will be discussed
  729. later.) There are 3 bits in the enumerated values shown in the Bit Format
  730. Flags section that control the base setting:
  731.  
  732.    ios::dec    0x0010     Show integers in decimal format
  733.    ios::oct    0x0020     Show integers in octal format
  734.    ios::hex    0x0040     Show integers in hexadecimal format
  735.  
  736. To guarantee that decimal output is used, you must turn on the bit
  737. "ios::dec", and ensure that all the remaining 2 bits are turned off. The same
  738. reasoning applies to octal and hex output. But we proved in example
  739. OUTPUT-11 that no bit pertaining to the output base is on by default.
  740. Therefore, which base will be used? The answer is that the compiler will
  741. default to decimal output if none of the 3 base field bits is on. But be
  742. careful! If more than one output base bit happends to be on, then the output
  743. is unpredictable. (Of course, you would never deliberately put yourself in
  744. this situation.). Remember: Once the base has been set, it stays set for all
  745. future integers unless it is subsequently changed.
  746.  
  747. Recall that the field "ios::basefield" has been defined for you to contain all
  748. 3 base field bits ORed together, and should be used in the second parameter
  749. of "setf" to ensure that all 3 bits are turned off before altering them. So now
  750. let's create a program to output the number 65 using the default base,
  751. followed by the base in octal, hexadecimal, and decimal. (NOTE: a better
  752. way in which to write this program will be shown in the section on
  753. manipulators.)
  754.  
  755.  // EXAMPLE OUTPUT-21
  756.  
  757.  // HOW TO PRINT IN DECIMAL, OCTAL
  758.  // AND HEXADECIMAL FORMATS
  759.  
  760.  #include <header.h>
  761.  
  762.  int main()
  763.  {
  764.     cout << 65 << '\n' ;
  765.     cout.setf(ios::oct , ios::basefield) ;
  766.     cout << 65 << '\n' ;
  767.     cout.setf(ios::hex , ios::basefield) ;
  768.     cout << 65 << '\n' ;
  769.     cout.setf(ios::dec , ios::basefield) ;
  770.     cout << 65 << '\n' ;
  771.  
  772.     return 0 ;
  773.  }
  774.  
  775. The output of this program, as expected, is:
  776.  
  777. 65
  778. 101
  779. 41
  780. 65
  781.  
  782. One final point: In a "printf" function call, the use of the flag # causes the
  783. base of an octal or hexadecimal number to appear (0 and 0x, respectively).
  784. The same effect can be achieved in C++ by setting on the bit "ios::showbase".
  785. Here is example OUTPUT-21 again, but this time the base of the octal and
  786. hexadecimal numbers is shown. To turn off this feature, use the "unsetf"
  787. function.
  788.  
  789.  // EXAMPLE OUTPUT-22
  790.  
  791.  // HOW TO PRINT IN DECIMAL, OCTAL
  792.  // AND HEXADECIMAL FORMATS AND SHOW
  793.  // THE BASE FOR OCTAL AND HEX
  794.  // NUMBERS
  795.  
  796.  #include <header.h>
  797.  
  798.  int main()
  799.  {
  800.     cout.setf(ios::showbase) ;
  801.     cout << 65 << '\n' ;
  802.     cout.setf(ios::oct , ios::basefield) ;
  803.     cout << 65 << '\n' ;
  804.     cout.setf(ios::hex , ios::basefield) ;
  805.     cout << 65 << '\n' ;
  806.     cout.setf(ios::dec , ios::basefield) ;
  807.     cout << 65 << '\n' ;
  808.  
  809.     return 0 ;
  810.  }
  811.  
  812. The output of this program is:
  813.  
  814. 65
  815. 0101
  816. 0x41
  817. 65
  818.  
  819. Note that on positive decimal output, a '+' sign is assumed. If you want this
  820. sign to appear, turn on the bit "ios::showpos". (Of course, if the number is
  821. negative, the '-' sign will always appear.) To turn off this feature, use the
  822. "unsetf" function. In this example the number 65 is displayed with a '+' sign.
  823.  
  824.  // EXAMPLE OUTPUT-23
  825.  
  826.  // HOW TO SHOW THE SIGN OF A POSITIVE
  827.  // NUMBER
  828.  
  829.  #include <header.h>
  830.  
  831.  int main()
  832.  {
  833.     cout.setf(ios::showpos) ;
  834.     cout << 65 << '\n' ;
  835.  
  836.     return 0 ;
  837.  }
  838.  
  839. The output of this program is:
  840.  
  841. +65
  842.  
  843. There is one other option you can employ with hexadecimal numbers. By
  844. default any hex digit, as well as the 'x' in the base, appears in lower-case.
  845. The same rule applies to the 'e' when printing in scientific notation. If you
  846. want to see upper-case, turn on the bit "ios::uppercase". To revert back to
  847. lower-case, use the "unsetf" function.
  848.  
  849. This example prints the number 171 in hexadecimal, and shows all hex
  850. digits in upper-case.
  851.  
  852.  // EXAMPLE OUTPUT-24
  853.  
  854.  // HOW TO PRINT HEX DIGITS IN
  855.  // UPPER CASE LETTERS
  856.  
  857.  #include <header.h>
  858.  
  859.  int main()
  860.  {
  861.     cout.setf(ios::uppercase | ios::showbase) ;
  862.     cout.setf(ios::hex , ios::basefield) ;
  863.     cout << 171 << '\n' ;
  864.  
  865.     return 0 ;
  866.  }
  867.  
  868. The output of this program is:
  869.  
  870. 0XAB
  871.  
  872. *****************************************************************
  873. Character Output
  874.  
  875. Integer output pertains to the display of decimal, octal and hexadecimal
  876. numbers. The next question is: Can you emulate "%c" in a "printf" function
  877. call to set the base for character output, i.e., set it so that all integral
  878. values appear in their character representations? Unfortunately, the answer
  879. is no. However, the problem only arises when a non-character value needs to be
  880. displayed in its character form, because if you define a character using type
  881. char , then it will automatically be shown in its character format. Thus, to
  882. make a non-char type appear in character format, an explicit cast to type
  883. "char" is required.
  884.  
  885. For example, this program prints the letter 'A' five times:
  886.  
  887.  // EXAMPLE OUTPUT-31
  888.  
  889.  // HOW TO PRINT A CHARACTER AND A
  890.  // NON-CHARACTER IN CHARACTER
  891.  // FORMAT.
  892.  
  893.  #include <header.h>
  894.  
  895.  int main()
  896.  {
  897.     // No cast needed here
  898.     char ch1 = 'A' ;
  899.     cout << ch1 << '\n' ;
  900.     char ch2 = 65 ;
  901.     cout << ch2 << '\n' ;
  902.  
  903.     // Cast needed here
  904.     int ch3 = 65 ;
  905.     cout << (char)ch3 << '\n' ;
  906.     int ch4 = 0101 ;
  907.     cout << (char)ch4 << '\n' ;
  908.     int ch5 = 0x41 ;
  909.     cout << (char)ch5 << '\n' ;
  910.  
  911.     return 0 ;
  912.  }
  913.  
  914. How about the opposite? That is, suppose you want a character to be shown
  915. in its decimal, octal, and hexadecimal representations. Once again, a cast is
  916. required, this time to type "int". By doing this cast in conjunction with the
  917. proper base setting, the desired result can be obtained. In this example, the
  918. character "ch" is shown in its decimal, octal, and hexadecimal
  919. representations.
  920.  
  921.  // EXAMPLE OUTPUT-32
  922.  
  923.  // HOW TO PRINT A CHARACTER AS A
  924.  // DECIMAL, OCTAL AND HEXADECIMAL
  925.  // VALUE.
  926.  
  927.  #include <header.h>
  928.  
  929.  int main()
  930.  {
  931.     char ch = 'A' ;
  932.  
  933.     cout << (int)ch << '\n' ;
  934.     cout.setf(ios::oct , ios::basefield) ;
  935.     cout << (int)ch << '\n' ;
  936.     cout.setf(ios::hex , ios::basefield) ;
  937.     cout << (int)ch << '\n' ;
  938.  
  939.     return 0 ;
  940.  }
  941.  
  942. The output of this program is:
  943.  
  944. 65
  945. 101
  946. 41
  947.  
  948. There is another way to guarantee that an integral value gets shown in its
  949. character format. That is with the use of the member function called "put"
  950. (think of the C function "putchar"). This function always outputs its one
  951. argument in character format, regardless of how it was defined. This
  952. example prints the character 'A' three times.
  953.  
  954.  // EXAMPLE OUTPUT-33
  955.  
  956.  // HOW TO USE THE MEMBER FUNCTION
  957.  // put TO OUTPUT A CHARACTER
  958.  
  959.  #include <header.h>
  960.  
  961.  int main()
  962.  {
  963.     char ch1 = 'A' ;
  964.     int ch2 = 65 ;
  965.  
  966.     cout.put(ch1) << '\n' ;
  967.     cout.put('A') << '\n' ;
  968.     cout.put(ch2) << '\n' ;
  969.  
  970.     return 0 ;
  971.  }
  972.  
  973. ******************************************************************
  974. Setting the Field Width
  975.  
  976. The field width in C++ works in a similar manner to that of C. If the total
  977. number of characters needed for output is less than the specified width,
  978. then the extra spaces will be filled with the current fill character. If the
  979. number of characters is greater than the specified width, then the width is
  980. 'expanded' to accommodate the entire field. (In C the fill character in a
  981. "printf" function call can only be either a zero or a space; in C++ it can be
  982. any character you desire. This topic is dicussed following width.)
  983.  
  984. If no width is ever specified, then the default value of zero is assumed (just
  985. as it is in C). To change the field width, use the member function "width"
  986. with one argument: the width value itself. Then the next field to be output
  987. will use this value.
  988.  
  989. For example, this program prints the number 1 right-justified and preceded
  990. by 4 blanks, while the number 23 has 3 preceding blanks.
  991.  
  992.  // EXAMPLE OUTPUT-41
  993.  
  994.  // HOW TO SET THE FIELD WIDTH
  995.  
  996.  #include <header.h>
  997.  
  998.  int main()
  999.  {
  1000.     cout.width(5) ;
  1001.     cout << 1 << '\n' ;
  1002.     cout.width(5) ;
  1003.     cout << 23 << '\n' ;
  1004.  
  1005.     return 0 ;
  1006.  }
  1007.  
  1008. The output of this program is:
  1009.  
  1010.     1
  1011.    23
  1012.  
  1013. Something should strike you as odd about this example. Why was it
  1014. necessary to write the line "cout.width(5)" twice? The answer is that the
  1015. width specification only applies to the next field to be output.  To prove this
  1016. statement, let's modify this example slightly and remove the second width
  1017. setting.
  1018.  
  1019.  // EXAMPLE OUTPUT-42
  1020.  
  1021.  // NOTE THAT THE WIDTH SETTING
  1022.  // ONLY APPLIES TO THE NEXT FIELD
  1023.  // TO BE OUTPUT
  1024.  
  1025.  #include <header.h>
  1026.  
  1027.  int main()
  1028.  {
  1029.     cout.width(5) ;
  1030.     cout << 1 << '\n' ;
  1031.     cout << 23  << '\n' ;
  1032.  
  1033.     return 0 ;
  1034.  }
  1035.  
  1036. The output of this program is:
  1037.  
  1038.     1
  1039. 23
  1040.  
  1041. Now the number 23 appears left-justified because the width reverted back
  1042. to its default value of 0.
  1043.  
  1044. In addition to setting the field width, the "width" function also returns the
  1045. value of the width just prior to the function call. If you wish to return this
  1046. value and leave it alone, then call the  width  function with no argument
  1047. specified.
  1048.  
  1049. IMPORTANT NOTE: Under the current implementation of Turbo C++,
  1050. the field width specification does NOT apply to character fields that are
  1051. output. This does not mean that the width reverts back to zero upon
  1052. encountering a character field, but instead is applied to the next non-
  1053. character field that is encountered. The patch IOPAT.ZIP in the
  1054. CompuServe BPROGB forum will fix this problem.
  1055.  
  1056. ******************************************************************
  1057. Specifying the Fill Character
  1058.  
  1059. If the total number of characters needed to display a field is less than the
  1060. current field width, the extra output spaces will be filled with the current
  1061. fill character. In a "printf" function call, the default fill character is a
  1062. blank, and you only have the option to change it to a zero.
  1063.  
  1064. In C++, however, you now have the option for any character to serve as the
  1065. fill character. As before, the default is a blank. The member function "fill"
  1066. is used to specify a new fill character. Once it is specified, it remains as
  1067. the fill character unless it is subsequently changed. The function takes a
  1068. single argument: the new fill character, and returns the previous fill
  1069. character. As with "width", it may be called with no actual argument if you
  1070. merely want to return the previous fill character.
  1071.  
  1072. This example outputs the default fill character, changes it to an asterisk, and
  1073. then proves that the current fill character is, indeed, an asterisk.
  1074.  
  1075.  // EXAMPLE OUTPUT-51
  1076.  
  1077.  // HOW TO SET THE FILL CHARACTER
  1078.  
  1079.  #include <header.h>
  1080.  
  1081.  int main()
  1082.  {
  1083.     const char quote = '\'' ;
  1084.     char old_fill = cout.fill('*') ;
  1085.     cout << "Old fill character is "
  1086.          << quote
  1087.          << old_fill
  1088.          << quote
  1089.          << '\n' ;
  1090.  
  1091.     cout << "It was changed to "
  1092.          << quote
  1093.          << cout.fill()
  1094.          << quote
  1095.          << '\n' ;
  1096.  
  1097.     return 0 ;
  1098.  }
  1099.  
  1100. The output of this program is:
  1101.  
  1102. Old fill character is ' '
  1103. It was changed to '*'
  1104.  
  1105. Now let's re-run example OUTPUT-41, but this time we'll fill the first
  1106. field with zeroes, and the second with asterisks.
  1107.  
  1108.  // EXAMPLE OUTPUT-52
  1109.  
  1110.  // A COMBINATION OF SETTING THE
  1111.  // FIELD WIDTH AND SPECIFYING
  1112.  // THE FILL CHARACTER
  1113.  
  1114.  #include <header.h>
  1115.  
  1116.  int main()
  1117.  {
  1118.     cout.width(5) ;
  1119.     cout.fill('0') ;
  1120.     cout << 1 << '\n' ;
  1121.     cout.width(5) ;
  1122.     cout.fill('*') ;
  1123.     cout << 23 << '\n' ;
  1124.  
  1125.     return 0 ;
  1126.  }
  1127.  
  1128. The output of this program is:
  1129.  
  1130. 00001
  1131. ***23
  1132.  
  1133. ******************************************************************
  1134. Field Justification
  1135.  
  1136. Whenever a field gets output, and the field width is greater than the number
  1137. of characters needed to display the field, the data is always right-justified
  1138. with the fill character used as padding to the left. (Of course, if the field
  1139. width is less than or equal to the number of characters needed, no
  1140. justification occurs and the fill character is ignored.)
  1141.  
  1142. Recall that there are 3 bits which are used to set the field justification:
  1143.  
  1144.  ios::left      0x0002     Left-justification of output
  1145.  ios::right     0x0004     Right-justification of output
  1146.  ios::internal  0x0008     Pad after sign or base indicator
  1147.  
  1148. If no bit is set in the field "x_flags", then the justification defaults to
  1149. right. Once the justification has been set, it remains set unless it is sub-
  1150. sequently changed. As with setting the base, there is a field called
  1151. "ios::adjustfield" which has been defined with all 3 justification bits turned
  1152. on. When setting the justification, this field should be used as the second
  1153. argument in the "setf" member function call to ensure that the other 2 bits are
  1154. turned off. To set the justification to left, use the member function "setf"
  1155. with the bit "ios::left", and to change it back to right, use the bit
  1156. "ios::right".
  1157.  
  1158. Here is example OUTPUT-41 again, this time with both fields left-justified.
  1159.  
  1160.  // EXAMPLE OUTPUT-60
  1161.  
  1162.  // HOW TO LEFT-JUSTIFY A FIELD
  1163.  
  1164.  #include <header.h>
  1165.  
  1166.  int main()
  1167.  {
  1168.     cout.setf(ios::left , ios::adjustfield) ;
  1169.     cout.width(5) ;
  1170.     cout.fill('0') ;
  1171.     cout << 1 << '\n' ;
  1172.     cout.width(5) ;
  1173.     cout.fill('*') ;
  1174.     cout << 23 << '\n' ;
  1175.  
  1176.     return 0 ;
  1177.  }
  1178.  
  1179. The output of this program is:
  1180.  
  1181. 10000
  1182. 23***
  1183.  
  1184. The justification resulting from the "ios::internal" bit means that padding
  1185. with the fill character, if any, will occur after the base of the number has
  1186. been shown (for octal and hexadecimal numbers) and before the number
  1187. itself. In the case of decimal numbers, the padding will occur after the sign
  1188. ('+' or '-') and before the number itself. That is, instead of padding
  1189. occurring on the left or on the right, it occurs "in the middle".
  1190.  
  1191. In this example, the base is shown, the fill character is set to '=', the
  1192. internal  bit is set on, the field width is set to 10, hexadecimal output is
  1193. requested, and the number 65 is printed. Then the same number is printed
  1194. again, but with left justification.
  1195.  
  1196.  // EXAMPLE OUTPUT-61
  1197.  
  1198.  // HOW TO DO INTERNAL JUSTIFICATION
  1199.  
  1200.  #include <header.h>
  1201.  
  1202.  int main()
  1203.  {
  1204.     cout.setf(ios::showbase) ;
  1205.     cout.fill('=') ;
  1206.     cout.setf(ios::internal , ios::adjustfield) ;
  1207.     cout.width(10) ;
  1208.     cout.setf(ios::hex , ios::basefield) ;
  1209.     cout << 65 << '\n' ;
  1210.     cout.setf(ios::left , ios::adjustfield) ;
  1211.     cout.width(10) ;
  1212.     cout << 65 << '\n' ;
  1213.  
  1214.     return 0 ;
  1215.  }
  1216.  
  1217.  The output of this program is:
  1218.  
  1219. 0x======41
  1220. 0x41======
  1221.  
  1222. ******************************************************************
  1223. Floating Point Output
  1224.  
  1225. Floating point numbers are output in C++ just like any other type of
  1226. number. However, the formatting is certainly different, and default values
  1227. are not the same as you would get from using a "printf" function call.
  1228.  
  1229. In this example some floating point constants are output.
  1230.  
  1231.  // EXAMPLE OUTPUT-70
  1232.  
  1233.  // DISPLAY SOME FLOATING POINTS
  1234.  // CONSTANTS WITHOUT ANY FORMATTING
  1235.  
  1236.  #include <header.h>
  1237.  
  1238.  int main()
  1239.  {
  1240.     cout << 1.2300 << '\n' ;
  1241.     cout << 4.00 << '\n' ;
  1242.     cout << 5.678E2 << '\n' ;
  1243.     cout << 0.0 << '\n' ;
  1244.  }
  1245.  
  1246. The output of this program is:
  1247.  
  1248. 1.23
  1249. 4
  1250. 567.8
  1251. 0
  1252.  
  1253. For the first constant, note that the 2 trailing zeroes were not printed. This
  1254. is certainly different from "printf" in which the default is to show 6
  1255. positions after the decimal point. In the second case, not only do the trailing
  1256. zeroes  not  show, but even the decimal point does not appear. In the third
  1257. case, the number prints in fixed point notation despite being keyed in
  1258. scientific notation. In the final case, at least one significant digit will
  1259. always appear.
  1260.  
  1261. Thus, we can infer that by default, all trailing zeroes, even the decimal
  1262. point, will be suppressed. If you really want to emulate how the "printf"
  1263. function works, you need to turn on the "ios::showpoint" bit. To revert
  1264. back to the default value, use the function "unsetf" to turn it off. Here is
  1265. the same example with this bit now on in the field "x_flags".
  1266.  
  1267.  // EXAMPLE OUTPUT-71
  1268.  
  1269.  // HOW TO EMULATE printf
  1270.  
  1271.  #include <header.h>
  1272.  
  1273.  int main()
  1274.  {
  1275.     cout.setf(ios::showpoint) ;
  1276.     cout << 1.2300 << '\n' ;
  1277.     cout << 4.00 << '\n' ;
  1278.     cout << 5.678E2 << '\n' ;
  1279.     cout << 0.0 << '\n' ;
  1280.  
  1281.     return 0 ;
  1282.  }
  1283.  
  1284. The output of this program is:
  1285.  
  1286. 1.230000
  1287. 4.000000
  1288. 567.800000
  1289. 0.000000
  1290.  
  1291. The next step is to override the default of 6 decimal positions. To do this,
  1292. use the member function "precision" in which the one argument is the
  1293. number of decimal positions to be shown. This function also returns the
  1294. previous value of the precision. If it is called without an argument, it
  1295. merely returns the current value of the precision and does not alter it. The
  1296. default precision is 0.
  1297.  
  1298. Here is the same example with the precision now set to 1.
  1299.  
  1300.  // EXAMPLE OUTPUT-72
  1301.  
  1302.  // HOW TO EMULATE printf AND SET
  1303.  // THE PRECISION
  1304.  
  1305.  #include <header.h>
  1306.  
  1307.  int main()
  1308.  {
  1309.     cout.setf(ios::showpoint) ;
  1310.     cout.precision(1) ;
  1311.     cout << 1.2300 << '\n' ;
  1312.     cout << 4.00 << '\n' ;
  1313.     cout << 5.678E2 << '\n' ;
  1314.     cout << 0.0 << '\n' ;
  1315.  
  1316.     return 0 ;
  1317.  }
  1318.  
  1319. The output of this program is:
  1320.  
  1321. 1.2
  1322. 4.0
  1323. 5.7e+02
  1324. 0.0
  1325.  
  1326. Note that the third answer is displayed in scientific notation. To guarantee
  1327. that all output is shown in either fixed decimal or scientific notation, recall
  1328. that the following bits are pre-defined in the class "ios":
  1329.  
  1330.    ios::scientific     0x0800    Use exponential notation on floating
  1331.                                  point numbers
  1332.    ios::fixed          0x1000    Use fixed decimal output on floating point
  1333.                                  numbers
  1334.  
  1335. If neither bit is turned on, then the compiler emulates the "%g" conversion
  1336. specification in a "printf" function call. Also recall that there is a constant
  1337. called "ios:floatfield" that is the value of these two bits ORed together, and
  1338. may be used as the second argument in a "setf" function call.
  1339.  
  1340.  // EXAMPLE OUTPUT-73
  1341.  
  1342.  // HOW TO EMULATE printf AND SET
  1343.  // THE PRECISION
  1344.  
  1345.  #include <header.h>
  1346.  
  1347.  int main()
  1348.  {
  1349.     cout.setf(ios::showpoint) ;
  1350.     cout.precision(2) ;
  1351.  
  1352.     // Guarantee fixed decimal
  1353.     cout.setf(ios::fixed , ios::floatfield) ;
  1354.     cout << 1.2300 << '\n' ;
  1355.     cout << 4.00 << '\n' ;
  1356.     cout << 5.678E2  << '\n' ;
  1357.     cout << 0.0 << '\n' ;
  1358.  
  1359.     // Guarantee scientific
  1360.     cout.setf(ios::scientific , ios::floatfield) ;
  1361.     cout << 1.2300 << '\n' ;
  1362.     cout << 4.00  << '\n' ;
  1363.     cout << 5.678E2<< '\n' ;
  1364.     cout << 0.0 << '\n' ;
  1365.  
  1366.     return 0 ;
  1367.  }
  1368.  
  1369. The output of this program is:
  1370.  
  1371. 1.23
  1372. 4.00
  1373. 567.80
  1374. 0.00
  1375. 1.23e+00
  1376. 4.00e+00
  1377. 5.68e+02
  1378. 0.00e+00
  1379.  
  1380. ******************************************************************
  1381. Printing addresses
  1382.  
  1383. The address of a variable (or instance of a class) can be generated by using
  1384. the address operator (&). Because the address operator can be applied to a
  1385. wide variety of types (both built-in and user-defined), the type of argument
  1386. can theoretically be "pointer to int" or "pointer to float" or even 'pointer to
  1387. my class type'. To accommodate all of these various types, the class
  1388. "ostream" contains an overloaded function "operator<<" to handle all such
  1389. argument types. This function is prototyped to accept an argument of type
  1390. "void*" which, according to the rules of argument matching, is acceptable to
  1391. the compiler as a "match".
  1392.  
  1393. In Turbo C++, this address is always shown in 32-bit (4 byte) hexadecimal
  1394. form, even though the default output base is decimal .
  1395.  
  1396.  // EXAMPLE OUTPUT-80
  1397.  
  1398.  // HOW TO PRINT AN ADDRESS
  1399.  
  1400.  #include <header.h>
  1401.  
  1402.  int main()
  1403.  {
  1404.     int number ;
  1405.  
  1406.     cout << "Address of number as a\n"
  1407.          << "  32-bit hex is "
  1408.          << &number
  1409.          << '\n' ;
  1410.  
  1411.     return 0 ;
  1412.  }
  1413.  
  1414. If you wish, you may view this address in decimal by using a cast to an
  1415. unsigned long.
  1416.  
  1417.  // EXAMPLE OUTPUT-81
  1418.  
  1419.  // HOW TO PRINT AN ADDRESS IN
  1420.  // DECIMAL AS AN UNSIGNED LONG
  1421.  
  1422.  #include <header.h>
  1423.  
  1424.  int main()
  1425.  {
  1426.     int number ;
  1427.  
  1428.     cout << "Address of number as a\n"
  1429.          << "  long integer is "
  1430.          << (unsigned long)&number
  1431.          << '\n' ;
  1432.  
  1433.     return 0 ;
  1434.  }
  1435.  
  1436. But since addresses are stored in 2 bytes when using the small memory
  1437. model, it's probably better to cast to an "unsigned int".
  1438.  
  1439.  // EXAMPLE OUTPUT-82
  1440.  
  1441.  // HOW TO PRINT AN ADDRESS IN
  1442.  // DECIMAL AS AN UNSIGNED INT
  1443.  
  1444.  #include <header.h>
  1445.  
  1446.  int main()
  1447.  {
  1448.     int number ;
  1449.  
  1450.      cout << "Address of number as an\n"
  1451.           << "  unsigned int is "
  1452.           << (unsigned)&number
  1453.           << '\n' ;
  1454.  
  1455.     return 0 ;
  1456.  }
  1457.  
  1458. When dealing with a string, a problem arises. It's the same problem that
  1459. occurred in C in a program fragment such as:
  1460.  
  1461.   char* ptr = "ABC" ;
  1462.   printf ("%s" , ptr) ;
  1463.  
  1464. No doubt the user will see "ABC" as the output. The problem is how to print
  1465. the ADDRESS contained within the pointer variable "ptr". The solution in C is
  1466. to provide a different conversion specification, namely "%p".
  1467.  
  1468. In C++ this program fragment:
  1469.  
  1470.   char* ptr = "ABC" ;
  1471.   cout << ptr ;
  1472.  
  1473. would also output "ABC" because the argument "ptr" is of type "char*" which
  1474. matches exactly an overloaded "operator<<" that accepts an argument of
  1475. type "char*". To emulate the "%p" in C++, you must override the built-in
  1476. type of "char*" with the type "void*" so that the "operator<<" function that
  1477. outputs an ADDRESS will be called instead.
  1478.  
  1479.  // EXAMPLE OUTPUT-83
  1480.  
  1481.  // HOW TO PRINT AN ADDRESS OF
  1482.  // A STRING
  1483.  
  1484.  #include <header.h>
  1485.  
  1486.  int main()
  1487.  {
  1488.     char* ptr = "ABC" ;
  1489.  
  1490.     cout << "The string itself is "
  1491.          << ptr
  1492.          << '\n' ;
  1493.  
  1494.     cout << "The address of the"
  1495.          << "string is "
  1496.          << (unsigned)(void*)ptr
  1497.          << '\n' ;
  1498.  
  1499.     return 0 ;
  1500.  }
  1501.  
  1502. ******************************************************************
  1503. Binary output
  1504.  
  1505. It's possible to take any internal representation of a C++ type and output it
  1506. as though it were just an array of characters. For a type such as "float", this
  1507. will produce meaningless output, but it may be useful for integers. To do
  1508. this, the member function  write  must be used. This function takes 2
  1509. arguments: The first is the address of the data to be output, and the second
  1510. is the number of bytes to be shown. Note that in the case of a string, the
  1511. null byte is treated just like any other byte.
  1512.  
  1513. Because the function "write" is declared to accept an argument of type
  1514. "char*", if the item you wish to print is not of this type, then the address
  1515. must be generated using the address operator, and then cast to type "char*".
  1516.  
  1517.  // EXAMPLE OUTPUT-90
  1518.  
  1519.  // HOW TO DISPLAY THE BINARY REPRE-
  1520.  // SENTATION OF A NUMBER
  1521.  
  1522.  #include <header.h>
  1523.  
  1524.  int main()
  1525.  {
  1526.     long number = 0x414243 ;
  1527.  
  1528.     cout.write((char*)&number , sizeof(number)) ;
  1529.     cout << '\n' ;
  1530.  
  1531.     return 0 ;
  1532.  }
  1533.  
  1534. Note that the output of this program is "CBA", because the address of a "long"
  1535. refers to the low-order byte.
  1536.  
  1537. ************************ SECTION 3 -- INPUT *********************************
  1538.  
  1539. Introduction
  1540.  
  1541. In addition to being able to use classes to control output, C++ stream I/O
  1542. classes also handle all input. Just as output consists of a stream of characters
  1543. being sent to some device, input consists of characters coming in from some
  1544. device and being translated into their proper defined type. In other words,
  1545. the characters '1', '2' and '3' could be the string '123' or the integer 123,
  1546. depending upon the type of the receiving field. Unlike output, the realm of
  1547. possibilities for 'formatting' simply does not exist when inputting data.
  1548.  
  1549. The class "istream" is derived from the class "ios", and it controls the input
  1550. handling functions. The global instance that is defined for you is called "cin",
  1551. and is defined as:
  1552.  
  1553.    istream cin ;
  1554.  
  1555. In addition to data members, the class "istream" contains functions to
  1556. operate upon these members. The function you will use the most often is
  1557. called the extraction operator, and it is written as:
  1558.  
  1559.    operator>>
  1560.  
  1561. The argument to this function is the variable name that you wish to contain
  1562. the input. The name 'extraction' comes from the fact that you are
  1563. 'extracting' (taking) data from the input stream.
  1564.  
  1565. For example, to input an integer, you would code:
  1566.  
  1567.    int number ;
  1568.    cin.operator>>(number) ;
  1569.  
  1570. As with the insertion operator, this code can be replaced with the simpler
  1571. form:
  1572.  
  1573.    int number ;
  1574.    cin >> number ;
  1575.  
  1576. Note that the type of the input variable determines how the characters from
  1577. the input stream are to be stored.
  1578.  
  1579. For example, this program inputs a number, character and float, and then
  1580. echoes them back.
  1581.  
  1582.  // EXAMPLE INPUT-01
  1583.  
  1584.  // HOW TO INPUT SOME SIMPLE TYPES
  1585.  
  1586.  #include <header.h>
  1587.  
  1588.  int main()
  1589.  {
  1590.     int number ;
  1591.     cout << "Enter a number: " ;
  1592.     cin >> number ;
  1593.     cout << "You entered: "
  1594.          << number
  1595.          << '\n' ;
  1596.  
  1597.     char ch ;
  1598.     cout << "Enter a character: " ;
  1599.     cin >> ch ;
  1600.     cout << "You entered: "
  1601.          << ch
  1602.          << '\n' ;
  1603.  
  1604.     float fl ;
  1605.     cout << "Enter a float: " ;
  1606.     cin >> fl ;
  1607.     cout << "You entered: "
  1608.          << fl
  1609.          << '\n' ;
  1610.  
  1611.     return 0 ;
  1612.  }
  1613.  
  1614. The extraction operator, like the insertion operator, can be chained
  1615. together.
  1616.  
  1617.  // EXAMPLE INPUT-02
  1618.  
  1619.  // EXTRACTION OPERATORS CAN BE
  1620.  // CHAINED TOGETHER
  1621.  
  1622.  #include <header.h>
  1623.  
  1624.  int main()
  1625.  {
  1626.     int number1 , number2 ;
  1627.     cout << "Enter 2 numbers: " ;
  1628.     cin >> number1 >> number2 ;
  1629.     cout << "You entered: "
  1630.          << number1
  1631.          << " and "
  1632.          << number2
  1633.          << '\n' ;
  1634.  
  1635.     return 0 ;
  1636.  }
  1637.  
  1638. Recall from the discussion on output that numbers can be displayed in
  1639. either their decimal, octal, or hexadecimal representations. This is done by
  1640. changing the base setting of the output stream. In a similar fashion, the base
  1641. of the input stream can be changed from its default setting of decimal to
  1642. either octal or hexadecimal. This is how the "%o" and "%x" conversion
  1643. specifications in a "scanf" function call can be emulated. For example, this
  1644. program prompts the user for numbers in decimal, octal, and hexadecimal
  1645. formats, then echoes each number back. Note that the output is always in
  1646. decimal because the setting of the output base has not been affected. In
  1647. other words, the base setting is stored separately for each stream.
  1648. Obviously, if an illegal input value is entered, the value will not be stored.
  1649. (NOTE: Borland Turbo C++ version 1.00 had a bug in regard to the
  1650. inputting of octal and hex numbers, but it was corrected in version 1.01.)
  1651.  
  1652.  // EXAMPLE INPUT-03
  1653.  
  1654.  // INTEGERS CAN BE INPUT IN ANY OF
  1655.  // 3 DIFFERENT BASES
  1656.  
  1657.  #include <header.h>
  1658.  
  1659.  int main()
  1660.  {
  1661.     int number ;
  1662.  
  1663.     cout << "Enter a decimal number: " ;
  1664.     cin >> number ;
  1665.     cout << "You entered: "
  1666.          << number
  1667.          << endl ;
  1668.  
  1669.     cout << "Enter an octal number: " ;
  1670.     cin.setf(ios::oct , ios::basefield) ;
  1671.     cin >> number ;
  1672.     cout << "You entered: "
  1673.          << number
  1674.          << endl ;
  1675.  
  1676.     cout << "Enter a hex number: " ;
  1677.     cin.setf(ios::hex , ios::basefield) ;
  1678.     cin >> number ;
  1679.     cout << "You entered: "
  1680.          << number
  1681.          << endl ;
  1682.  
  1683.     return 0 ;
  1684.  }
  1685.  
  1686. If the operator enters 65 for all 3 prompts, then the output of this program
  1687. is:
  1688.  
  1689. 65
  1690. 53
  1691. 101
  1692.  
  1693. *****************************************************************
  1694. Character Input
  1695.  
  1696. Characters may be read in using either the extraction operator ">>" or the
  1697. member function "get" (think of the C function "getchar"). If the extraction
  1698. operator is used, then leading whitespace is bypassed and the first non-
  1699. whitespace character is fetched. Also, a reference to the invoking instance is
  1700. returned. In this example, enter some spaces and tabs before striking a
  1701. character and <RETURN>.
  1702.  
  1703.  // EXAMPLE INPUT-11
  1704.  
  1705.  // DEMONSTRATE HOW TO READ IN A
  1706.  // CHARACTER AND BYPASS LEADING
  1707.  // WHITESPACE
  1708.  
  1709.  #include <header.h>
  1710.  
  1711.  int main()
  1712.  {
  1713.     const char quote = '\'' ;
  1714.  
  1715.     cout << "Enter a character: " ;
  1716.     char ch ;
  1717.     cin >> ch ;
  1718.     cout << "You entered: "
  1719.          << quote
  1720.          << ch
  1721.          << quote
  1722.          << '\n' ;
  1723.  
  1724.     return 0 ;
  1725.  }
  1726.  
  1727. Another method to read a character is to use the member function "get". This
  1728. can be done in two differenct ways. The first takes one argument: the
  1729. character variable name pass in by reference. It returns a reference to the
  1730. invoking instance. The difference between the extraction operator ">>" and
  1731. "get" is that "get" does not use the format flags, so it does not bypass
  1732. leading whitespace. In this example, enter some spaces and then another
  1733. character. You will see that the first space gets entered into the variable.
  1734.  
  1735.  // EXAMPLE INPUT-12
  1736.  
  1737.  // DEMONSTRATE HOW TO READ IN A
  1738.  // CHARACTER AND RETAIN LEADING
  1739.  // WHITESPACE USING get(char&)
  1740.  
  1741.  #include <header.h>
  1742.  
  1743.  int main()
  1744.  {
  1745.     const char quote = '\'' ;
  1746.  
  1747.     cout << "Enter a character: " ;
  1748.     char ch ;
  1749.     cin.get(ch) ;
  1750.     cout << "You entered: "
  1751.          << quote
  1752.          << ch
  1753.          << quote
  1754.          << '\n' ;
  1755.  
  1756.     return 0 ;
  1757.  }
  1758.  
  1759. The other function using "get" takes no input argument (just like "getchar" in
  1760. C) and returns a value of type "int", which represents the character just read,
  1761. or the "EOF" constant if either (a) end-of-file was detected, or (b) no
  1762. character could be read. This function is unique in that it does not set
  1763. 'failbit'. The other unformatted extractors will set 'failbit' if called at
  1764. end-of-file time, so that no other characters can be read.
  1765.  
  1766. Here is example INPUT-12 repeated, but now it uses "get()" and checks for
  1767. end-of-file. Because the variable "ch" must be defined as type "int", don't
  1768. forget the cast in order to display it as a character.
  1769.  
  1770.  // EXAMPLE INPUT-13
  1771.  
  1772.  // DEMONSTRATE HOW TO READ IN A
  1773.  // CHARACTER AND RETAIN LEADING
  1774.  // WHITESPACE USING get()
  1775.  
  1776.  #include <header.h>
  1777.  
  1778.  int main()
  1779.  {
  1780.     const char quote = '\'' ;
  1781.  
  1782.     cout << "Enter a character: " ;
  1783.     int ch ;
  1784.     ch = cin.get() ;
  1785.     if (ch != EOF)
  1786.        cout << "You entered: "
  1787.             << quote
  1788.             << (char)ch
  1789.             << quote
  1790.             << '\n' ;
  1791.     else
  1792.        cout << "End-of-file\n" ;
  1793.  
  1794.     return 0 ;
  1795.  }
  1796.  
  1797. ******************************************************************
  1798. String Input
  1799.  
  1800. As with character input, strings may be entered using the extraction
  1801. operator or the overloaded member function "get". With the extraction
  1802. operator, leading whitespace is bypassed, and the first whitespace
  1803. encountered terminates the input. (This acts just like the function "scanf".)
  1804.  
  1805.  // EXAMPLE INPUT-21
  1806.  
  1807.  // DEMONSTRATE HOW TO READ IN A
  1808.  // STRING AND BYPASS WHITESPACE
  1809.  // TOTALLY (LOOKS LIKE scanf)
  1810.  
  1811.  #include <header.h>
  1812.  
  1813.  const int length = 100 ;
  1814.  
  1815.  int main()
  1816.  {
  1817.     char string [length] ;
  1818.     const char quote = '\"' ;
  1819.  
  1820.     cout << "Enter a string: " ;
  1821.     cin >> string ;
  1822.     cout << "Your string: "
  1823.          << quote
  1824.          << string
  1825.          << quote
  1826.          << '\n' ;
  1827.  
  1828.     return 0 ;
  1829.  }
  1830.  
  1831. But just like "scanf", the possibility exists for a program hang or crash if
  1832. the operator enters more characters than can safely be accommodated by the
  1833. string array. In other words, run this program and enter more than 10
  1834. characters.
  1835.  
  1836.  // EXAMPLE INPUT-22
  1837.  
  1838.  // IT'S POSSIBLE TO OVERFLOW AN
  1839.  // ARRAY WHEN INPUTTING A STRING
  1840.  
  1841.  #include <header.h>
  1842.  
  1843.  const int max = 10 ;
  1844.  
  1845.  int main()
  1846.  {
  1847.     char array[max] ;
  1848.  
  1849.     cout << "Enter a string: " ;
  1850.     cin >> array ;
  1851.     cout << "You entered: "
  1852.          << array
  1853.          << '\n' ;
  1854.  
  1855.     return 0 ;
  1856.  }
  1857.  
  1858. If it didn't bomb, consider yourself lucky. To guard against this disaster,
  1859. you may set the width of the input stream to physically limit the number of
  1860. characters that will be stored. This is done by using the member function
  1861. "width" in the class "istream". Run this program and enter the letters 'A'
  1862. through 'M'. Note that only the letters 'A' through 'I' got stored into the
  1863. string (the last byte is always reserved for the null character) and the
  1864. remaining characters remain in the input buffer.
  1865.  
  1866.  // EXAMPLE INPUT-23
  1867.  
  1868.  // HOW TO AVOID OVERFLOWING AN
  1869.  // ARRAY WHEN INPUTTING A STRING
  1870.  // WITH THE EXTRACTION OPERATOR
  1871.  
  1872.  #include <header.h>
  1873.  
  1874.  const int max = 10 ;
  1875.  
  1876.  int main()
  1877.  {
  1878.     char array[max] ;
  1879.  
  1880.     cout << "Enter a string: " ;
  1881.     cin.width(max) ;
  1882.     cin >> array ;
  1883.     cout << "You entered: "
  1884.          << array
  1885.          << '\n' ;
  1886.  
  1887.     return 0 ;
  1888.  }
  1889.  
  1890. Caution: Just like the "width" function used for output, the input "width"
  1891. function only applies to the next item to be input.
  1892.  
  1893. Another way to read in strings is to use the member function  get  with 3
  1894. arguments. (Note the similarity to the C function "fgets".) The first
  1895. argument is the address of the string area, the second is the maximum
  1896. number of characters (less 1) than can be read in, and the third specifies the
  1897. terminating character (the one that will stop the transfer of characters from
  1898. the buffer into the string array). This third argument defaults to the value
  1899. '\n', which is the <RETURN> key. Note, however, that if it is changed to
  1900. some other character, then the <RETURN> key must still be pressed for
  1901. the input action to cease. Both leading whitespace and embedded
  1902. whitespace are retained as part of the string value.
  1903.  
  1904.  // EXAMPLE INPUT-24
  1905.  
  1906.  // DEMONSTRATE HOW TO READ IN A
  1907.  // STRING AND RETAIN WHITESPACE,
  1908.  // BOTH LEADING AND EMBEDDED
  1909.  
  1910.  #include <header.h>
  1911.  
  1912.  const int length = 100 ;
  1913.  
  1914.  int main()
  1915.  {
  1916.     char string [length] ;
  1917.     const char quote = '\"' ;
  1918.  
  1919.     cout << "Enter a string: " ;
  1920.     cin.get(string , length) ;
  1921.     cout << "Your string: "
  1922.          << quote
  1923.          << string
  1924.          << quote
  1925.          << '\n' ;
  1926.  
  1927.     return 0 ;
  1928.  }
  1929.  
  1930. A slight variation on the function "get" taking 3 arguments is the function
  1931. "getline". The only difference is that "getline" extracts the newline character
  1932. ('\n') from the input buffer, whereas "get" leaves it alone (and, presumably,
  1933. must then be flushed by the programmer). In Turbo C++ version 1.01, this
  1934. newline character is made part of the string, even though the A T & T spec
  1935. does not say to do this.
  1936.  
  1937.  // EXAMPLE INPUT-25
  1938.  
  1939.  // TEST getline FUNCTION
  1940.  
  1941.  // NOTE THAT THE LAST DOUBLE QUOTE
  1942.  // APPEARS ON THE FOLLOWING LINE
  1943.  // DUE TO THE INCLUSION OF THE
  1944.  // NEWLINE CHARACTER IN string
  1945.  
  1946.  #include <header.h>
  1947.  
  1948.  const int length = 100 ;
  1949.  
  1950.  int main()
  1951.  {
  1952.     char string [length] ;
  1953.     const char quote = '\"' ;
  1954.  
  1955.     cout << "Enter a string: " ;
  1956.     cin.getline(string , length) ;
  1957.     cout << "Your string: "
  1958.          << quote
  1959.          << string
  1960.          << quote ;
  1961.  
  1962.     return 0 ;
  1963.  }
  1964.  
  1965. ******************************************************************
  1966. Checking for End-Of-File
  1967.  
  1968. When reading data from the keyboard or a file, the programmer must
  1969. always be on guard for the occurrence of an end-of-file mark (in DOS it's
  1970. the character ^Z or decimal value 26 from text files). This is comparable to
  1971. detecting the value "EOF" when doing a "scanf" in C.
  1972.  
  1973. In C++, the member function "eof" in the class "istream" taking no arguments
  1974. will report 'true' if the end-of-file condition was found, 'false' if not
  1975. found.
  1976.  
  1977. Normally data is obtained within a 'while' loop, with the loop continuing to
  1978. execute as long as end-of-file is  not  detected. This situation could be coded
  1979. like this:
  1980.  
  1981.  // EXAMPLE INPUT-31
  1982.  
  1983.  // ENTER A NUMBER AND LOOP
  1984.  // UNTIL EOF IS DETECTED
  1985.  
  1986.  #include <header.h>
  1987.  
  1988.  int main()
  1989.  {
  1990.     cout << "Enter a number: " ;
  1991.     int num ;
  1992.     cin >> num ;
  1993.     while (!cin.eof())
  1994.     {
  1995.        cout << "You entered: "
  1996.             << num
  1997.             << '\n' ;
  1998.        cout << "\nNext number: " ;
  1999.        cin >> num ;
  2000.     }
  2001.  
  2002.     return 0 ;
  2003.  }
  2004.  
  2005. While this program certainly works, there is a better way to code it. Since
  2006. the statement:
  2007.  
  2008.    cin >> num ;
  2009.  
  2010. returns a reference to the invoking object itself (namely "cin"), this object
  2011. can be used as the invoking object for the "eof" member function call. Thus,
  2012. the revised code looks like:
  2013.  
  2014.  // EXAMPLE INPUT-32
  2015.  
  2016.  // A BETTER METHOD OF CODING
  2017.  // EXAMPLE INPUT-31
  2018.  
  2019.  #include <header.h>
  2020.  
  2021.  int main()
  2022.  {
  2023.     cout << "Enter a number: " ;
  2024.     int num ;
  2025.     while (!(cin >> num).eof())
  2026.     {
  2027.       cout << "You entered: "
  2028.            << num
  2029.            << '\n' ;
  2030.       cout << "\nNext number: " ;
  2031.     }
  2032.  
  2033.     return 0 ;
  2034.  }
  2035.  
  2036. Notice how the read and check for end-of-file have been combined to form
  2037. the Boolean condition of the 'while' loop.
  2038.  
  2039. ******************************************************************
  2040. Checking for Errors
  2041.  
  2042. Unfortunately, we live in an imperfect world. People don't smile, cars
  2043. crash, checks bounce, and data entry operators don't always do what they're
  2044. supposed to do. This means that as a programmer you must be responsible
  2045. for making your code as 'operator-proof' as possible. In other words, no
  2046. matter what the user may enter as 'data', your program must capture it and
  2047. successfully trap all error conditions to avoid such catastrophes as 'garbage
  2048. in, garbage out', aborts, hangs, endless loops, etc.
  2049.  
  2050. When expecting character or string input, there's not too much that can go
  2051. wrong, other than array overflow which has already been covered. But
  2052. with numeric data, such as "int"s, "float"s and "double"s, only certain
  2053. keystrokes in a prescribed order and considered to be valid. For example,
  2054. when you expect a decimal integer to be input, the user may enter a sign (+
  2055. or -) followed by the digits 0 through 9. An entry of A12 is obviously
  2056. invalid. An entry such as 12A, however, is considered to be the number 12,
  2057. with the "invalid" character 'A' serving to terminate the numeric portion of
  2058. the input stream. In addition, any whitespace character terminates a
  2059. numeric entry, and all leading whitespace characters are bypassed
  2060. automatically.
  2061.  
  2062. There are several ways to check for 'garbage' input when expecting valid
  2063. numeric data. Within the class "istream" the member function "good" will
  2064. return 'true' if the preceding operation succeeded, 'false' otherwise. In
  2065. addition, the member function "fail" will do just the opposite.
  2066.  
  2067. Another way to check for an input error is to use the overloaded "operator!"
  2068. (Boolean not) on the instance of "istream". This operator will return
  2069. 'true' if an error occurred, 'false' otherwise. Similarly, testing the
  2070. instance itself as a Boolean value will return 'true' if the input was good,
  2071. 'false' otherwise.
  2072.  
  2073. Note that in the header file <header.h> the function "IOFLAGS" has been
  2074. defined to accept an instance of an input stream as an argument, and will
  2075. display the various input states. The default argument is the instance "cin".
  2076. To test this, trying entering some numeric and non-numeric data for this
  2077. program, as well as end-of-file.
  2078.  
  2079.  // EXAMPLE INPUT-41
  2080.  
  2081.  // TEST THE INPUT STREAM STATES
  2082.  
  2083.  #include <header.h>
  2084.  
  2085.  int main()
  2086.  {
  2087.     cout << "Enter a number: " ;
  2088.     int number ;
  2089.     cin >> number ;
  2090.     IOFLAGS() ;
  2091.  
  2092.     return 0 ;
  2093.  }
  2094.  
  2095. Now that you see what does and does not work, the next problem is how to
  2096. eliminate the excess, or garbage, characters from the input stream. This can
  2097. be accomplished by reading 1 character at a time until the <RETURN>
  2098. ('\n') character has been read. (Of course this method assumes that if an
  2099. error condition is encountered, then the integrity of the remaining
  2100. characters in the buffer is in question.) In addition, when an error occurs,
  2101. the status of the input stream is changed from 'good' to 'fail' and  no more
  2102. characters can be read until the status is reset to 'good' . To do this, you
  2103. must call upon the "istream" member function "clear" with no arguments (the
  2104. default argument is 0, which means 'set the status of the stream to 'good'').
  2105.  
  2106. To save you the trouble of having to code a function to accomplish this
  2107. 'flushing' task, the file <header.h> has a manipulator called FLUSH that will
  2108. do this for you. (The subject of manipulators and how they work will be
  2109. covered in the section on manipulators.)
  2110.  
  2111. Thus, an 'operator-proof' program that loops while reading numbers and
  2112. checking for end-of-file and garbage input might resemble this:
  2113.  
  2114.  // EXAMPLE INPUT-42
  2115.  
  2116.  // SHOW HOW TO HANDLE ANYTHING
  2117.  // THE OPERATOR CAN THROW AT
  2118.  // THE PROGRAM
  2119.  
  2120.  #include <header.h>
  2121.  
  2122.  int main()
  2123.  {
  2124.     cout << "\nEnter a number: " ;
  2125.     int number ;
  2126.     while (!(cin >> number).eof())
  2127.     {
  2128.       // Test for a bad number
  2129.       if (!cin)
  2130.         cout << "Input error!\n" ;
  2131.  
  2132.       // Process a good number
  2133.       else
  2134.         cout << "YOU ENTERED: "
  2135.              << number
  2136.              << endl ;
  2137.  
  2138.       // Clear out the input buffer.
  2139.       cin >> FLUSH ;
  2140.  
  2141.       cout << "\nNext number: " ;
  2142.     }
  2143.     cout << "\nEND OF PROGRAM\n" ;
  2144.  
  2145.     return 0 ;
  2146.  }
  2147.  
  2148. One note about the logic of this program. If 2 valid numbers are entered
  2149. before the user presses <RETURN>, then only the first number will be
  2150. processed; the second will be flushed. You may or may not want this to
  2151. happen, depending upon your design philosophy.
  2152.  
  2153. ************************ SECTION 4 -- MANIPULATORS ************************
  2154.  
  2155. Introduction
  2156.  
  2157. As you have probably noticed by now, the elimination of conversion
  2158. specifications ("%d", "%c", etc.) found in the "scanf" and "printf" functions
  2159. in C causes you to do a lot of extra coding to accomplish the same end result.
  2160. For example, to output a number in hex, the specification "%x" does the job
  2161. in a "printf" statement, but with <iostream.h> you have to write:
  2162.  
  2163.   cout.setf(ios::hex , ios::basefield) ;
  2164.  
  2165. before outputting the number itself.
  2166.  
  2167. Fortunately, the input and output stream classes provide the capability to
  2168. eliminate much of this tedious coding, as well as a method to combine the
  2169. setting of the stream state with the actual outputting (or inputting) of the
  2170. data itself. This method uses what is called a 'manipulator'. The term
  2171. comes from the fact that a manipulator does just what it implies: it
  2172. manipulates, or changes, the state of the stream.
  2173.  
  2174. In the same sense that a call of a function causes that function to do any
  2175. number of individual tasks the programmer may specify, a manipulator is
  2176. also a function that sets the stream state. The input and output classes come
  2177. with some manipulators already built in, and a nice feature is that you can
  2178. easily define your own.
  2179.  
  2180. The one peculiar aspect about manipulators is that they are always called
  2181. 'indirectly' by a separate function. This other function knows which
  2182. individual manipulator to call because it has the manipulator's  address  as
  2183. its one argument. How does it get this address? When the name of a function is
  2184. written without the open and close parentheses, the compiler generates the
  2185. address  of the function instead of actually calling the function. This address
  2186. can, in turn, be passed as an argument to another function. Of course, this
  2187. address must be stored into a variable declared as 'pointer to function' and
  2188. which has the proper return type and argument list.
  2189.  
  2190. In this example the address of the function "print" is passed as an argument
  2191. to the function called "test", stored into the pointer variable called "ptr",
  2192. and then executed via the statement "ptr();". Note that this is the same as
  2193. coding (*ptr)();
  2194.  
  2195.  // EXAMPLE MANIP-01
  2196.  
  2197.  // HOW TO PASS THE ADDRESS OF A
  2198.  // FUNCTION AS AN ARGUMENT
  2199.  
  2200.  #include <header.h>
  2201.  
  2202.  // Function declarations
  2203.  
  2204.  void print() ;
  2205.  void test(void (*)()) ;
  2206.  
  2207.  int main()
  2208.  {
  2209.     test(print) ;
  2210.  
  2211.     return 0 ;
  2212.  }
  2213.  
  2214.  void print()
  2215.  {
  2216.     cout << "print function\n" ;
  2217.  }
  2218.  
  2219.  void test(void (*ptr)())
  2220.  {
  2221.     ptr() ;
  2222.  }
  2223.  
  2224. Since the manipulators to handle input and output stream states can be
  2225. chained with other arguments, then (assuming output) generically they have
  2226. the form:
  2227.  
  2228.   cout << data-item1 << manipulator << data-item2 ;
  2229.  
  2230. In order to preserve the ability to concatenate successive calls to the
  2231. insertion operator function, each manipulator function must adhere to the
  2232. rule that the invoking instance is always passed in by reference and
  2233. returned by reference. This means that all manipulator functions have the
  2234. format:
  2235.  
  2236.  ostream& manipulator_name(ostream& strm)
  2237.  {
  2238.    // your code here
  2239.   return strm ;
  2240.  }
  2241.  
  2242. In a similar fashion, all input manipulators have the format:
  2243.  
  2244.  istream& manipulator_name(istream& strm)
  2245.  {
  2246.    // your code here
  2247.   return strm ;
  2248.  }
  2249.  
  2250. To accommodate an argument of type 'pointer to function', the class
  2251. "ostream" has an overloaded insertion operator similar to this:
  2252.  
  2253.  ostream& operator<<(ostream& (*ptr)(ostream&))
  2254.  {
  2255.   return (*ptr)(*this) ;
  2256.  }
  2257.  
  2258.  The class  istream  has an overloaded insertion operator similar to this:
  2259.  
  2260.  istream& operator<<(istream& (*ptr)(istream&))
  2261.  {
  2262.   return (*ptr)(*this) ;
  2263.  }
  2264.  
  2265. It's these two functions that call upon your manipulator function whose
  2266. address has been stored into the pointer variable "ptr".
  2267.  
  2268. As a test, here is a program that creates a manipulator function called
  2269. "manip" that sets the field width to 5 and the fill character to '*'.
  2270.  
  2271.  // EXAMPLE MANIP-02
  2272.  
  2273.  // HOW TO PASS CREATE YOUR OWN
  2274.  // MANIPULATOR
  2275.  
  2276.  #include <header.h>
  2277.  
  2278.  ostream& manip(ostream& strm)
  2279.  {
  2280.     strm.width(5) ;
  2281.     strm.fill('*') ;
  2282.     return strm ;
  2283.  }
  2284.  
  2285.  int main()
  2286.  {
  2287.     cout << manip
  2288.          << 23
  2289.          << '\n' ;
  2290.  
  2291.     return 0 ;
  2292.  }
  2293.  
  2294. The output of this program is:
  2295.  
  2296. ***23
  2297.  
  2298. ******************************************************************
  2299. Built-in Manipulators Taking No Arguments
  2300.  
  2301. Because some output (and input) stream manipulations are done so
  2302. frequently, the header file <iostream.h> includes some pre-defined
  2303. manipulators. These manipulators may take no arguments, or 1 argument.
  2304. Let's first consider some built-in manipulators that take no arguments.
  2305.  
  2306. As the first example, the manipulator "endl" is designed to output a new line
  2307. character and flush the output buffer. Use may use this in place of '\n'. For
  2308. example,
  2309.  
  2310.  // EXAMPLE MANIP-11
  2311.  
  2312.  // THE endl MANIPULATOR
  2313.  
  2314.  #include <header.h>
  2315.  
  2316.  int main()
  2317.  {
  2318.     cout << 1
  2319.          << endl
  2320.          << 2
  2321.          << endl ;
  2322.  
  2323.     return 0 ;
  2324.  }
  2325.  
  2326. The output of this program is:
  2327.  
  2328. 1
  2329. 2
  2330.  
  2331. The manipulators "dec", "oct" and "hex" work for both input and output
  2332. operations, and set the stream state accordingly. For example,
  2333.  
  2334.  // EXAMPLE MANIP-12
  2335.  
  2336.  // SETTING THE STREAM STATES USING
  2337.  // MANIPULATORS
  2338.  
  2339.  #include <header.h>
  2340.  
  2341.  int main()
  2342.  {
  2343.     cout << "Input a hex number: " ;
  2344.     int number ;
  2345.     cin >> hex >> number ;
  2346.     cout << "The number in octal is "
  2347.          << oct
  2348.          << number
  2349.          << endl ;
  2350.  
  2351.     return 0 ;
  2352.  }
  2353.  
  2354. If you enter the number '1f' (hex), you will then see the number 37 (octal).
  2355.  
  2356. Recall that when using the function "get" with 3 arguments to read in a
  2357. string, both leading and embedded whitespace are retained. If you want to
  2358. bypass the leading whitespace, and still retain the embedded whitespace,
  2359. then use the input manipulator "ws". In this program enter some leading
  2360. whitespace, then some significant characters including embedded
  2361. whitespace.
  2362.  
  2363.  // EXAMPLE MANIP-13
  2364.  
  2365.  // DEMONSTRATE HOW TO READ IN A
  2366.  // STRING AND RETAIN EMBEDDED
  2367.  // WHITE SPACE, BUT BYPASS
  2368.  // LEADING WHITE SPACE
  2369.  
  2370.  #include <header.h>
  2371.  
  2372.  const int length = 100 ;
  2373.  
  2374.  int main()
  2375.  {
  2376.     char string [length] ;
  2377.     const char quote = '\"' ;
  2378.  
  2379.     cout << "Enter a string: " ;
  2380.     cin >> ws ;
  2381.     cin.get(string , length) ;
  2382.     cout << "Your string: "
  2383.          << quote
  2384.          << string
  2385.          << quote
  2386.          << endl ;
  2387.  
  2388.     return 0 ;
  2389.  }
  2390.  
  2391. There is one other built-in manipulator that takes no argument: "ends". This
  2392. causes a null character to be output, and is useful for objects of type
  2393. strstream .
  2394.  
  2395. ******************************************************************
  2396. Built-in Manipulators Taking 1 Argument
  2397.  
  2398. Because a manipulator that takes 1 argument requires special handling by
  2399. the compiler, a separate header file  must  be included with each program.
  2400. This file is called <iomanip.h>. Note that in the file <header.h> it is
  2401. automatically included.
  2402.  
  2403. Perhaps the most frequently used manipulator taking an argument is "setw".
  2404. Like its counterpart, the member function "width()", it is used to set the
  2405. field width  for the next output item only.  But since manipulators are
  2406. designed to be coded 'in line' with data to be output, they do not return a
  2407. value (which would cause spurious data to appear in the output buffer). The
  2408. one argument is, of course, the field width itself.
  2409.  
  2410. Here is example OUTPUT-41 again, this time using a manipulator to set the
  2411. field width.
  2412.  
  2413.  // EXAMPLE MANIP-21
  2414.  
  2415.  // HOW TO SET THE FIELD WIDTH
  2416.  // USING A MANIPULATOR
  2417.  
  2418.  #include <header.h>
  2419.  
  2420.  int main()
  2421.  {
  2422.     cout << setw(5)
  2423.          << 1
  2424.          << endl ;
  2425.     cout << setw(5)
  2426.          << 23
  2427.          << endl ;
  2428.  
  2429.     return 0 ;
  2430.  }
  2431.  
  2432. Another frequently used manipulator is the one that sets the fill character.
  2433. It is called "setfill" and, as you would expect, the 1 argument is the fill
  2434. character itself.
  2435.  
  2436. Here is example OUTPUT-52 again, this time using manipulators to set the
  2437. field width and fill character.
  2438.  
  2439.  // EXAMPLE MANIP-22
  2440.  
  2441.  // A COMBINATION OF SETTING THE
  2442.  // FIELD WIDTH AND SPECIFYING
  2443.  // THE FILL CHARACTER USING
  2444.  // MANIPULATORS
  2445.  
  2446.  #include <header.h>
  2447.  
  2448.  int main()
  2449.  {
  2450.     cout << setw(5)
  2451.          << setfill('0')
  2452.          << 1
  2453.          << endl ;
  2454.     cout << setw(5)
  2455.          << setfill('*')
  2456.          << 23
  2457.          << endl ;
  2458.  
  2459.     return 0 ;
  2460.  }
  2461.  
  2462. The other manipulators that take an argument are:
  2463.  
  2464.    resetiosflags(long flag)  -- turns off the bits specified in "flag"
  2465.                                 (input and output)
  2466.    setbase(int base)  -- sets the output base to decimal if "base" if 0
  2467.                          or 10; to octal if "base" is 8; to hexadecimal
  2468.                          if "base" is 16 (output)
  2469.    setiosflags(long flag)  -- turns on the bits specified in "flag" (input
  2470.                               and output)
  2471.    setprecision(int prec)  -- sets the number of digits displayed after the
  2472.                               decimal point to "prec" (output)
  2473.  
  2474. ******************************************************************
  2475. Creating Your Own Manipulators Taking 1 Argument
  2476.  
  2477. The explanation of how manipulators taking 1 argument are handled by the
  2478. compiler is too complex to be explained here, so let's just see how it is
  2479. coded.
  2480.  
  2481. First, the generic form (assuming output) of the manipulator is:
  2482.  
  2483.  ostream& manipulator-name(ostream& strm , type arg)
  2484.  {
  2485.    // your code here using arg
  2486.    return strm ;
  2487.  }
  2488.  
  2489. where "type" is either "int" or "long", and "arg" is the formal argument name.
  2490.  
  2491. Next, you must include this code:
  2492.  
  2493.  OMANIP(type) manipulator-name(type arg)
  2494.  {
  2495.     return OMANIP(type) (manipulator-name , arg) ;
  2496.  }
  2497.  
  2498. where "OMANIP" is a class defined in <iomanip.h>.
  2499.  
  2500. For example, here is a manipulator called "manip" that sets the field width to
  2501. whatever the argument happens to be, and also sets the fill character to '*'.
  2502.  
  2503.  // EXAMPLE MANIP-31
  2504.  
  2505.  // HOW TO CREATE A MANIPULATOR THAT
  2506.  // TAKES 1 ARGUMENT
  2507.  
  2508.  #include <header.h>
  2509.  
  2510.  ostream& manip(ostream& strm , int length)
  2511.  {
  2512.     strm << setw(length) << setfill('*') ;
  2513.     return strm ;
  2514.  }
  2515.  
  2516.  OMANIP(int) manip(int length)
  2517.  {
  2518.     return OMANIP(int) (manip , length) ;
  2519.  }
  2520.  
  2521.  int main()
  2522.  {
  2523.     cout << manip(7)
  2524.          << 123
  2525.          << endl ;
  2526.     cout << manip(5)
  2527.          << 45
  2528.          << endl ;
  2529.  
  2530.     return 0 ;
  2531.  }
  2532.  
  2533. The output of this program is:
  2534.  
  2535. ****123
  2536. ***45
  2537.  
  2538. If you wish to use a type other than "int" or "long", then you must include the
  2539. following statement:
  2540.  
  2541.   IOMANIPdeclare(type) ;
  2542.  
  2543. where "type" is either "char", "float", "double", etc.
  2544.  
  2545. Here is the same example, but now it is the fill character that is variable.
  2546.  
  2547.  // EXAMPLE MANIP-32
  2548.  
  2549.  // HOW TO CREATE A MANIPULATOR THAT
  2550.  // TAKES 1 ARGUMENT, AND THAT ARGUMENT
  2551.  // IS NOT int OR long
  2552.  
  2553.  #include <header.h>
  2554.  
  2555.  // Don't forget this statement
  2556.  IOMANIPdeclare(char) ;
  2557.  
  2558.  ostream& manip(ostream& strm , char ch)
  2559.  {
  2560.     strm << setw(7) << setfill(ch) ;
  2561.     return strm ;
  2562.  }
  2563.  
  2564.  OMANIP(char) manip(char ch)
  2565.  {
  2566.     return OMANIP(char) (manip , ch) ;
  2567.  }
  2568.  
  2569.  int main()
  2570.  {
  2571.     cout << manip('*')
  2572.          << 123
  2573.          << endl ;
  2574.     cout << manip('$')
  2575.          << 45
  2576.          << endl ;
  2577.  
  2578.     return 0 ;
  2579.  }
  2580.  
  2581. The output of this program is:
  2582.  
  2583. ****123
  2584. $$$$$45
  2585.  
  2586. Finally, take a look at the file <header.h> for some useful manipulators that
  2587. have already been defined for you.
  2588.  
  2589. ************************* SECTION 5 -- FILE I/O ****************************
  2590.  
  2591. Introduction
  2592.  
  2593. File input/output using <iostream.h> involves any of these 3 operations:
  2594.  
  2595.  1) Reading a file
  2596.  2) Writing a file
  2597.  3) Both reading and writing a file
  2598.  
  2599. To handle these operations, special classes have already been defined. They
  2600. are:
  2601.  
  2602.  Read -- class  ifstream  (derived from  istream )
  2603.  Write -- class  ofstream  (derived from  ostream )
  2604.  Both -- class "fstream" (derived from  iostream )
  2605.  
  2606. To use any of these classes, you must:
  2607.  
  2608.   #include <fstream.h>
  2609.  
  2610. which automatically includes the header file <iostream.h>. (The file
  2611. <fstream.h> is already included in <header.h>.)
  2612.  
  2613. There are no pre-defined instances of these classes comparable to "cin" and
  2614. "cout". Therefore, the first step in using file I/O is to create an instance of the
  2615. appropriate class, e.g.,
  2616.  
  2617.   ifstream file_in ;
  2618.   ofstream file_out ;
  2619.   fstream  file_both ;
  2620.  
  2621. ****************************************************************
  2622. Using the instances
  2623.  
  2624. The first step in using the file instances is to open the disk file. In any
  2625. computer language this means establishing a communication link between
  2626. your code and the external file. Each of the 3 classes provides the member
  2627. function called  open  to do this. The declarations for these  open  functions
  2628. are as follows:
  2629.  
  2630.   void ifstream::open(const char* name ,
  2631.                       int m = ios::in ,
  2632.                       int prot = filebuf::openprot) ;
  2633.  
  2634.   void ofstream::open(const char* name ,
  2635.                       int m = ios::out ,
  2636.                       int prot = filebuf::openprot) ;
  2637.  
  2638.   void fstream::open(const char* name ,
  2639.                      int m,
  2640.                      int prot = filebuf::openprot) ;
  2641.  
  2642. The first argument is the external file name passed in as a constant string
  2643. literal.
  2644.  
  2645. The second argument is the file mode, and comes from a  public
  2646. enumerated type in the class "ios". There are eight possible modes, as
  2647. follows:
  2648.  
  2649.     ios::in        Input mode. (Default for input file.)
  2650.     ios::out       Output mode. (Default for output file.)
  2651.     ios::app       Append to an output file rather than update an existing
  2652.                    record.
  2653.     ios::ate       Position file marker at end of file instead of beginning.
  2654.     ios::trunc     Delete file if it exists and re-create it.
  2655.     ios::nocreate  File must exist, otherwise open fails (output only)
  2656.     ios::noreplace File must not exist, otherwise open fails (output only)
  2657.     ios::binary    Binary mode; default is text (Binary is a Borland
  2658.                    enhancement)
  2659.  
  2660. Note that for "fstream" instances, there is no default mode. Obviously, these
  2661. various modes may be bitwise ORed together if more than one is desired.
  2662.  
  2663. The third argument is the file access. Under Turbo C++ version 1.01, the
  2664. possible values are:
  2665.  
  2666.     0 = Default
  2667.     1 = Read-only file
  2668.     2 = Hidden file
  2669.     4 = System file
  2670.     8 = Archive bit set
  2671.  
  2672. If the open fails, the overloaded "operator!" used on the instance will
  2673. return 'true'.
  2674.  
  2675. For example:
  2676.  
  2677.     file_in.open("INPUT") ;
  2678.     file_out.open("OUTPUT") ;
  2679.     file_both.open("BOTH" , ios::in | ios::out) ;
  2680.  
  2681. An alternate method of calling the open function is to call the constructor
  2682. with the same argument(s) that you would use for the "open". Thus, instead
  2683. of creating the instance and then explicitly calling the "open" function, you
  2684. can combine these two steps by writing:
  2685.  
  2686.    ifstream file_in("INPUT") ;
  2687.    ofstream file_out("OUTPUT") ;
  2688.    fstream  file_both("BOTH", ios::in | ios::out) ;
  2689.  
  2690. When you are done using the file, the member function "close" taking no
  2691. arguments will close it. This function is called automatically by the
  2692. destructor for the class, but you may call it explicitly if you wish.
  2693.  
  2694. Let's start with a simple program that accepts string input from the user
  2695. and writes it to a disk file called "OUTPUT.DAT".
  2696.  
  2697. // EXAMPLE FILEIO-01
  2698.  
  2699. // CREATE AN OUTPUT FILE AND WRITE
  2700. // WHATEVER DATA THE OPERATOR MAY
  2701. // ENTER
  2702.  
  2703. #include <header.h>
  2704.  
  2705. const int max = 100 ;
  2706.  
  2707. ////////////////////////////////////
  2708.  
  2709. int main()
  2710. {
  2711.    char buffer[max] ;
  2712.    ofstream file_out("OUTPUT.DAT") ;
  2713.    if (!file_out)
  2714.    {
  2715.       cout << "OPEN FAILED\n" ;
  2716.       PAUSE() ;
  2717.       exit(1) ;
  2718.    }
  2719.  
  2720.    cout << "Enter a line of data: " ;
  2721.    while (!cin.get(buffer , max).eof())
  2722.    {
  2723.       file_out << buffer << endl ;
  2724.       cout << "Next line: " ;
  2725.       cin >> FLUSH ;
  2726.    }
  2727.  
  2728.    return 0 ;
  2729. }
  2730.  
  2731. Now give the user a chance to append more records to the file. Note that
  2732. the mode of the file is "ios::out | ios::app" (although "ios::app" by itself
  2733. would still have worked).
  2734.  
  2735. // EXAMPLE FILEIO-02
  2736.  
  2737. // GIVE THE USER A CHANCE TO APPEND
  2738. // RECORDS TO THE FILE
  2739.  
  2740. #include <header.h>
  2741.  
  2742. const int max = 100 ;
  2743.  
  2744. ////////////////////////////////////
  2745.  
  2746. int main()
  2747. {
  2748.    char buffer[max] ;
  2749.    ofstream file_out("OUTPUT.DAT" , ios::out | ios::app) ;
  2750.    if (!file_out)
  2751.    {
  2752.       cout << "OPEN FAILED\n" ;
  2753.       PAUSE() ;
  2754.       exit(1) ;
  2755.    }
  2756.  
  2757.    cout << "Enter a line of data: " ;
  2758.    while (!cin.get(buffer , max).eof\())
  2759.    {
  2760.       file_out << buffer << endl ;
  2761.       cout << "Next line: " ;
  2762.       cin >> FLUSH ;
  2763.    }
  2764.  
  2765.    return 0 ;
  2766. }
  2767.  
  2768. Finally, this program numbers and prints the records that were just written.
  2769.  
  2770. // EXAMPLE FILEIO-03
  2771.  
  2772. // NOW READ THE FILE THAT WAS JUST
  2773. // CREATED
  2774.  
  2775. #include <header.h>
  2776.  
  2777. const int max = 100 ;
  2778.  
  2779. ////////////////////////////////////
  2780.  
  2781. int main()
  2782. {
  2783.    char buffer[max] ;
  2784.    ifstream file_in("OUTPUT.DAT") ;
  2785.    if (!file_in)
  2786.    {
  2787.       cout << "OPEN FAILED\n" ;
  2788.       PAUSE() ;
  2789.       exit(1) ;
  2790.    }
  2791.  
  2792.    int rec = 0 ;
  2793.    while (!file_in.get(buffer , max).eof())
  2794.    {
  2795.       cout << "Record #"
  2796.            << ++rec
  2797.            << ": "
  2798.            << buffer
  2799.            << endl ;
  2800.       file_in >> FLUSH ;
  2801.    }
  2802.  
  2803.    return 0 ;
  2804. }
  2805.  
  2806. ****************************************************************
  2807. The File Position Markers
  2808.  
  2809. So that the file I/O classes can keep track of where in a file the data is
  2810. to be written to and read from, they establish what is called a 'file position
  2811. marker' (fpm). On Turbo C++ this marker has been 'typedef'ed as a 'long'
  2812. integer representing an offset value from the beginning of the file. In point
  2813. of fact, there are two such markers, one for reading, and one for writing.
  2814. You may alter these markers by using two member functions: "seekg" and
  2815. "seekp". "seekg" is associated with the file's 'get or read' pointer, and
  2816. "seekp" with the file's 'put or write' pointer. The declarations for these two
  2817. functions are as follows:
  2818.  
  2819.   istream& istream::seekg(streampos offset) ;
  2820.   istream& istream::seekg(streamoff offset , seek_dir) ;
  2821.  
  2822.   ostream& ostream::seekp(streampos offset) ;
  2823.   ostream& ostream::seekp(streamoff offset , seek_dir) ;
  2824.  
  2825. where "streampos" and "streamoff" represent "long" integers, and "seek_dir"
  2826. is an enumerated type defined as follows:
  2827.  
  2828.   enum seek_dir {ios::beg , ios::cur , ios::end} ;
  2829.  
  2830. If the 1-argument form of the function is used, then "offset" is the offset
  2831. from the beginning of the file. If the 2-argument form is used, then "offset"
  2832. is the offset number of bytes (positive or negative) from the absolute
  2833. "seek_dir" position. Therefore, a call to "seekg" with an argument of 0 causes
  2834. the file to rewind and data to be read starting with the first record.
  2835.  
  2836. To find out the positions of these markers, you may use the member functions
  2837. "tellg" and "tellp". They are declared as follows:
  2838.  
  2839.   streampos istream::tellg() ;
  2840.   streampos ostream::tellp() ;
  2841.  
  2842. To illustrate this, here is the previous example of writing and reading a
  2843. file, but now it uses an instance of the class "fstream" so that the output and
  2844. input can be combined. After each record is read and printed, the file
  2845. position marker (fpm) is displayed. NOTE: The inclusion of the mode
  2846. "ios::binary" is to avoid a Borland bug with "tellg" corrupting the fpm.
  2847.  
  2848. // EXAMPLE FILEIO-04
  2849.  
  2850. // HOW TO WRITE AND READ A FILE IN
  2851. // THE SAME PROGRAM
  2852.  
  2853. // NOTE: FILE IS OPENED IN BINARY
  2854. // MODE TO AVOID A tellg BUG IN
  2855. // TURBO C++
  2856.  
  2857. #include <header.h>
  2858.  
  2859. const int max = 100 ;
  2860.  
  2861. ////////////////////////////////////
  2862.  
  2863. int main()
  2864. {
  2865.    char buffer[max] ;
  2866.   "fstream"file_both("BOTH.DAT" ,
  2867.                       ios::in |
  2868.                       ios::out |
  2869.                       ios::binary) ;
  2870.    if (!file_both)
  2871.    {
  2872.       cout << "OPEN FAILED\n" ;
  2873.       PAUSE() ;
  2874.       exit(1) ;
  2875.    }
  2876.  
  2877.    cout << "Enter a line of data: " ;
  2878.    while (!cin.get(buffer , max).eof())
  2879.    {
  2880.       file_both << buffer << endl ;
  2881.       cout << "Next line: " ;
  2882.       cin >> FLUSH ;
  2883.    }
  2884.  
  2885.    // Flush the output buffer
  2886.    file_both << flush ;
  2887.  
  2888.    // Return to the start of the file
  2889.    file_both.seekg(0) ;
  2890.  
  2891.    // Read and print the records, and
  2892.    // show the file position marker
  2893.    int rec = 0 ;
  2894.    while (!file_both.get(buffer , max).eof())
  2895.    {
  2896.       cout << "Record #"
  2897.            << ++rec
  2898.            << ": "
  2899.            << buffer
  2900.            << endl ;
  2901.       cout << "fpm is: "
  2902.            << file_both.tellg()
  2903.            << endl ;
  2904.       file_both >> FLUSH ;
  2905.    }
  2906.  
  2907.    return 0 ;
  2908. }
  2909.  
  2910. This program gives the user complete flexibility as to the name of the
  2911. external file to be manipulated, and modes to be used. NOTE: Do not try to
  2912. include an instance of a file class within a class declaration. As of version
  2913. 1.01, there is a bug which does not allow this. As an avoidance technique,
  2914. you may include a pointer of the class type, and then obtain the space for
  2915. the instance via the "new" operator.
  2916.  
  2917. // EXAMPLE FILEIO-05
  2918.  
  2919. // GIVE THE USER COMPLETE FLEXIBILITY
  2920. // AS TO THE MODE OF THE FILE AND THE
  2921. // DATA WRITTEN AND READ
  2922.  
  2923. // ARGUMENTS ARE ENTERED FROM THE DOS
  2924. // COMMAND LINE. THE FIRST ARGUMENT
  2925. // IS THE DISK FILE NAME, AND THE
  2926. // REMAINING ARGUMENTS REPRESENT THE
  2927. // VARIOUS OPEN MODES, EXACTLY AS
  2928. // SPECIFIED BY THE ENUMERATED TYPES
  2929.  
  2930. // NOTE THAT A CLASS IS NOW USED TO
  2931. // CONTROL THE VARIOUS OPERATIONS ON
  2932. // A FILE OBJECT. HOWEVER, A POINTER
  2933. // IS DECLARED INSTEAD OF AN INSTANCE
  2934. // TO AVOID A BORLAND BUG
  2935.  
  2936. #include <header.h>
  2937.  
  2938. const int max = 100 ;
  2939.  
  2940. class file
  2941. {
  2942.    fstream* ptr ;
  2943.      public:
  2944.  
  2945.    file()
  2946.    {
  2947.       ptr = new fstream() ;
  2948.    }
  2949.  
  2950.    int open(int argc , char* argv[]) ;
  2951.    void read() ;
  2952.    void write() ;
  2953.    void beginning() ;
  2954.    void end() ;
  2955.    void close() ;
  2956. } ;
  2957.  
  2958. // Open the file by setting up the
  2959. // field 'mode' with the OR of what-
  2960. // ever modes the user has chosen
  2961.  
  2962. int file::open(int argc , char* argv[])
  2963. {
  2964.    int mode = 0 ;
  2965.  
  2966.    for (int i = 2 ; i < argc ; ++i)
  2967.    {
  2968.       if (!strcmp (argv[i] , "out"))
  2969.           mode |= ios::out ;
  2970.       else if (!strcmp (argv[i] , "in"))
  2971.           mode |= ios::in ;
  2972.       else if (!strcmp (argv[i] , "app"))
  2973.           mode |= ios::app ;
  2974.       else if (!strcmp (argv[i] , "ate"))
  2975.           mode |= ios::ate ;
  2976.       else if (!strcmp (argv[i] , "trunc"))
  2977.           mode |= ios::trunc ;
  2978.       else if (!strcmp (argv[i] , "nocreate"))
  2979.           mode |= ios::nocreate ;
  2980.       else if (!strcmp (argv[i] , "noreplace"))
  2981.           mode |= ios::noreplace ;
  2982.       else if (!strcmp (argv[i] , "binary"))
  2983.           mode |= ios::binary ;
  2984.       else
  2985.           cout << "Invalid mode: "
  2986.                 << argv[i]
  2987.                 << endl ;
  2988.    }
  2989.  
  2990.    // Perform the actual open
  2991.    ptr->open(argv[1] , mode) ;
  2992.  
  2993.    // If an error occurred, return
  2994.    // "true"
  2995.    return (!*ptr) ;
  2996. }
  2997.  
  2998. // Read the file
  2999.  
  3000. void file::read()
  3001. {
  3002.    char buffer [max] ;
  3003.  
  3004.    cout << "Data line: " ;
  3005.    ptr->get(buffer , max) ;
  3006.    *ptr >> FLUSH ;
  3007.    if (!(ptr->eof()))
  3008.       cout << buffer << endl ;
  3009.    else
  3010.       cout << "EOF\n" ;
  3011.    ptr->clear() ;
  3012. }
  3013.  
  3014. // Write the file
  3015.  
  3016. void file::write()
  3017. {
  3018.    char buffer [max] ;
  3019.  
  3020.    cout << "Enter some data: " ;
  3021.    cin.get(buffer , max) ;
  3022.    cin >> FLUSH ;
  3023.    *ptr << buffer << endl ;
  3024. }
  3025.  
  3026. // Return to the start of the file
  3027.  
  3028. void file::beginning()
  3029. {
  3030.    ptr->seekg(0) ;
  3031.    ptr->seekp(0) ;
  3032. }
  3033.  
  3034. // Seek to the end of the file
  3035.  
  3036. void file::end()
  3037. {
  3038.    ptr->seekg(0 , ios::end) ;
  3039.    ptr->seekp(0 , ios::end) ;
  3040. }
  3041.  
  3042. // Close the file
  3043.  
  3044. void file::close()
  3045. {
  3046.    ptr->close() ;
  3047. }
  3048.  
  3049. ///////////////////////////////////
  3050.  
  3051. char menu() ;
  3052.  
  3053. int main(int argc , char* argv [])
  3054. {
  3055.    file my_file ;
  3056.  
  3057.    if (argc < 2)
  3058.    {
  3059.       cout << "NO FILE NAME\n" ;
  3060.       exit(1) ;
  3061.    }
  3062.  
  3063.    if(my_file.open(argc , argv))
  3064.    {
  3065.       cout << "OPEN FAILED\n" ;
  3066.       exit(2) ;
  3067.    }
  3068.  
  3069.    char ch ;
  3070.    while ((ch = menu()) != 'X')
  3071.    {
  3072.       switch (ch)
  3073.       {
  3074.         case 'R' : my_file.read() ;
  3075.                    break ;
  3076.         case 'W' : my_file.write() ;
  3077.                    break ;
  3078.         case 'B' : my_file.beginning() ;
  3079.                    break ;
  3080.         case 'E' : my_file.end() ;
  3081.                    break ;
  3082.         default :  cout << "INVALID\n" ;
  3083.                    break ;
  3084.       }
  3085.    }
  3086.    my_file.close() ;
  3087.  
  3088.    return 0 ;
  3089. }
  3090.  
  3091. ///////////////////////////////////////
  3092.  
  3093. char menu()
  3094. {
  3095.    cout << "\t(R)ead a record\n" ;
  3096.    cout << "\t(W)rite a record\n" ;
  3097.    cout << "\t(B)eginning of file\n" ;
  3098.    cout << "\t(E)nd of the file\n" ;
  3099.    cout << "\te(X)it\n" ;
  3100.  
  3101.    cout << "\n\tYour choice: " ;
  3102.    char ch ;
  3103.    cin >> ch >> FLUSH ;
  3104.    return (toupper(ch)) ;
  3105. }
  3106.  
  3107. ****************************************************************
  3108. Using the Line Printer
  3109.  
  3110. The line printer is just another output file insofar as DOS is concerned. To
  3111. redirect output to a printer from within your program, use the predefined
  3112. name "prn".
  3113.  
  3114. // EXAMPLE FILEIO-06
  3115.  
  3116. // HOW TO PRINT FROM WITHIN A
  3117. // PROGRAM
  3118.  
  3119. #include <header.h>
  3120.  
  3121. int main()
  3122. {
  3123.    ofstream printer ;
  3124.    // "prn" is the DOS printer
  3125.    printer.open("prn") ;
  3126.    if (!printer)
  3127.    {
  3128.      cerr << "Can't open\n" ;
  3129.      exit(1) ;
  3130.    }
  3131.    printer << "This line appears"
  3132.            << " on the printer\n" ;
  3133.  
  3134.    return 0 ;
  3135. }
  3136.  
  3137.