Introduction to C Programming - Part 3

From EDM2
Jump to: navigation, search
Introduction to C Programming
Part: 1 2 3 4 5 6 7 8 9 10

by Carsten Whimster

First Things First: Some Corrections

This month has been bad for me, so this lesson will be a little short. Last month I managed to let a couple of errors creep in. Cindy Ross summarized it thus:

In your introduction to C, you say that "if (c)" and "if (c == 0)" "are not different in result". Oops, you got it backward, they are *opposite* in result! :-> "if (c)" means "if (c != 0)" and "if (!c)" means "if (c == 0)".

A little farther down you have "if ((a + b) = (c - d))" which won't even compile. I was amused to see this right after you explained about the == operator, which just goes to show how silly it was for C to do this to us in the first place.

I have made the changes to the article itself, so if you want to redownload it, you can. Otherwise, just read the above and understand why the errors were wrong. In fact, the second paragraph above happened because I didn't properly type > instead of >. An HTML error! Sorry about this. This is what happens when you run a magazine, write the editorial, write a book review, write a C intro, and then let your life get out of hand. I'll have to lower my coffee dose and cut back on the amount of work.

Loops

There are three basic types of loops in C, the while loop, the do-while loop, and the for loop. We have already covered the for loop. I will go through the other two now. The while loop is a little like the for loop we saw last time in that there is a test at the top, and the loop is executed until the test is false. Here is an example:

i = 0;
while (i < 10) {
  total = total + i;
  i++;
}

This loop is a little silly in that it is really well suited to a for loop. The point here is that the test inside the brackets can be anything, not just a simple test like this. Here is a more complicated expression:

int ch;
while ((ch = getchar()) != EOF) {
  /* some code that uses the character ch */
}

EOF is a "character" constant which the O/S puts at the end of all text files. The function getchar() returns the next character in the file. This particular construct is quite complex, and uses an assignment first, and then a comparison, all in the test. This is normally something to avoid, but in this case, this is a common usage, and it is well described in The C Programming Language, so it should be OK. Eventually the ch returned will be EOF, and the loop will end. At that point, the whole file has been processed. Look at the brackets carefully to understand the sequence of events in the test. There are many ways to use this while loop, but when you do use it, make sure that the intended meaning is clear, through the use of good variable names and such.

The second type of loop is the do-while loop. The do-while loop simply loops until the while test at the end is false. Here is an example:

int ch;
do {
  ch = getchar();
  if (ch >= '0' && ch <= '9')
    printf("%c\n", ch);
} while (ch != ' ');

This loop just reads characters in that the user types, printing out only the digits. When the first space is read, the loop exits.

In some languages there is another kind of loop, namely the loop that never ends. This is easily emulated in C, in a number of different ways:

do {
  /* something */
} while (1);

for (i=0; 1; i++) {
  /* something */
}

while (1) {
  /* something */
}

All these three loops go on forever, since the tests are always non-zero, i.e. true. There are two ways to break out. One is to press Ctrl-C, and the other is to include a break statement somewhere in the loop. Here is an example:

while (1) {
  ch = getchar();
  if (ch = ' ')
    break;
  if (ch >= '0' && ch <= '9')
    printf("%c\n", ch);
}

This loop does the same as the loop above. This is sometimes useful when the condition means that you sometimes want part of the loop to be executed, sometimes not. In this case, the test for a digit does not even get tested if the character is a space.

Finally, there is another keyword, continue, which relates to loops. Sometime when you are looping, you want to increment some variable, and only do some processing if some other condition holds true. The above loop is similar to this with respect to printing digits. It could be rewritten as follows:

while (1) {
  ch = getchar();
  if (ch = ' ')
    break;
  if (ch <= '0' || ch >= '9')
    continue;
  printf("%c\n", ch);
}

Now it breaks if it sees a space, iterates the loop if it sees a non-space, non-digit, and prints everything else, i.e. digits. Still the same result, but yet another way to do it.

There are incredibly many variations on these basic ideas. You will likely come across many as you program. Many others can be seen in the source code available here and other places. I will try to cover source code examples later on in this series, after we have covered basic C programming. This should be good experience.

Switch

Sometimes it is required that you examine a variable, and take some action depending on what the value of that variable is. Often this can be done well with an if statement, but if there are more than two or three possible outcomes, you should seriously consider the switch statement. It allows you to direct the flow of the program depending on what value the variable or expression has. The one limitation is that you can only use discrete values, so if you are looking for one of three different conditions to be true, the switch won't work. It has to evaluate to an integer expression ultimately, but because of C's odd types, chars, and enumerated variables work with the switch. The other keywords that go with the switch statement are case and default. Here is a silly example:

switch (ch) {
  case 'a':
  case 'b':
  case 'c':
    printf("small\n");
  case 'd':
    printf("medium\n");
    break;
  default:
    printf("large\n");
    break;
}

This example demonstrates a few things about switch. If you run this, in conjunction with a loop which reads in characters (you should be able to set this up now), you will notice that if you type a 'c', it prints "small" and "medium", if you type a 'd', it only prints "medium", and if you type anything other than a-d, it prints "large". The reason is that when it finds a case which has the same value as the expression in the switch statement, it starts executing at the first non-"case" line of code following the case statement which evaluated to true. It doesn't stop until stopped with a break statement. The case statements themselves don't actually execute at all. They are ignored if execution has started in the switch. This fall-through is yet another feature of C which in hindsight was probably a mistake. It causes a lot of inadvertent errors, and is only very rarely useful.

A more realistic example would be as follows:

switch (ch)
   case 'a':
      /* do some 'a' processing */
      break;
   case 'b':
      /* do some 'b' processing */
      break;
   case 'c':
      /* do some 'c' processing */
      break;
   default:
      /* do all other processing */
}

This is more normal. Note that the break after the last case or default can be left out. I prefer putting it in so that if I later add another case, it won't be inadvertently left out.

Yet again, I am going to opt for supplying some more useful code at a later stage. This should get you started, but you will probably need to see more real code before you really master the switch statement.

Conclusion

Well, I didn't get to functions this month either. I apologize for this, but as I said, this month has been really rough, believe me. I will use that as an excuse to bow out here. Next month, I will finally cover functions, and other things. Hang in there, and we will get to it all.