Matt Pierce

Web Developer

Lesson 6 - More Loops and Decisions

In this lesson we're going to tackle some more decision-making structures, some more looping structures, and handling input errors when using scanf(). We're going to write a program that asks the user for the radius of a circle and then prints the area.

Setting Up

Create the basic structure of a C program. We aren't doing anything special here so we really just need the headers for input/output.

#include <stdio.h>

int main(int argc, char *argv[]) {
    return 0;
}

Inside the main function, we need to define a few variables: a constant value for PI, a floating point number to hold the radius of the circle, and an integer to help us detect input errors.

Let's also output the name of the program at the beginning.

const float pi = 3.141592f;
float radius;
int ret;

printf ("Area of a Circle\n");

Given what you already know about C, you should also feel comfortable prompting the user for input:

printf("Please enter the radius: ");
scanf("%f", &radius);

Remember, you have to pass in the address of radius.

Last, at the end of the program we'll output the result:

printf("The area of a circle with radius %f is %f.\n", radius, radius*radius*pi);

You should be able to compile and run the program at this point. Go ahead and give it a try.

Checking for Errors

You might notice, btw, that your program works fine as long as you type in a number. If you don't enter a number you might get weird or unpredictable results.

We can check for errors in scanf() by storing its return value.

ret = scanf("%f", &radius);

The funciton scanf() will return the number of variables it was able to match to tokens in the format string. In this case, we have one token (%f) and one variable (radius), so we expect it to return 1.

We can check ret and output an error message.

if (ret == 0) {
    printf ("**ERROR: You must enter a number.\n");
}

We might also want to check to make sure that the number entered is a positive number - but we only want to check it when something valid was entered. In this case, we'll change our if statement into an if-else statement.

if (ret == 0) {
    printf ("**ERROR: You must enter a number.\n");
} else if (radius <= 0) {
    printf ("**ERROR: The radius must be a positive number.\n");
}

Looping for Valid Input

It doesn't make any sense to go on to calculate the area of the circle if we got bad input. What we'd really like to do is go back to the beginning of the program and ask for that input again.

In this case, the best way to go about things would be a do-while loop. A do-while loop will do the loop at least one time and then check to see if it should do it again.

In general our program should look something like this

do {
    printf("Please enter the radius: ");
    ret = scanf("%f", &radius);

    if (ret == 0) {
        printf ("**ERROR: You must enter a number.\n");
    } else if (radius <= 0) {
        printf ("**ERROR: The radius must be a positive number.\n");
    }
} while ((ret == 0) || (radius <= 0));

You can compile the program here and give it a try. First try to run the program and enter a negative number. Then try to enter a letter.

If your program ends up in an endless loop, hit Ctrl+Z to exit.

Clearing the Input Buffer

So, your program got stuck in an endless loop - that's unexpected! We've missed an important step here that you had no way of knowing about before now and it all has to do with a weird quirk in scanf().

First let's understand exactly how the program is looping.

  1. The program asks for input and you entered a letter, then pressed Enter.
  2. scanf() returned 0 because your input didn't match the expected input.
  3. Our error check noticed the problem and output the error message.
  4. Our loop also noticed the problem and started over.
  5. The program asks for input and immediately skips past scanf()
  6. Our error check noticed a problem and output the error message.
  7. Our loop also noticed the problem and started over.

So, at first, you might ask "why is my program skipping scanf()? The answer is that it's not.

When you call scanf() your program essentially gets suspended while the operating system waits for input. Once the user hits Enter, the input is returned to the scanf() function, which then scans the input trying to match the format you specified.

Now here's the trick - if it encounters an error, scanf() doesn't clear the input buffer. All the text you entered is sitting right there waiting for you the next time you go through the loop, and that text results in the same error.

What we need to do is use a function called getchar() to get a single character out of the input buffer. We're going to do this until we get to the end of the line or until we get to the end of the buffer because some computers do it one way and some computers do it the other.

while ((ret!='\n') && (ret!=EOF)) ret = getchar();
ret = 0;

We can use ret to store the char returned from getchar() temporarily. But once we're done clearing out the buffer we need to set it back to 0 so that our main loop still works.

The Full Program

In the end your full program should look like this:

#include <stdio.h>

int main(int argc, char *argv[]) {
    const float pi = 3.141592f;
    float radius;
    int ret;

    printf ("Area of a Circle\n");

    do {
        printf("Please enter the radius: ");
        ret = scanf("%f", &radius);

        if (ret == 0) {
            printf ("**ERROR: You must enter a number.\n");
            while ((ret!='\n') && (ret!=EOF)) ret = getchar();
            ret = 0;
        } else if (radius <= 0) {
            printf ("**ERROR: The radius must be a positive number.\n");
        }
    } while ((ret == 0) || (radius <= 0));

    printf("The area of a circle with radius %f is %f.\n", radius, radius*radius*pi);

    return 0;
}

In this lesson we discussed the do-while loop, if-else, and while. We also went over some basic error checking with scanf().