Chapter 9 - Standard Input/Output


                          THE STDIO.H HEADER FILE

             Load  the file SIMPLEIO.C for our first look at a  file
        with  standard I/O.   Standard I/O refers to the most  usual
        places  where  data is either read from,  the  keyboard,  or
        written to, the video monitor.  Since they are used so much,
        they are used as the default I/O devices and do not need  to
        be  named in the Input/Output instructions.   This will make
        more  sense when we actually start to use them so lets  look
        at the file in front of you.

             The  first thing you will notice is the second line  of
        the  file,  the #include "stdio.h" line.   This is very much
        like  the  #define  we have  already  studied,  except  that
        instead of a simple substitution,  an entire file is read in
        at  this  point.   The  system  will  find  the  file  named
        "stdio.h"  and read its entire contents in,  replacing  this
        statement.   Obviously then,  the file named "STDIO.H"  must
        contain  valid  C source statements that can be compiled  as
        part  of  a program.   This particular file is  composed  of
        several standard #defines to define some of the standard I/O
        operations.   The file is called a header file and you  will
        find several different header files on the source disks that
        came  with your Turbo C compiler.  Each of the header  files
        has  a  specific  purpose  and any or all  of  them  can  be
        included in any program.

             The  Turbo  C compiler uses the double quote  marks  to
        indicate  that the search for the "include" file will  begin
        in  the  current directory, and if it not found  there,  the
        search will continue in the "include" directory as set up in
        the environment.  It also uses the "less than" and  "greater
        than" signs to indicate that the file search should begin in
        the  directory  specified in the environment.  Most  of  the
        programs  in  this tutorial have the double  quotes  in  the
        "include" statements.  The next program uses the "<" and ">"
        to  illustrate the usage.  Note that this will result  is  a
        slightly  faster  (but  probably  unnoticeable)  compilation
        because  the  system will not bother to search  the  current
        directory.

                        INPUT/OUTPUT OPERATIONS IN C

             Actually  the  C programming language has no  input  or
        output operations defined as part of the language, they must
        be user defined.   Since everybody does not want to reinvent
        his  own input and output operations,  the compiler  writers
        have done a lot of this for us and supplied us with  several
        input  functions and several output functions to aid in  our
        program development.   The functions have become a standard,
        and  you  will find the same functions available  in  nearly


                                  Page 60









                     Chapter 9 - Standard Input/Output


        every  compiler.   In fact,  the industry standard of the  C
        language  definition has become the book written by Kernigan
        and Ritchie, and they have included these functions in their
        definition.   You will often,  when reading literature about
        C,  find  a reference to K & R.   This refers  to  the  book
        written  by Kernigan and Ritchie.  You would be  advised  to
        purchase a copy for reference.

             You should print out the file named "STDIO.H" and spend
        some  time studying it.   There will be a lot that you  will
        not understand about it, but parts of it will look familiar.
        The  name  "STDIO.H"  is  sort  of  cryptic  for   "standard
        input/output header",  because that is exactly what it does.
        It  defines  the standard input and output functions in  the
        form of #defines and macros.  Don't worry too much about the
        details  of this now.   You can always return to this  topic
        later  for  more study if it interests  you,  but  you  will
        really  have no need to completely understand the  "STDIO.H"
        file.  You will have a tremendous need to use it however, so
        these comments on its use and purpose are necessary.

                            OTHER INCLUDE FILES

             When  you  begin writing larger programs and  splitting
        them  up into separately compiled portions,  you  will  have
        occasion  to  use  some  statements common to  each  of  the
        portions.   It would be to your advantage to make a separate
        file  containing  the  statements and use  the  #include  to
        insert it into each of the files.  If you want to change any
        of the common statements,  you will only need to change  one
        file  and  you will be assured of having all of  the  common
        statements  agree.   This  is  getting  a  little  ahead  of
        ourselves  but  you  now  have  an  idea  how  the  #include
        directive can be used.

                    BACK TO THE FILE NAMED "SIMPLEIO.C"

             Lets  continue our tour of the file in  question.   The
        one  variable  "c" is defined and a message is  printed  out
        with the familiar "printf" function.  We then find ourselves
        in  a continuous loop as long as "c" is not equal to capital
        X.   If  there is any question in your mind about  the  loop
        control, you should review chapter 3 before continuing.  The
        two  new functions within the loop are of paramount interest
        in this program since they are the new functions.  These are
        functions to read a character from the keyboard and  display
        it on the monitor one character at a time.

             The  function "getchar()" reads a single character from
        the  standard  input  device,  the  keyboard  being  assumed
        because that is the standard input device, and assigns it to


                                  Page 61









                     Chapter 9 - Standard Input/Output


        the variable "c".   The next function "putchar(c)", uses the
        standard output device,  the video monitor,  and outputs the
        character contained in the variable "c".   The character  is
        output  at  the  current cursor location and the  cursor  is
        advanced  one space for the next character.   The system  is
        therefore taking care of a lot of the overhead for us.   The
        loop  continues reading and displaying characters  until  we
        type a capital X which terminates the loop.

             Compile and run this program for a few surprises.  When
        you type on the keyboard, you will notice that what you type
        is displayed faithfully on the screen,  and when you hit the
        return key,  the entire line is repeated.   In fact, we only
        told  it  to output each character once but it seems  to  be
        saving  the  characters up and redisplaying them.   A  short
        explanation is in order.

               DOS IS HELPING US OUT (OR GETTING IN THE WAY)

             We need to understand a little bit about how DOS  works
        to  understand  what is happening here.   When data is  read
        from  the keyboard,  under DOS control,  the characters  are
        stored  in  a buffer until a carriage return is  entered  at
        which  time the entire string of characters is given to  the
        program.   When the characters are being typed, however, the
        characters are displayed one at a time on the monitor.  This
        is called echo,  and happens in many of the applications you
        run.

             With  the above paragraph in mind,  it should be  clear
        that when you are typing a line of data into "SIMPLEIO", the
        characters are being echoed by DOS,  and when you return the
        carriage,  the characters are given to the program.  As each
        character  is given to the program,  it displays it  on  the
        screen  resulting  in  a repeat of the line  typed  in.   To
        better  illustrate  this,  type  a line  with  a  capital  X
        somewhere  in the middle of the line.   You can type as many
        characters  as you like following the "X" and they will  all
        display because the characters are being read in under  DOS,
        echoed  to the monitor,  and placed in the DOS input buffer.
        DOS doesn't think there is anything special about a  capital
        X.   When the string is given to the program,  however,  the
        characters  are  accepted by the program one at a  time  and
        sent  to  the monitor one at a time,  until a capital  X  is
        encountered.   After the capital X is displayed, the loop is
        terminated,  and the program is terminated.   The characters
        on  the input line following the capital X are not displayed
        because the capital X signalled program termination.

             Compile  and  run  "SIMPLEIO.C".    After  running  the
        program  several  times  and  feeling  confident  that   you


                                  Page 62









                     Chapter 9 - Standard Input/Output


        understand  the above explanation,  we will go on to another
        program.

             Don't  get  discouraged by the  above  seemingly  weird
        behavior  of the I/O system.   It is strange,  but there are
        other ways to get data into the computer.  You will actually
        find the above method useful for many applications,  and you
        will probably find some of the following useful also.

                         ANOTHER STRANGE I/O METHOD

             Load  the file named SINGLEIO.C and display it on  your
        monitor for another method of character I/O.  Once again, we
        start  with the standard I/O header file using the  "<"  and
        ">"  method of defining it. Then we define a variable  named
        "c",  and  finally we print a welcoming message.   Like  the
        last program, we are in a loop that will continue to execute
        until  we  type  a capital X, but the  action  is  a  little
        different here.

             The  "getch()"  is  a  new  function  that  is  a  "get
        character" function.  It differs from "getchar()" in that it
        does  not  get tied up in DOS.   It reads the  character  in
        without echo, and puts it directly into the program where it
        is operated on immediately.  This function therefore reads a
        character,  immediately  displays  it  on  the  screen,  and
        continues the operation until a capital X is typed.

             When  you compile and run this program,  you will  find
        that there is no repeat of the lines when you hit a carriage
        return,  and  when  you  hit  the  capital  X,  the  program
        terminates immediately.  No carriage return is needed to get
        it to accept the line with the X in it.   We do have another
        problem  here,  however,  there  is  no  linefeed  with  the
        carriage return.

                          NOW WE NEED A LINE FEED

             It  is not apparent to you in most application programs
        but  when  you hit the enter key,  the  program  supplies  a
        linefeed to go with the carriage return.  You need to return
        to  the  left side of the monitor and you also need to  drop
        down  a line.   The linefeed is not automatic.  We  need  to
        improve  our program to do this also.   If you will load and
        display the program named BETTERIN.C, you will find a change
        to incorporate this feature.

             In BETTERIN.C, we have two additional statements at the
        beginning  that  will  define the character  codes  for  the
        linefeed (LF), and the carriage return (CR).  If you look at
        any  ASCII table you will find that the codes 10 and 13  are


                                  Page 63









                     Chapter 9 - Standard Input/Output


        exactly  as  defined  here.   In  the  main  program,  after
        outputting the character,  we compare it to CR, and if it is
        equal to CR,  we also output a linefeed which is the LF.  We
        could have just left out the two #define statements and used
        "if  (c  ==  13)  putchar(10);" but it  would  not  be  very
        descriptive  of what we are doing here.  The method used  in
        the program represents better programming practice.

             Compile  and  run BETTERIN.C to see if it does what  we
        have said it should do.   It should display exactly what you
        type in, including a linefeed with each carriage return, and
        should stop immediately when you type a capital X.

                           WHICH METHOD IS BEST?

             We have examined two methods of reading characters into
        a  C program,  and are faced with a choice of which  one  we
        should  use.   It really depends on the application  because
        each  method has advantages and disadvantages.   Lets take a
        look at each.

             When using the first method,  DOS is actually doing all
        of  the  work for us by storing the characters in  an  input
        buffer and signalling us when a full line has been  entered.
        We  could write a program that,  for example,  did a lot  of
        calculations,  then  went to get some input.   While we were
        doing the calculations,  DOS would be accumulating a line of
        characters  for  us,  and they would be there when  we  were
        ready  for  them.   However,  we could not  read  in  single
        keystrokes   because  DOS  would  not  report  a  buffer  of
        characters to us until it recognized a carriage return.

             The second method, used in BETTERIN.C, allows us to get
        a single character,  and act on it immediately.   We do  not
        have  to  wait  until  DOS decides we can  have  a  line  of
        characters.  We cannot do anything else while we are waiting
        for  a  character  because  we are  waiting  for  the  input
        keystroke  and tying up the entire machine.   This method is
        useful  for highly interactive types of program  interfaces.
        It  is up to you as the programmer to decide which  is  best
        for your needs.

             I  should  mention at this point that there is also  an
        "ungetch" function that works with the "getch" function.  If
        you "getch" a character and find that you have gone one  too
        far,  you  can "ungetch" it back to the input device.   This
        simplifies  some  programs because you don't know  that  you
        don't  want the character until you get it.   You  can  only
        "ungetch"  one character back to the input device,  but that
        is  sufficient  to  accomplish the task  this  function  was
        designed for.   It is difficult to demonstrate this function


                                  Page 64









                     Chapter 9 - Standard Input/Output


        in  a simple program so its use will be up to you  to  study
        when you need it.

             The discussion so far in this chapter, should be a good
        indication  that,  while the C programming language is  very
        flexible,  it does put a lot of responsibility on you as the
        programmer to keep many details in mind.

                        NOW TO READ IN SOME INTEGERS

             Load  and display the file named INTIN.C for an example
        of  reading in some formatted data.   The structure of  this
        program  is  very similar to the last three except  that  we
        define  an "int" type variable and loop until  the  variable
        somehow acquires the value of 100.

             Instead of reading in a character at a time, as we have
        in the last three files,  we read in an entire integer value
        with  one  call  using the  function  named  "scanf".   This
        function  is very similar to the "printf" that you have been
        using for quite some time by now except that it is used  for
        input instead of output.   Examine the line with the "scanf"
        and  you  will notice that it does not ask for the  variable
        "valin"  directly,  but  gives the address of  the  variable
        since it expects to have a value returned from the function.
        Recall  that a function must have the address of a  variable
        in  order to return a value to that variable in the  calling
        program.   Failing  to  supply  a  pointer  in  the  "scanf"
        function is probably the most common problem encountered  in
        using this function.

             The  function  "scanf" scans the input  line  until  it
        finds  the first data field.   It ignores leading blanks and
        in this case,  it reads integer characters until it finds  a
        blank  or  an invalid decimal character,  at which  time  it
        stops reading and returns the value.

             Remembering  our discussion above about the way the DOS
        input  buffer  works,  it should be clear  that  nothing  is
        actually acted on until a complete line is entered and it is
        terminated by a carriage return.   At this time,  the buffer
        is  input,  and  our  program will search  across  the  line
        reading  all  integer values it can find until the  line  is
        completely scanned.  This is because we are in a loop and we
        tell it to find a value,  print it,  find another, print it,
        etc.   If you enter several values on one line, it will read
        each one in succession and display the values.  Entering the
        value  of  100  will cause the  program  to  terminate,  and
        entering  the  value 100 with other values  following,  will
        cause   termination   before  the   following   values   are
        considered.


                                  Page 65









                     Chapter 9 - Standard Input/Output



                      IT MAKES WRONG ANSWERS SOMETIMES

             If  you  enter a number up to and including  32767,  it
        will display correctly, but if you enter a larger number, it
        will appear to make an error.  For example, if you enter the
        value 32768,  it will display the value of -32768,  entering
        the  value  65536 will display as a  zero.   These  are  not
        errors but are caused by the way an integer is defined.  The
        most significant bit of the 16 bit pattern available for the
        integer variable is the sign bit,  so there are only 15 bits
        left  for the value.   The variable can therefore only  have
        the  values  from  -32768 to 32767,  any  other  values  are
        outside  the range of integer variables.   This is up to you
        to take care of in your programs.   It is another example of
        the increased responsibility you must assume using C  rather
        than a higher level language such as Pascal, Modula-2, etc.

             Compile and run this program,  entering several numbers
        on  a line to see the results,  and with varying numbers  of
        blanks between the numbers.   Try entering numbers that  are
        too big to see what happens,  and finally enter some invalid
        characters  to  see  what the system  does  with  nondecimal
        characters.

                           CHARACTER STRING INPUT

             Load  and  display  the file named  STRINGIN.C  for  an
        example  of  reading  a string variable.   This  program  is
        identical to the last one except that instead of an  integer
        variable,  we  have defined a string variable with an  upper
        limit of 24 characters (remember that a string variable must
        have  a  null character at the end).   The variable  in  the
        "scanf"  does  not  need  an & because  "big"  is  an  array
        variable  and by definition it is already a  pointer.   This
        program  should require no additional explanation.   Compile
        and run it to see if it works the way you expect.

             You probably got a surprise when you ran it because  it
        separated  your sentence into separate words.   When used in
        the string mode of input,  "scanf" reads characters into the
        string until it comes to either the end of a line or a blank
        character.   Therefore,  it  reads a word,  finds the  blank
        following it,  and displays the result.   Since we are in  a
        loop, this program continues to read words until it exhausts
        the DOS input buffer.   We have written this program to stop
        whenever  it  finds a capital X in column 1,  but since  the
        sentence  is split up into individual words,  it  will  stop
        anytime a word begins with capital X.  Try entering a 5 word
        sentence  with  a  capital X as the first character  in  the



                                  Page 66









                     Chapter 9 - Standard Input/Output


        third word.  You should get the first three words displayed,
        and the last two simply ignored when the program stops.

             Try  entering more than 24 characters to see  what  the
        program   does.    In  an  actual  program,   it   is   your
        responsibility  to count characters and stop when the  input
        buffer  is full.  You may be getting the feeling that a  lot
        of  responsibility is placed on you when writing in  C.   It
        is,  but  you also get a lot of flexibility in  the  bargain
        too.

                       INPUT/OUTPUT PROGRAMMING IN C

             C was not designed to be used as a language for lots of
        input and output,  but as a systems language where a lot  of
        internal operations are required.   You would do well to use
        another language for I/O intensive programming,  but C could
        be used if you desire.  The keyboard input is very flexible,
        allowing you to get at the data in a very low level way, but
        very little help is given you.  It is therefore up to you to
        take  care of all of the bookkeeping chores associated  with
        your  required  I/O operations.   This may seem like a  real
        pain in the neck, but in any given program, you only need to
        define your input routines once and then use them as needed.

             Don't let this worry you.   As you gain experience with
        C, you will easily handle your I/O requirements.

             One final point must be made about these I/O functions.
        It   is  perfectly  permissible  to  intermix  "scanf"   and
        "getchar"  functions during read operations.   In  the  same
        manner,  it  is also fine to intermix the output  functions,
        "printf" and "putchar".

                               IN MEMORY I/O

             The  next operation may seem a little strange at first,
        but  you will probably see lots of uses for it as  you  gain
        experience.   Load the file named INMEM.C and display it for
        another  type  of I/O,  one that never accesses the  outside
        world, but stays in the computer.

             In INMEM.C, we define a few variables, then assign some
        values to the ones named "numbers" for illustrative purposes
        and then use a "sprintf" function.   The function acts  just
        like  a  normal  "printf" function except  that  instead  of
        printing the line of output to a device,  it prints the line
        of  formatted  output to a character string in  memory.   In
        this  case  the string goes to the string  variable  "line",
        because  that  is the string name we inserted as  the  first
        argument  in the "sprintf" function.   The spaces after  the


                                  Page 67









                     Chapter 9 - Standard Input/Output


        2nd  %d were put there to illustrate that the next  function
        will  search  properly  across  the  line.    We  print  the
        resulting  string and find that the output is  identical  to
        what  it would have been by using a "printf" instead of  the
        "sprintf"  in the first place.   You will see that when  you
        compile and run the program shortly.

             Since  the generated string is still in memory,  we can
        now  read  it  with the  function  "sscanf".   We  tell  the
        function  in its first argument that "line" is the string to
        use for its input,  and the remaining parts of the line  are
        exactly  what  we  would  use if we were going  to  use  the
        "scanf"  function and read data from outside  the  computer.
        Note  that it is essential that we use pointers to the  data
        because  we  want to return data from a function.   Just  to
        illustrate  that  there are many ways to declare  a  pointer
        several methods are used,  but all are pointers.   The first
        two simply declare the address of the elements of the array,
        while the last three use the fact that "result", without the
        accompanying  subscript,  is  a pointer.   Just to  keep  it
        interesting,  the  values  are read back in  reverse  order.
        Finally the values are displayed on the monitor.

                           IS THAT REALLY USEFUL?

             It  seems sort of silly to read input data from  within
        the  computer  but  it does have  a  real  purpose.   It  is
        possible to read data from an input device using any of  the
        standard  functions  and  then do  a  format  conversion  in
        memory.   You  could read in a line of data, look at  a  few
        significant  characters,  then  use  these  formatted  input
        routines   to   reduce  the  line  of   data   to   internal
        representation.  That would sure beat writing your own  data
        formatting routines.

                           STANDARD ERROR OUTPUT

             Sometimes  it is desirable to redirect the output  from
        the  standard  output device to a file.   However,  you  may
        still  want the error messages to go to the standard  output
        device,  in our case the monitor.  This next function allows
        you to do that. Load and display SPECIAL.C for an example of
        this new function.

             The  program  consists  of a  loop  with  two  messages
        output,  one  to the standard output device and the other to
        the  standard  error device.   The message to  the  standard
        error  device  is  output with the  function  "fprintf"  and
        includes  the  device name "stderr" as the  first  argument.
        Other  than those two small changes,  it is the same as  our
        standard  "printf"  function.   (You will see  more  of  the


                                  Page 68









                     Chapter 9 - Standard Input/Output


        "fprintf"  function in the next chapter,  but its  operation
        fit  in better as a part of this chapter.)  Ignore the  line
        with the "exit" for the moment, we will return to it.

             Compile  and  run this program,  and you will  find  12
        lines of output on the monitor.   To see the difference, run
        the  program  again with redirected output to a  file  named
        "STUFF" by entering the following line at the Dos prompt;

        A> special >stuff

             More  information about I/O redirection can be found in
        your  DOS manual.   This time you will only get the 6  lines
        output to the standard error device, and if you look in your
        directory,  you will find the file named "STUFF"  containing
        the other 6 lines, those to the standard output device.  You
        can use I/O redirection with any of the programs we have run
        so far,  and as you may guess, you can also read from a file
        using I/O redirection but we will study a better way to read
        from a file in the next chapter.

                     WHAT ABOUT THE exit(4) STATEMENT?

             Now  to  keep our promise about the exit(4)  statement.
        Redisplay  the file named SPECIAL.C on  your  monitor.   The
        last  statement  simply  exits the program and  returns  the
        value  of 4 to DOS.   Any number from 0 to 9 can be used  in
        the parentheses for DOS communication.  If you are operating
        in  a  BATCH  file,  this  number can  be  tested  with  the
        "ERRORLEVEL" command.

            A check of the documentation for my COMPAQ, resulted  in
        a  minimal and confusing documentation of  the  "ERRORLEVEL"
        command, so a brief description of it is given in this file.


        PROGRAMMING EXERCISE

        1.   Write  a program to  read in a character using a  loop,
             and  display the character in its normal  "char"  form.
             Also  display  it  as a decimal  number.  Check  for  a
             dollar  sign  to use as the  stop  character.  Use  the
             "getch" form of input so it will print immediately. Hit
             some of the special keys,  such as function keys,  when
             you  run the program for some surprises.  You will  get
             two  inputs  from the special keys,  the first being  a
             zero  which  is  the indication to the  system  that  a
             special key was hit.





                                  Page 69