Friday 7 January 2011

The C Programming Language (K&R) 01x05—File Copying (p. 18)


I continue my trek through the book “The C Programming Language” by Brian Kernighan and Dennis Ritchie aka K&R and write a blog about my experience using the sample C code.

The reasons I’m doing it? To learn the language. To show others I know something about the C. To create notes for future reference where, on a blog, I can easily find an answer on something I did previously. To practice my writing of documentation and in general.

I am using Visual C++ 2010 and creating the code as a console application. At some point I will try other compilers, but that’s for another day.

K&R p. 18, File Copying

All of the coding in the book so far has been at the console level. No Windows. No graphical user interface (GUI). No mouse. I suspect, since the book was published in 1988, I’m not going to see anything but console applications. That’s fine.

When I was in university I programmed on a Honeywell mainframe. No GUI there. You would sit down at a console (monitor) with a keyboard and log in. There was no computer box. No slots to insert a floppy disk. The console connected by a cable to the mainframe computer in the computer room. A console is otherwise known as a dumb terminal since it had no computing ability on its own unlike most networked computers today.

The mainframe was the size of a long car in its own room. It sat on an elevated floor where all the cables came in from all over the university and connected to the computer. The room was cooled to keep the parts from overheating. There was one processor for all the users. A 72-bit processor instead of the 8-bit 8088 chip used in the first IBM PCs at the time. There were hard drives and tape drives to store data, but you never touched those. That was the land of the computer operator. There were line printers spread out in various rooms where you could print out your code or print the output of your program. Noisy printers, 128 characters wide with perforated holes on the side to feed the paper. Yet, it was all very straightforward and orderly.

So when I studied the code on p. 18 of the K&R, I was comfortable with the setup. I was used to writing programs that worked solely on a console environment. But as I tested the code on my computer using Visual C++ 2010, I was in for a surprise. It didn’t work as I expected.

It’s a simple program. Declare a variable. Call a standard I/O function to capture a character from the standard input (keyboard) and store the value in the variable. If the character wasn’t the special end of input character, print the character on the console and repeat until you get the end of input character (i.e., EOF).

Here’s the code from p. 18.

#include <stdio.h>

/* copy input to output; 1st version */

main()
{
int c;

c = getchar();
while (c != EOF) {
putchar(c);
c = getchar();
}
}

The first time I ran it, it worked, sort of. I would type characters and they would display on the screen but then when I hit enter, the exact string of characters would show up on a new line. My input was showing up twice. That was odd. It shouldn’t happen.

Here’s a sample of the output.

 

What was going on? Why wasn’t it working? What was I doing wrong?

I played around with the code to make sense of it by adding this code: putchar(‘/’);. If I added this code I would see what was happening.

     while (c != EOF) {
           putchar(c);
           putchar('/');
           c = getchar();
     }

Here’s the new output:

 
The output makes it clear what’s happening. The system is responding to my taps on the keyboard, displaying the character on the console and waiting for the next character. It’s stuck on the line: c = getchar(); waiting for me to press enter. When that happens, each character is processed by the code and displayed again.

In technical terms the implementation of the getchar() function is echoing what I type on the monitor without the use of the putchar() function. Also, the I/O is being buffered. Instead of sending each character to the program one at a time, it’s waiting, storing characters in a buffer until it either reaches the buffer limit or it encounters a carriage return.

This behaviour is not unique to VC++ and is not C standard.

The work around. Use a different get character function: getch() in the conio.h library.

Here’s the modified code:

#include <stdio.h>
#include <conio.h>

int main()
{
     int c;
    
     c = _getch();
     // Variant for VC++
     // Requires conio.h
    
     while (c != EOF) {
           putchar(c);
           c = _getch();
     }
}

Here’s the console screen.

 
Characters aren’t showing up twice, but there is a bug in this code. It’s not allowing the new line or carriage return character to be processed. It’s stuck on the first line. Fixing it is for another time, another blog entry.

No comments:

Post a Comment