- •Table of Contents
- •Introduction
- •About This Here Dummies Approach
- •How to Work the Examples in This Book
- •Foolish Assumptions
- •Icons Used in This Book
- •Final Thots
- •The C Development Cycle
- •From Text File to Program
- •The source code (text file)
- •The compiler and the linker
- •Running the final result
- •Save It! Compile and Link It! Run It!
- •Reediting your source code file
- •Dealing with the Heartbreak of Errors
- •The autopsy
- •Repairing the malodorous program
- •Now try this error!
- •The Big Picture
- •Other C Language Components
- •Pop Quiz!
- •The Helpful RULES Program
- •The importance of being \n
- •Breaking up lines\ is easy to do
- •The reward
- •More on printf()
- •Printing funky text
- •Escape from printf()!
- •A bit of justification
- •Putting scanf together
- •The miracle of scanf()
- •Experimentation time!
- •Adding Comments
- •A big, hairy program with comments
- •Why are comments necessary?
- •Bizarr-o comments
- •C++ comments
- •Using Comments to Disable
- •The More I Want, the More I gets()
- •Another completely rude program example
- •And now, the bad news about gets()
- •The Virtues of puts()
- •Another silly command-prompt program
- •puts() and gets() in action
- •More insults
- •puts() can print variables
- •The Ever-Changing Variable
- •Strings change
- •Running the KITTY
- •Hello, integer
- •Using an integer variable in the Methuselah program
- •Assigning values to numeric variables
- •Entering numeric values from the keyboard
- •The atoi() function
- •So how old is this Methuselah guy, anyway?
- •Basic mathematical symbols
- •How much longer do you have to live to break the Methuselah record?
- •The direct result
- •Variable names verboten and not
- •Presetting variable values
- •The old random-sampler variable program
- •Maybe you want to chance two pints?
- •Multiple declarations
- •Constants and Variables
- •Dreaming up and defining constants
- •The handy shortcut
- •The #define directive
- •Real, live constant variables
- •Numbers in C
- •Why use integers? Why not just make every number floating-point?
- •Integer types (short, long, wide, fat, and so on)
- •How to Make a Number Float
- •The E notation stuff
- •Single-character variables
- •Char in action
- •Stuffing characters into character variables
- •Reading and Writing Single Characters
- •The getchar() function
- •The putchar() function
- •Character Variables As Values
- •Unhappily incrementing your weight
- •Bonus program! (One that may even have a purpose in life)
- •The Sacred Order of Precedence
- •A problem from the pages of the dentistry final exam
- •The confounding magic-pellets problem
- •Using parentheses to mess up the order of precedence
- •The computer-genie program example
- •The if keyword, up close and impersonal
- •A question of formatting the if statement
- •The final solution to the income-tax problem
- •Covering all the possibilities with else
- •The if format with else
- •The strange case of else-if and even more decisions
- •Bonus program! The really, really smart genie
- •The World of if without Values
- •The problem with getchar()
- •Meanwhile, back to the GREATER problem
- •Another, bolder example
- •Exposing Flaws in logic
- •A solution (but not the best one)
- •A better solution, using logic
- •A logical AND program for you
- •For Going Loopy
- •For doing things over and over, use the for keyword
- •Having fun whilst counting to 100
- •Beware of infinite loops!
- •Breaking out of a loop
- •The break keyword
- •The Art of Incrementation
- •O, to count backward
- •How counting backward fits into the for loop
- •More Incrementation Madness
- •Leaping loops!
- •Counting to 1,000 by fives
- •Cryptic C operator symbols, Volume III: The madness continues
- •The answers
- •The Lowdown on while Loops
- •Whiling away the hours
- •Deciding between a while loop and a for loop
- •Replacing those unsightly for(;;) loops with elegant while loops
- •C from the inside out
- •The Down-Low on Upside-Down do-while Loops
- •The devil made me do-while it!
- •do-while details
- •The always kosher number-checking do-while loop
- •Break the Brave and Continue the Fool
- •The continue keyword
- •The Sneaky switch-case Loops
- •The switch-case Solution to the LOBBY Program
- •The Old switch-case Trick
- •The Special Relationship between while and switch-case
- •A potentially redundant program in need of a function
- •The noble jerk() function
- •Prototyping Your Functions
- •Prototypical prototyping problems
- •A sneaky way to avoid prototyping problems
- •The Tao of Functions
- •The function format
- •How to name your functions
- •Adding some important tension
- •Making a global variable
- •An example of a global variable in a real, live program
- •Marching a Value Off to a Function
- •How to send a value to a function
- •Avoiding variable confusion (must reading)
- •Functions That Return Stuff
- •Something for your troubles
- •Finally, the computer tells you how smart it thinks you are
- •Return to sender with the return keyword
- •Now you can understand the main() function
- •Give that human a bonus!
- •Writing your own dot-H file
- •A final warning about header files
- •What the #defines Are Up To
- •Avoiding the Topic of Macros
- •A Quick Review of printf()
- •The printf() Escape Sequences
- •The printf() escape-sequence testing program deluxe
- •Putting PRINTFUN to the test
- •The Complex printf() Format
- •The printf() Conversion Characters
- •More on Math
- •Taking your math problems to a higher power
- •Putting pow() into use
- •Rooting out the root
- •Strange Math? You Got It!
- •Something Really Odd to End Your Day
- •The perils of using a++
- •Oh, and the same thing applies to a --
- •Reflections on the strange ++a phenomenon
- •On Being Random
- •Using the rand() function
- •Planting a random-number seed
- •Randoming up the RANDOM program
- •Streamlining the randomizer
- •Arrays
- •Strings
- •Structures
- •Pointers
- •Linked Lists
- •Binary Operators
- •Interacting with the Command Line
- •Disk Access
- •Interacting with the Operating System
- •Building Big Programs
- •Use the Command-Line History
- •Use a Context-Colored Text Editor
- •Carefully Name Your Variables
- •Breaking Out of a Loop
- •Work on One Thing at a Time
- •Break Up Your Code
- •Simplify
- •Talk through the Program
- •Set Breakpoints
- •Monitor Your Variables
- •Document Your Work
- •Use Debugging Tools
- •Use a C Optimizer
- •Read More Books!
- •Setting Things Up
- •The C language compiler
- •The place to put your stuff
- •Making Programs
- •Finding your learn directory or folder
- •Running an editor
- •Compiling and linking
- •Index
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);
}