                          C INPUT AND OUTPUT

                            Matthew Probert

                           Servile  Software


Input to a C program may occur from the console, the standard input 
device (unless otherwise redirected this is the console), from a file 
or from a data port. 

The general input command for reading data from the standard input 
stream 'stdin' is scanf(). Scanf() scans a series of input fields, one 
character at a time. Each field is then formatted according to the 
appropriate format specifier passed to the scanf() function as a 
parameter. This field is then stored at the ADDRESS passed to scanf() 
following the format specifiers list. 

For example, the following program will read a single integer from the 
stream stdin; 

main()
{
    int x;

    scanf("%d",&x);
}

Notice the address operator & prefixing the variable name 'x' in the 
scanf() parameter list. This is because scanf() stores values at 
ADDRESSES rather than assigning values to variables directly. 

The format string is a character string that may contain three types 
of data: whitespace characters (space, tab and newline), non-
whitespace characters (all ascii characters EXCEPT %) and format 
specifiers. 

Format specifiers have the general form;

    %[*][width][h|l|L]type_character

After the % sign the format specifier is comprised of:

    an optional assignment suppression character, *, which suppresses 
    assignment of the next input field.

    an optional width specifier, width, which declares the maximum 
    number of characters to be read.

    an optional argument type modifier, h or l or L, where:

        h is a short integer
        l is a long
        L is a long double

    the data type character that is one of;

        d       Decimal integer
        D       Decimal long integer 
        o       Octal integer
        O       Octal long integer
        i       Decimal, octal or hexadecimal integer
        I       Decimal, octal or hexadecimal long integer
        u       Decimal unsigned integer
        U       Decimal unsigned long integer
        x       Hexadecimal integer
        X       Hexadecimal long integer
        e       Floating point
        f       Floating point
        g       Floating point
        s       Character string
        c       Character
        %       % is stored


An example using scanf();

#include <stdio.h>

main()
{
    char name[30];
    int age;

    printf("\nEnter your name and age ");
    scanf("%30s%d",name,&age);
    printf("\n%s %d",name,age);
}

Notice the include line, "#include <stdio.h>", this is to tell the 
compiler to also read the file stdio.h that contains the function 
prototypes for scanf() and printf(). 

If you type in and run this sample program you will see that only one 
name can be entered, that is you can't enter; 

    JOHN SMITH

because scanf() detects the whitespace between "JOHN" and "SMITH" and 
moves on to the next input field, which is age, and attempts to assign 
the value "SMITH" to the age field! The limitations of scanf() as an 
input function are obvious. 

An alternative input function is gets() that reads a string of 
characters from the stream stdin until a newline character is 
detected. The newline character is replaced by a null (0 byte) in the 
target string. This function has the advantage of allowing whitespace 
to be read in. The following program is a modification to the earlier 
one, using gets() instead of scanf(). 


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

main()
{
    char data[80];
    char *p;
    char name[30];
    int age;

    printf("\nEnter your name and age ");
    /* Read in a string of data */
    gets(data);


    /* P is a pointer to the last character in the input string */
    p = &data[strlen(data) - 1];

    /* Remove any trailing spaces by replacing them with null bytes */ 
    while(*p == ' ')
    {
        *p = 0;
        p--;
    }

    /* Locate last space in the string */
    p = strrchr(data,' ');

    /* Read age from string and convert to an integer */
    age = atoi(p);

    /* Terminate data string at start of age field */
    *p = 0;

    /* Copy data string to name variable */
    strcpy(name,data);

    /* Display results */
    printf("\nName is %s age is %d",name,age);
}

The most common output function is printf() that is very similar to 
scanf() except that it writes formatted data out to the standard 
output stream stdout. Printf() takes a list of output data fields and 
applies format specifiers to each and outputs the result. The format 
specifiers are the same as for scanf() except that flags may be added 
to the format specifiers. These flags include; 

    - Which left justifies the output padding to the right with spaces.
    + Which causes numbers to be prefixed by their sign

The width specifier is also slightly different for printf(). In its 
most useful form is the precision specifier; 

    width.precision

So, to print a floating point number to three decimal places you would 
use; 

    printf("%.3f",x);

And to pad a string with spaces to the right or truncate the string to 
twenty characters if it is longer, to form a fixed twenty character 
width; 

    printf("%-20.20s",data);

Special character constants may appear in the printf() parameter list. 
These are; 

    \n              Newline
    \r              Carriage return
    \t              Tab
    \b              Sound the computer's bell
    \f              Formfeed
    \v              Vertical tab
    \\              Backslash character
    \'              Single quote
    \"              Double quote
    \?              Question mark
    \O              Octal string
    \x              Hexadecimal string

Thus, to display "Hello World", surrounded in quotation marks and 
followed by a newline you would use; 

    printf("\"Hello World\"\n");


The following program shows how a decimal integer may be displayed as 
a decimal, hexadecimal or octal integer. The 04 following the % in the 
printf() format tells the compiler to pad the displayed figure to a 
width of at least four digits padded with leading zeroes if required. 


/* A simple decimal to hexadecimal and octal conversion program */

#include <stdio.h>

main()
{
    int x;

    do
    {
        printf("\nEnter a number, or 0 to end ");
        scanf("%d",&x);
        printf("%04d  %04X  %04o",x,x,x);
    }
    while(x != 0);

}

There are associated functions to printf() that you should be aware 
of. 

fprintf() has the prototype; 

    fprintf(FILE *fp,char *format[,argument,...]);

This variation on printf() simply sends the formatted output to the 
specified file stream. 

sprintf() has the function prototype;

    sprintf(char *s,char *format[,argument,...]);

and writes the formatted output to a string. You should take care 
using sprintf() that the target string has been declared long enough 
to hold the result of the sprintf() output. Otherwise other data will 
be overwritten in memory. 

An example of using sprintf() to copy multiple data to a string;

#include<stdio.h>

int main()
{
    char buffer[50];

    sprintf(buffer,"7 * 5 == %d\n",7 * 5);

    puts(buffer);
}

An alternative to printf() for outputting a simple string to the 
stream stdout is puts(). This function sends a string to the stream 
stdout followed by a newline character. It is faster than printf(), 
but far less flexible. Instead of; 

    printf("Hello World\n");

You can use;

    puts("Hello World");

