user1763115
user1763115

Reputation:

Input validation in C

I'm writing a program in C. In the program, the user has to choose a number, either 1, 2 or 3. I would like to construct the code so that when the user enters in a number that isn't 1, 2 or 3, he/she will be told "Invalid selection - choose again" and then they will be brought back to the start of the program:

int main() {

    int choice;
    char response, Y, N;

    printf("Choose a shape from the following:\n 1.Sphere\n 2.Cone\n 3.Cylinder\n");

    scanf("%d",&choice);

    if(choice==1||choice==2||choice==3) {
        printf("Enter the radius, r\n");                             
    } else
        printf("Invalid selection, choose again.\n");

}

What I would like is that after "Invalid selection, choose again" appears, the user is brought back to the start of the program, so they can input their choice again. How would I do this?

Upvotes: 3

Views: 29610

Answers (6)

Mubarak
Mubarak

Reputation: 1

here is a simple validation using the while loop, I just copied your code and made a few adjustments, here the code will scan the integer from the user and will proceed to print "Enter the radius, r" only and only if the user types in the integers 1, 2 or 3, otherwise the program will keep on asking him to type in the correct input.

int main() {

    int choice;
    char response, Y, N;

    printf("Choose a shape from the following:\n 1.Sphere\n 2.Cone\n 3.Cylinder\n");

    scanf(" %d",&choice);
    while((choice<=1)||(choice>=3)){

            printf("Invalid selection, choose again.\n");
            scanf(" %d",&choice);
    }
    printf("Enter the radius, r\n");

}

Upvotes: 0

William Morris
William Morris

Reputation: 3684

Here is an alternative for you to consider. Notice that the getting of user input is separated into a function and the main() just calls that function and loops on error. Readers of main() probably don't care about how you get the input choice, so why make them read it?

Also notice that I used fgets, not scanf. If you run your version with scanf and enter a non-digit, that character will remain in the input buffer indefinitely; scanf will never remove it as it is looking for digits to satisfy the %d format string - hence an infinite loop. You could try flushing stdin before the scanf (using fpurge) but the function would still not correctly handle the closing of stdin (eg with ctrl-d on the shell UNIX based systems).

#include <stdio.h>
#include <stdlib.h>

static int get_shape(int *shape)
{
    char buf[10] = "";
    printf("Choose a shape from the following:\n"
           " 1.Sphere\n 2.Cone\n 3.Cylinder\n");

    if (!fgets(buf, sizeof buf, stdin)) { /* Note: fgets, not scanf */
        exit(1); /* ctrl-d */
    }
    *shape = strtol(buf, NULL, 0);

    if (*shape==1 || *shape==2 || *shape==3) {
        return 1;
    }
    printf("Invalid selection\n");
    return 0;
}

int main(int argc, char ** argv)
{
    int shape = 0;
    while (!get_shape(&shape)) {
        /* loop */
    }
    printf("Choice: %d\n", shape);
    return 0;
}

Upvotes: 2

Dietrich Epp
Dietrich Epp

Reputation: 213258

Some people will object to this, but I think in these situations a plain old goto is a very clean and readable way of doing things, because it emphasizes the linearity of the "normal" control path:

int main(int arg, char *argv[])
{
    int choice;

choose_shape:
    printf("Choose a shape from the following:\n"
           " 1.Sphere\n 2.Cone\n 3.Cylinder\n");
    scanf("%d", &choice);
    if (choice < 1 || choice > 3) {
        printf("Invalid selection, please choose again.\n");
        goto choose_shape;
    }

    printf("Enter the radius, r:\n");
    ...
}

Yes, people have complained about goto so let me justify it some more.

Here is a more sophisticated version that allows you to select a shape by letter:

    char c;
    shape_t shape;
choose_shape:
    printf("Choose a shape: [s]phere, [c]one, c[y]linder:\n");
    scanf("%c", &c);
    switch (c) {
    cases 's':
        shape = SHAPE_SPHERE;
        break;

    case 'c':
        shape = SHAPE_CONE;
        break;

    case 'y':
        shape = SHAPE_CYLINDER;
        break;

    default:
        printf("Not a valid shape: %c\n", c);
        goto choose_shape;
    }

And here is the version with goto. Note that this introduces another variable, flag, whose only purpose is to get rid of the goto statement. You cannot simply use break here (which is an unlabeled goto to begin with) because of the switch statement. I consider this harder to read due to the additional state. It's five lines longer.

    char c;
    shape_t shape;
    int flag;
    for (flag = 0; !flag; ) {
        printf("Choose a shape: [s]phere, [c]one, c[y]linder:\n");
        scanf("%c", &c);
        switch (c) {
        cases 's':
            shape = SHAPE_SPHERE;
            flag = 1;
            break;

        case 'c':
            shape = SHAPE_CONE;
            flag = 1;
            break;

        case 'y':
            shape = SHAPE_CYLINDER;
            flag = 1;
            break;

        default:
            printf("Not a valid shape: %c\n", c);
            break;
        }
    }

Upvotes: 0

Ravindra Bagale
Ravindra Bagale

Reputation: 17655

use do-while loop, loops until correct input
do like this,add choice 4 for exit:

 do {
        scanf("%d",&choice);
int flag=0;
        if(choice==1||choice==2||choice==3) {
            printf("Enter the radius, r\n");                             
        } else {
            printf("Invalid selection, choose again.\n");
            flag=1;
        }
    } while(flag==1&& choice!=4);

Upvotes: -1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726479

Here is what you do:

int choice;
char response, Y, N;
for (;;) {
    printf("Choose a shape from the following:\n 1.Sphere\n 2.Cone\n 3.Cylinder\n");

    scanf("%d",&choice);

    if(choice==1||choice==2||choice==3) {
        break;                    
    }
    printf("Invalid selection, choose again.\n");
}

Once this loop is over, prompt for the radius. You will nearly certainly need another loop to prevent the input of negative values for the radius, so do not prompt for it in the same loop.

Upvotes: 2

Desert Ice
Desert Ice

Reputation: 4600

Use a while loop for this

int main()
{
    int choice;
    char response, Y, N;

    printf("Choose a shape from the following:\n 1.Sphere\n 2.Cone\n 3.Cylinder\n");
    while(1)
    {
        scanf("%d",&choice);

        if(choice==1||choice==2||choice==3)
        {
            printf("Enter the radius, r\n");                             
            //Maybe read the radius here
            scanf("%d",&radius);
            break;
        }
        else
            printf("Invalid selection, choose again.\n");
    }
}

Upvotes: 1

Related Questions