简体   繁体   中英

If statement inside while loop with the same condition

Is there a better way to write the following code by eliminating the repeated condition in the if statement in C?

while (n < 0) {
   printf("Enter a positive integer: ");
   scanf("%d", &n);

   if (n < 0) {
      printf("Error: please enter a positive integer\n");
   }
}

Thank you.

Simply rework your loop breaking when correct input is given. This way the check is done only one time:

while (1)
{
   printf("Enter a positive integer: ");
   scanf("%d", &n);

   if (n >= 0)
       break;

   printf("Error: please enter a positive integer\n");
}

And, as specified in comments, an optimized compiler should be able to reverse the loop by itself.

The following examples are presented in the spirit that people should know what is available in the language. 1 The way I would usually write the code is shown in Frankie_C's answer . As some have noted, optimization usually makes this simple case not worth worrying about, but the question is not limited to a simple evaluation like n < 0 ; the test might be a function call to some expensive evaluation of more complicated criteria.

Folks are not going to like this, but:

    goto middle;
    do
    {
        printf("Error, please enter a positive integer\n");
middle:
        printf("Enter a positive integer: ");
        scanf("%d", &n);
    } while (n < 0);

If you are vehemently opposed to goto , you can use a stripped-down version of Duff's device :

    switch (0)
    do
    {
        printf("Error, please enter a positive integer\n");
    case 0:
        printf("Enter a positive integer: ");
        scanf("%d", &n);
    } while (n < 0);

But you should not.

Footnote

1 Commonly, software engineers will have to work with code written by others, so they must be prepared to recognize and understand anything expressible in the language, even if that is just a first step toward rewriting it into better code. And occasionally situations arise where “ugly” code becomes desirable for commercial or other practical reasons.

This is something that IMO is best accomplished with a bit of refactoring:

#include <stdio.h>
#include <stdbool.h>

static bool get_postive_integer(int *pOut) {
    int n;
    printf("Enter a positive integer: ");
    scanf("%d", &n);

    if(n < 0)
        return false;

    *pOut = n;
    return true;
}

int main(void)
{
   int n;
   while (!get_postive_integer(&n)) {
       printf("Error: please enter a positive integer\n");
   }
}

Give the operation a name , check that it fails, and only then print a message accordingly. The success or failure condition is only coded once here, in the named operation.

You could use:

while (printf("Enter a positive integer: ") > 0 &&
       scanf("%d", &n) == 1 &&
       n < 0)
{
    printf("Error: please enter a positive integer\n");
}

This stops if the printf() fails, if the scanf() fails, or if the value in n is non-negative. It's a good idea to always check that the scanf() succeeds. It is merely convenient that printf() returns the number of characters it wrote (or a negative number on failure) so it can be used in a condition too. You could add fflush(stdout) == 0 && into the stack of operations too.

Or you could decide that the code in the condition should be in a function:

static int read_positive_integer(void)
{
    int value;
    if (printf("Enter a positive integer: ") > 0 &&
        fflush(stdout) == 0 &&
        scanf("%d", &value) == 1 &&
        value >= 0)
        return value;
   return -1;
}

and then the calling code is:

while ((n = read_positive_integer()) < 0)
    printf("Error: please enter a positive integer\n");

There are many variations on the theme; you might wrap the while loop into a function; you might make the prompts into parameters to the function. You might decide to be more careful about reporting what goes wrong (different actions if printf() fails compared with what happens if scanf() returns 0 (non-numeric data in the input) or EOF (no more data in the input).

Another alternative is to split into a function:

int func(){
   int n;
   printf("Enter a positive integer: ");
   scanf("%d", &n);
   return scanf("%d", &n) == 1 ? n : -1;
}

and the loop becomes

while ((n = func()) < 0){
    printf("Error: please enter a positive integer\n");
}

although the assignment in the condition check is not to everyone's taste. Note that I return -1 if the return value of scanf is not 1, something that you should always check.


What I do though in this situation (See Eric's answer) is to write

switch (0) do {
    printf("Error, please enter a positive integer\n");
case 0:
    printf("Enter a positive integer: ");
    scanf("%d", &n);
} while (n/*ToDo - make sure n is initialised if scanf fails*/ < 0);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM