Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C For Dummies 2nd Ed 2004.pdf
Скачиваний:
43
Добавлен:
17.08.2013
Размер:
8.34 Mб
Скачать

Chapter 18: Do C While You Sleep 229

Use your operating system’s scroll-back buffer to view the lines that have scrolled off the screen. Hopefully, the DOS prompt or terminal window that you’re using has this feature.

What about typing 0 or a negative number? Try that now; run the program and type–5. You see something like this:

T-minus -5

Zero!

Blast off!

The do while loop is executed at least once, so the -5 is displayed. Ack! It isn’t one of the great boo-boos of modern programming history, but it’s bound to startle the astronauts, who are expecting a leisurely though suspenseful takeoff sequence.

The way to guard against this faux pas is to write a special loop to ensure that the value that is typed is kosher. Yes, it’s a kosher number loop. That is han­ dled quite brilliantly by do-while.

The always kosher number-checking do-while loop

One thing you should do in all your programs is — and I have put this on a separate line for emphasis:

Check your input bounds!

This advice makes sense only if you know what input bounds are. Okay: They’re the range of numbers or letters or whatever that your program is looking for. In COUNTDWN.C, they’re numbers from 1 to 100. In some database programs, they’re the “type 40 or fewer character” limits. Stuff like that.

You want to ensure that users cannot type a wrong, or “illegal,” value — one that would screw up your program. You have to make sure that they type only 40 or fewer characters. Any more than that, and your program may die a strange death. You must guard against this situation — and you can, if you write your program correctly.

Traditionally, this type of defensive programming is known as bulletproofing. It protects the program from this type of error in advance. That’s why you check everything the user types, to see whether it’s kosher. If not, you can either ask politely for input again or just print a rude error message.

230 Part III: Giving Your Programs the Ability to Run Amok

To make the COUNTDWN.C program bulletproof, you have to have the pro­ gram ask for input again whenever the value that’s entered is either less than 1 or greater than 100. A do-while loop does that job nicely, and I’m willing to argue that on two points:

The first argument for do-while is that it repeats itself once, no matter what. That way, you can ask the question the first time and it has to be repeated only when the value that’s entered is out of range.

The second argument is that the while part of the loop checks to see whether the value that’s entered (the start variable) is less than 1 or greater than 100.

You don’t have to change COUNTDWN.C very much. Just modify the first part of the program to read:

do

{

printf(“Please enter the number to start\n”); printf(“the countdown (1 to 100):”); scanf(“%d”,&start);

}

while(start<1 || start>100);

The do-while loop asks the same question the program asked earlier. But, after a user types a value, the while part of the loop checks to see whether the value of the start variable is less than 1 OR greater than 100. If either condition is true, the loop repeats, asking the same question over and over until a proper value is entered.

Save the changed COUNTDWN.C source code to disk. Compile the program.

Run it:

Please enter the number to start

the countdown (1 to 100):

Type 0 and press Enter.

Ha! The program asks again. Type 101 and press Enter.

Golly, this program is smart! Any value outside the range from 1 to 100 causes the program to ask again and again for the proper number to be pressed. That’s all made possible with a nifty do-while loop.

Bounds checking like this is done in just about every professional pro­ gram. Whenever you’re asked to type a value in a certain range or to type fewer than so-many letters, a loop is in there, making sure that you’re doing it right.

Chapter 18: Do C While You Sleep 231

Most of the problems Microsoft has had with critical or fatal errors in its software are caused by a lack of this type of bounds checking.

Refer to Chapter 14 for more information about the logical || (OR)

comparison.

You may want to insert the following comment into your source code, just above the first loop:

/* This loop ensures they type in

a proper value */

Nested Loops and Other

Bird-Brained Concepts

Glorious loops within loops, wheels within wheels, spinning ’round like some nauseating amusement park ride with a drugged-out, tattooed guy named Craig asleep at the controls. But that’s another subject. In the C programming lan­ guage, spinning two loops is a cinchy and practical thing to do. It’s called making a nested loop, or with one loop inside another.

Adding a tense, dramatic delay to the COUNTDWN.C program

What’s missing from the COUNTDWN.C program is a little tension. In case you haven’t noticed, typing any value from 1 to 100 doesn’t really affect the speed at which the countdown is displayed; after you press Enter, the text zips on up the screen. No suspense!

To help slow down the display, you can insert a delay loop into the program. The purpose of the delay loop is merely to spin the computer’s CPU, burning up clock cycles to slow down the program at a certain point. Yes, you do it on purpose.

Modify the second do while loop in the COUNTDWN.C program to read:

do

