Computer Systems Org I - Prof. Grishman

Lecture 18 - Nov. 8, 2004

IO with putchar and getchar, cont'd

Redirection

getchar reads a character from standard input;  putchar writes a character to standard output.
In Unix (and systems using similar shells, like Linux and Cygwin) standard input can be redirected to read from a file

./a <sometext

reads from file 'sometext' instead of standard input;

./a <sometext >moretext

reads from file 'sometext' and writes to file 'moretext'.  This allows a program to be tested first interactively and then -- without changing the program, to use a data file as input.

EOF

If getchar is reading from a file and encounters an end-of-file, it returns the value EOF, which is defined as part of stdio.h.  So a program to copy a complete file from input to output would be

#include <stdio.h>

main() {
   char c;
   /* copy input characters to output until end of file */
   while ((c = getchar()) != EOF) putchar(c);
}

Returning a string from a C function:  using malloc

Suppose we wanted to write a function getline which returns as its value the next line of input.  We first wrote

#include <stdio.h>

char* getline();

main () {
        char* p;
        p = getline();
        printf ("Line is %s", p);
}

char* getline () {
        char line[20];
        char c;
        int i = 0;
        while (i<20 && (c = getchar()) != '\n')
                line[i++] = c;
        return line;
}

but this did not work because the array 'line' was effectively erased from the stack when getline returned;  this program printed garbage.  So next we tried making 'line' a global variable, so it would not go away (it would be static).

#include <stdio.h>

char* getline();

char line[20];

main () {
        char* p;
        p = getline();
        printf ("Line is %s", p);
}

char* getline () {
        char c;
        int i = 0;
        while (i<19 && (c = getchar()) != '\n')
                line[i++] = c;
        line[i] = 0;
        return line;
}

We also were careful this time to add a zero character to the end of the string.  This worked fine, so we were more ambitious and tried to read and write two lines with the following main program ...

main () {
        char* p;
        char* q;
        p = getline();
        q = getline();
        printf ("First line is %s\n", p);
        printf ("Second line is %s\n", q);
}

However, when we typed in 'moo' followed by 'quack' it responded with two 'quack's.  We just had a single array 'line' which was being used for both lines.

To fix this, we copy each string to the heap as it is read in.  We use the malloc function to get space on the heap.  This led to the final version (which worked)

#include <stdio.h>

char* getline();

char line[20];

main () {
        char* p;
        char* q;
        p = getline();
        q = getline();
        printf ("First line is %s\n", p);
        printf ("Second line is %s\n", q);
}

char* getline () {
        char c;
        char* m;
        int i = 0;
        while (i<19 && (c = getchar()) != '\n')
                line[i++] = c;
        line[i] = 0;
        m = malloc(i+1);
        strcpy (m, line);
        return m;
}

(We could have made 'line' local again in this version ... it doesn't matter.)  For more info on malloc, see Patt and Patel sec. 19.4 (formal definition, page 613).