Wednesday, May 29, 2013

Busy-ness!!

Man, this blog has been lingering in the back of my mind all weekend. o-o;

I feel so bad for not updating it aggh. But I seriously didn't want to do any work on my coding this weekend... I've been madly creative and inspired (and also kicking ass in pvp on ToR with Fiance...)

This morning hasn't been crazily busy by any means, so I took it upon myself to scribble down some more notes from K&R. Mom walked by my desk and made a comment about how fast I write, then became very interested in what I was writing about. I flipped the cover of K&R over to show her, and the following conversation ensued:

Mom: "Coding!?"
Me: *grins* "Include standard input/output dot H..."
Mom: "What the fuck, girls don't code!!"

It made me giggle. C:

Anyway, I'm getting into Character Input and Output, specifically with getchar and putchar. I really have to work at this one to figure out what they're talking about. I'm trying to paraphrase, but I keep finding myself writing their explanations word-for-word because I don't understand them enough to paraphrase. Baahh.

First, I need to transcribe my notes from 1.4. Then I'll move to 1.5, which is input/output for character info. Belowwww the break...


K&R 1.4 Symbolic Constants

In the past examples of the Fahrenheit to Celsius conversion programs, the program has been written with values set by the statements, within the statements. This is typically bad practice, as these "magic numbers" such as "300" and "20" have little to no value to anyone who might read the code later on. They also become difficult to change.

So, one way to avoid this issue is to give these "magic numbers" specific names.

#define gives a symbolic name (a.k.a. symbolic constant) a particular string of characters that is easily recognizable.

#define    name    replacement text
Once this line occurs, any further occurrence of  of the text in place of "name" will be replaced with the string "replacement text" -- no quotes necessary. This replacement text can be any combination of characters -- letters and numbers.

Example time:

#include <stdio.h>
#define  LOWER  0
#define  UPPER  300
#define  STEP  20
main()
{
     int fahr;
     for (fahr = LOWER; fahr <= UPPER; fahr = fahr + STEP)
          printf("%3d %6.1f\n", fahr, (5.0/9.0 * (fahr-32));
}

Symbolic constant names are typically all uppercase to be readily distinguishable from lowercase variable names. There is no need for a semicolon at the end of a #define line.

K&R 1.5 Character Input and Output

Text input and output -- regardless of origin or destination -- is dealt with as streams of characters.
A text stream is a sequence of characters divided into lines; each line consists of zero or more characters followed by a newline character (\n).

The library is responsible for making input or output streams conform to this model.

Standard library provides several functions for reading and writing 1 character at a time; getchar and putchar. These aren't the only functions, but they are the simplest.

getchar - reads the next input character from a text stream and returns that as its value

     c = getchar()

The variable c contains the next character of input. The character typically comes from the keyboard, and input from other sources such as files is discussed later.

putchar - prints the character each time the command is used

     putchar(c)

This prints the contents of the integer variable c as a character, usually on the screen. This seems similar to printf -- the two can be used interleaved (but not interchangeably, as they are truly two different functions). The output will appear in the order that the commands are written.

K&R 1.5.1 File Copying

getchar and putchar are powerful, and K&R mentions that a lot of very useful code can be written without knowing more than these commands. The most simple program copies the input to output, one character at a time.

In psuedo:

     read character
     while (character is not end-of-file indicator)
           output the character just read
           read a character

Convert to C:

#include <stdio.h>
main()
{
     int c
     c = getchar
     while (c != EOF){
          putchar(c);
          c = getchar();
      }
}

(I tried this. You can't have a return 0; line because that will terminate the program without giving you the chance to put any inputs through it. However, leaving the return 0; line out without a condition that commands it to terminate will force you to quit terminal in order to end the program. FYI.)

!= is a rational operator that means "not equal to".

Characters by nature are nothing more than bit patterns. The data type char is specifically meant for storing patterns such as these, but any integer type can be used.

int was chosen for an important reason in this case (and this is where K&R has slightly lost me. I had to investigate in other places, and it still does not entirely make sense).

The main question here is: How is the end of the input distinguished from valid data?
getchar returns a distinctive value when there is no more input -- and this value can't be confused with any real character. This value is known as EOF for End Of File.

The data type we declare c to be must be big enough to hold any value that getchar returns. The way I saw this explained was that char can only hold 256 values of all characters that could be returned. EOF is an additional value, and that makes it difficult for char to handle it. So, if we can't use char because it isn't large enough, we opt for int.

I suppose that float could be an option for this, as well... But int makes more sense because we don't need the power of float.

Specifically, EOF is an integer defined in <stdio.h>, but the numeric value is insignificant. The only thing that matters is that it does not share a value with any char. By using the symbolic constant of EOF, we can be sure that nothing in the program will be dependent on that particular value.

K&R expresses that the program above can be written more consicely:

#include <stdio.h>
main()
{
     int c
     while ((c = getchar()) != EOF){
           putchar(c);
     }
}

In C, any assignment

    c = getchar

such as this, is an expression and has a value. That value is represented on the left side of the assignment (in this case, c is the value).
This is important because it means an assignment can appear as part of a larger expression. Above, the assignment of a character to c is put inside the test statement of a while loop.

while gets a character, assigns it to c, then tests whether the character is the end-of-file value. If not, the body of while executes by printing the character. while will then repeat until the end-of-input is reached.

This version of the program centralizes input to only reference getchar once, resulting in a more compact program. With understanding of the idiom, it is also easier to read -- making this style popular with writers.
(All things in moderation, of course. This style also leads to "impenetrable code", or code that is so confusing with so many expressions compounded upon one another in a single statement, that it can barely be understood by anyone else reading it.)

Another important thing to point out is the placement of the parentheses. The assignment (c = getchar) must be enclosed in parentheses because -- much like an algebraic expression -- they denote that the assignment must take precedence over all other operations in the statement.
Normally, != has a higher precedence than =. Without the parentheses in the proper place, the statement

      c = getchar() != EOF

is equivalent to

      c = (getchar() != EOF)

This unintentionally sets c to 0 (if the file does not end) or 1 (if the file does end).

This is the end of 1.5.1, and honestly, while this is very good information, I am looking over the exercises... and they have me baffled.

Exercise 1-6: Verify that the expression getchar() != EOF is 0 or 1.
I can say that when I enter it into the program above so that c = (getchar() != EOF), I don't get an output, which means putchar(c) is picking up a 0 value, I think? Confused at this.

Exercise 1-7: Write a program to print the value of EOF.
Hmm. Well, the program I tried to write gave a never-ending line of question marks. I think I ought to take a slower course. Looks like I'm shelving K&R for a while and going back to King. I really don't understand how to write a program that will do this...

No comments:

Post a Comment