{

printf(“T-minus %d\n”,start); start--;

for(delay=0;delay<100000;delay++); /* delay loop */

}

while(start>0);

232 Part III: Giving Your Programs the Ability to Run Amok

And, because the program would puke if it encountered the delay variable without its first being declared, add the following line just below the int start statement, at the top of the source code:

long delay;

Here’s the entire, updated source code, including changes added in the previ­ ous sections:

/* An important program for NASA to properly launch America’s spacecraft. */

#include <stdio.h>

int main()

{

int start; long delay; do

{

printf(“Please enter the number to start\n”); printf(“the countdown (1 to 100):”); scanf(“%d”,&start);

}

while(start<1 || start>100);

/* The countdown loop */

do

{

printf(“T-minus %d\n”,start); start--;

for(delay=0;delay<100000;delay++); /* delay loop */

}

while(start>0);

printf(“Zero!\nBlast off!\n”); return(0);

}

Ensure that your source code for COUNTDWN.C resembles this source code, which now has a nested loop, for purposes of delaying the text display and output.

Save. Compile. Run.

If the output still runs too fast, change the value in the for loop from 100,000 to 1,000,000 (written like this: 1000000). If that still doesn’t work, try 2,000,000. (If you need to go to 4,000,000, you need to declare the delay variable as an unsigned long.)

Chapter 18: Do C While You Sleep 233

Having a for loop inside a while loop is referred to as a nested loop. Note that both loops don’t need to be of the same type (two for loops or two while loops).

A nested loop is basically one loop spinning ’round inside another loop.

The first loop, or outside loop, ticks off first. Then, the inside loop ticks off, looping as many times as it does. After that, the outside loop ticks off another one, and then the inside loop is repeated entirely again. That’s how they work.

Keep separate the variables associated with one loop or another. For example, the following two for loops are nested improperly:

for(x=0;x<5;x++)

for(x=5;x>0;x--);

Because x is used in both loops, these nested loops don’t behave as you expect. This loop is infinite, in fact, because both are manipulating the same variable in different directions.

This disaster probably isn’t apparent to you. You write some huge pro­ gram and nest two for loops miles apart without thinking about it, by using your favorite variable x (or i) in each one. Those kind of bugs can wreck your day.

The way to avoid messing up nested loops is to use different variables with each one — for example, a or b, or i1 and i2, or even something descriptive, such as start and delay, as used in the COUNTDWN.C example.

That nested for loop in COUNTDWN.C ends with a semicolon, indicating that it doesn’t “own” any statements that are repeated. Here’s another way you could format it:

for(delay=0;delay<100000;delay++)

;

This example shows you that the for loop doesn’t have any statements worth repeating. It just sits and spins the microprocessor, wasting time (which is what you want).

Although delay loops, such as the one shown in COUNTDWN.C, are common, a better way exists. That is to use the computer’s internal clock to time a delay of a specific duration. I show you an example in C All-in-One Desk Reference For Dummies (Wiley).

My first IBM PC — some 20 years ago — required a delay loop that counted to only 10,000 for about a half-second pause between each line displayed. Today’s computers are much, much faster — obviously!

234 Part III: Giving Your Programs the Ability to Run Amok

Sleepy time!

The C language does have a built-in delay func­ tion, so you really have no need to program a delay loop — as long as you can stand the wait!

The sleep() function is used to pause a pro­ gram for a given number of seconds. Yes — I said seconds. You specify the seconds to wait in sleep()’s parentheses:

sleep(40);

You can catch 40 winks — or 40 seconds — of wait time while a program is running.

You can replace the for delay loop in COUNTDWN.C with

sleep(1);

This line adds a dramatic pause between each line’s output — a slow, dramatic, and often mad­ dening pause. But, it works.

Note that in some implementations of GCC, the sleep() function apparently uses millisec­ onds, not seconds, as its argument. To delay one second, for example, you use this command in COUNTDWN.C:

sleep(1000);

Keep in mind that this implementation of the sleep() function is nonstandard.

The nitty GRID.C of nested loops

Nested loops happen all the time. Most often, they happen when you’re filling in a grid or an array. In that case, you work on rows and columns, filling up the columns row-by-row, one after the other, or vice versa. An example of how it’s done is shown in the GRID.C program, which displays a grid of numbers and letters:

#include <stdio.h>

int main()

{

int a; char b;

printf(“Here is thy grid...\n”);

for(a=1;a<10;a++)

{

for(b=’A’;b<’K’;b++)

{

printf(“%d-%c “,a,b);

}

putchar(‘\n’); /* end of line */

}

return(0);

}