                     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 first  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 compiler.   Each of the header files has  a 

        specific  purpose and any or all of them can be included  in 

        any program.

             Most C compilers use the double quote marks to indicate 

        that  the  "include"  file  will be  found  in  the  current 

        directory.   A  few use the "less than" and  "greater  than" 

        signs  to indicate that the file will be found in a standard 

        header  file.   Nearly all MSDOS C compilers use the  double 

        quotes,  and  most require the "include" file to be  in  the 

        default  directory.   All  of the programs in this  tutorial 

        have the double quotes in the "include" statements.  If your 

        compiler  uses the other notation,  you will have to  change 

        them before compiling.

                        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 

        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 



                                  Page 55









                     Chapter 9 - Standard Input/Output


        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 

        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 



                                  Page 56









                     Chapter 9 - Standard Input/Output


        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  confidant  that   you 

        understand  the above explanation,  we will go on to another 

        program.




                                  Page 57









                     Chapter 9 - Standard Input/Output


             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,  we  define  a 

        variable named "c",  and 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 then  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, 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 

        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  as well have left  out  the  two  #define 

        statements and used "if (c == 13) putchar(10);" but it would 



                                  Page 58









                     Chapter 9 - Standard Input/Output


        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. 

             If  you are using a nonstandard compiler,  it  may  not 

        find  a "CR" because your system returns a "LF" character to 

        indicate  end-of-line.   It will be up to you  to  determine 

        what method your compiler uses.   The quickest way is to add 

        a  "printf"  statement  that prints the input  character  in 

        decimal format.

                           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 



                                  Page 59









                     Chapter 9 - Standard Input/Output


        "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 

        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  the value  to  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 



                                  Page 60









                     Chapter 9 - Standard Input/Output


        entering  the  value 100 with other values  following,  will 

        cause   termination   before  the   following   values   are 

        considered. 

                      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.

             The   above  paragraph  is  true  for  most  MS-DOS   C 

        compilers.   There  is  a very small possibility  that  your 

        compiler uses an integer value other than 16 bits.   If that 

        is  the  case,  the  same  principles will be  true  but  at 

        different limits than those given above.

             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 



                                  Page 61









                     Chapter 9 - Standard Input/Output


        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 

        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.  It should generate an error, but that will be 

        highly dependent on the system you are using.   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.




                                  Page 62









                     Chapter 9 - Standard Input/Output


             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 

        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 in 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.



                                  Page 63









                     Chapter 9 - Standard Input/Output



             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 

        "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.

             Most compilers that operate in several passes return  a 

        1  with  this mechanism to indicate that a fatal  error  has 

        occurred and it would be a waste of time to go on to another 

        pass resulting in even more errors.

             It  is therefore wise to use a batch file for compiling 

        programs and testing the returned value for errors.  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.





                                  Page 64









                     Chapter 9 - Standard Input/Output


        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 65

