如何使用 else if 条件优化 C 代码

How to optimize C code with else if conditions

我正在学习 C 的一些基础知识(实际上我正在学习哈佛的 cs50x)并且我编写了以下代码:

#include <cs50.h>
#include <stdio.h>

int main(void) {
    while(0 == 0) {
        printf("1. SUM\n2. SUBSTRACTION\n3. MULTIPLICATION\n4. DIVISION\n5. QUIT\n");
    
        int a = get_int("Choose one option: ");
        
        if (a == 1) {
            int x = get_int("x: ");
            int y = get_int("y: ");
            int sum = x + y;
            int sub = x - y;
            int division = x/y;
            int mul = x*y;
            printf("Result = %i\n\n", sum);
        }
        else if (a == 2) {
            int x = get_int("x: ");
            int y = get_int("y: ");
            int sum = x + y;
            int sub = x - y;
            int division = x/y;
            int mul = x*y;
            printf("Result = %i\n\n", sub);
        }
        else if (a == 3) {
            int x = get_int("x: ");
            int y = get_int("y: ");
            int sum = x + y;
            int sub = x - y;
            int division = x/y;
            int mul = x*y;
            printf("Result = %i\n\n", mul);
        }
        else if (a == 4) {
            int x = get_int("x: ");
            int y = get_int("y: ");
            int sum = x + y;
            int sub = x - y;
            int division = x/y;
            int mul = x*y;
            printf("Result = %i\n\n", division);
        }
        else if (a == 5) {
            printf("Alright! See you soon!\n");
            break;
        }
        else {
            printf("Invalid Input\n");
            break;
        }
    }
}

它完全符合我的要求,但我觉得它可以用更好的方式编写。
我真的不喜欢所有重复的 int 变量,我认为可以通过某种方式对其进行优化,但不知道如何进行优化。

在每种情况下计算所有结果有点无用。包含结果的变量也没什么用,因为您可以在 printf 函数中进行计算,如下所示:

printf("Result = %i\n\n", x+y);

最后,您可以将 if 语句更改为 switch case,这将使代码看起来更简洁,在性能方面,switch case 部分不会有任何影响,但其他更改会。

就像 Weather Vane 评论的那样,您可以 while(1)

除“QUIT”和“无效”操作外的所有操作都有行

int x = get_int("x: ");
int y = get_int("y: ");

共同点。因此,将这两行移到 if...else if 链之外是有意义的,这样您只需编写一次。但是,必须事先处理“QUIT”和“无效”的情况,这样用户想退出或输入无效时就不会提示输入这两个操作数。

此外,您始终执行所有 4 种算术运算(加法、减法、乘法和除法),尽管只需要计算用户选择的一种。

此外,我怀疑这些行是否正确:

else {
    printf("Invalid Input\n");
    break;
}

如果用户输入无效输入,您可能希望通过重新启动循环而不是退出程序来重新提示用户输入。

您可以使用 switch 语句来代替长 if...else if 链。

while (0==0){

在技术上是正确的,但是这样写是很不常见的。

为了创建一个无限循环,通常会写 while (1)for (;;),后者是更传统的语法。

这是一个包含上述改进的程序:

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

int main( void )
{
    for (;;)
    {
        printf(
            "1. SUM\n"
            "2. SUBSTRACTION\n"
            "3. MULTIPLICATION\n"
            "4. DIVISION\n"
            "5. QUIT\n"
        );
    
        int a = get_int( "Choose one option: " );

        if ( a == 5 )
        {
            printf( "Alright! See you soon!\n" );

            //break out of infinite loop
            break;
        }

        //verify that input is between 1 and 4
        if ( ! ( 1 <= a && a <= 4 ) )
        {
            printf( "Invalid Input\n\n" );

            //restart loop so that user gets reprompted for input
            continue;
        }

        int x = get_int( "x: " );
        int y = get_int( "y: " );

        switch ( a )
        {
            case 1:
                printf( "Result = %i\n\n", x + y );
                break;
            case 2:
                printf( "Result = %i\n\n", x - y );
                break;
            case 3:
                printf( "Result = %i\n\n", x * y );
                break;
            case 4:
                printf( "Result = %i\n\n", x / y );
                break;
            default:
                //these lines should never be reached
                fprintf( stderr, "internal program error!" );
                exit( EXIT_FAILURE );
        }
    }
}

要改进您的代码,您可以创建操作函数,然后将它们与 if...else 梯形图或 switch...case 语句一起使用。您可以浏览以下代码并提出任何问题。请注意,我不是专业的 C 程序员,这就是我修改您的代码的方式。我相信会有更好的方法来修改你的程序。

#include <stdio.h>

int main(void) {
    
        int a;
    
        float x;
        float y;
        
        float result;
        float my_remainder;
        
        // Let's create functions first
        float my_sum(float x, float y)        // function for addition
        {
            result = x + y;
        };
        
        float my_sub(int x, int y)           // function for subtraction
        {
            result = x - y;
        };
        
        float my_mul(int x, int y)           // function for multiplication
        {
            result = x * y;
        };
        
        float my_div(int x, int y)          // function for divison
        {
            result = x / y;
            my_remainder = x % y;
        };
        
    while(1){
        start:
        printf("1. SUM\n2. SUBSTRACTION\n3. MULTIPLICATION\n4. DIVISION\n5. QUIT\n");
        
        choose:                     // let's choose an option, but can choose only one of the mentioned ones
        printf("choose one option: ");
        scanf("%d", &a);
        
        switch(a)                  // check if "a" is not equal to either one of the mentioned numbers, then go back to 'choose' to ask for the right one
        {
            case 1: case 2: case 3: case 4: case 5: goto letsgo;
            
            default:
            printf("Invalid Input. Please choose an option from the given ones:\n\n"); 
            goto start;
        };
        letsgo:
        if(a == 5)                  // firstly, need to check QUIT condition, if QUIT is selected then the while loop stops (the process ends)
        {
            printf("\nAlright! See you soon!\n");
            //return 0;
            break;
        }
        
        else                        // if QUIT is not selected, it means one of the operations should be done
        {                           // so let's get the numbers for corresponding calculation
        printf("Please enter first number: ");
        scanf("%f", &x);
        printf("Please enter second number: ");
        scanf("%f", &y);
        
        if(a == 1)          // addition
        {
            my_sum(x,y);
            printf("Result = %.2f", result);        // %.2f <-- "2" represents the number of digits after the decimal separator. 
           return 0;                                // e.g., 1.4 + 1.2 = 2.60, however, if it was %.4f, then: 1.4 + 1.2 = 2.6000
        }
        else if(a == 2)     // subtraction
        {
            my_sub(x,y);
            printf("Result %.2f", result);
            return 0;
        }
        else if(a == 3)     // multiplication
        {
            my_mul(x,y);
            printf("Result %.2f", result);
            return 0;
        }
        else if(a == 4)     // division
        {
            my_div(x,y);
            printf("Result %.2f", result);
            if(my_remainder != 0)           // check if remainder is not equal to 0, then print, otherwise, don't print
            {
            printf("\nRemainder: %.2f", my_remainder);
            }
            return 0;
        }
        
        }
        
    }
        
}

这是完整的代码版本

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

int main() {
int choose = 0, num1, num2, work;
float div;

while(choose!=5){
    
    printf(" 1. SUM\n 2. SUBSTRACTION\n 3. MULTIPLICATION\n 4. DIVISION\n 5. QUIT\n");
    printf("Choose an option... \n");
    scanf("%d", &choose);

    printf("\nInsert two numbers: \n");
    scanf("%d", &num1);
    scanf("%d", &num2);
    
    switch(choose){
        case 1:
            work = num1 + num2;
            printf("Sum: %d", work);
            break; //you can use it to terminate your case switch instruction
        
        case 2:
            work = num1 - num2;
            printf("Sub: %d", work);
            break;

        case 3:
            work = num1 * num2;
            printf("Multiplication: %d", work);
            break;

        case 4:
            div = num1 / num2;
            printf("Division: %f", div);
            break;
        
        case 5:
            choose = 5;
            break;
        
        default:
            printf("Error / invalid input");
            break;
    }
}

}

@AndreasWenzel 的回答已经相当不错了,使用条件保护和控制流工具,如 continuebreak

作为替代方案,您可以在开关中分配一个 result 变量,然后执行单个 printf 输出。

int main(void) {
    while (1) {
        printf("1. SUM\n2. SUBSTRACTION\n3. MULTIPLICATION\n4. DIVISION\n5. QUIT\n");
    
        int a = get_int("Choose one option: ");
        
        if (a == 5) {
            printf("Alright! See you soon!\n");
            return 0;
        } 
        else if (a < 1 || a > 4) {
            printf("Invalid Input\n");
            continue;
        }

        int x = get_int("x: ");
        int y = get_int("y: ");
        int result;

        switch (a) {
            case 1:
            result = x + y;
            break;

            case 2:
            result = x - y;
            break;

            case 3:
            result = x * y;
            break;
 
            case 4:
            result = x / y;
            break;
        }

        printf("Result = %i\n", result);
    }

    return 0;
}

作为替代方案,我们可以像以前一样检查正确的输入和退出选择,但是使用函数指针数组来非常简洁地实现这一点。

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int div(int a, int b) { return a / b; }

typedef int(*op)(int, int);

int main(void) {
    op ops[] = { add, sub, mul, div };    

    while(0 == 0) {
        printf("1. SUM\n2. SUBSTRACTION\n3. MULTIPLICATION\n4. DIVISION\n5. QUIT\n");
    
        int a = get_int("Choose one option: ");       

        if (a == 5) {
            printf("Alright! See you soon!\n");
            return 0;
        } 
        else if (a < 1 || a > 4) {
            printf("Invalid Input\n");
            continue;
        }

        int x = get_int("x: ");
        int y = get_int("y: ");
        int result = ops[a - 1](x, y);

        printf("Result = %i\n", result);
    }

    return 0;
}

更进一步,我们可以将要执行的操作的选择分解为具有所有必需的输入错误处理的单独函数,并将函数指针和菜单选项分组到结构中。

typedef int(*op)(int, int);

typedef struct {
    op operation;
    char *menu_option;
} option;

option get_option(char *prompt, char * out_of_range_msg, char *out_of_tries_msg, 
                  option *ops, size_t n, int tries,
                  int add_quit_option, char *quit_option_text, char *quit_msg) {
    while (tries--) {
        for (size_t i = 0; i < n; ++i) {
            printf("%2d: %s\n", i + 1, ops[i].menu_option);
        } 

        if (add_quit_option) {
            printf("%2d: %s\n", n + 1, quit_option_text);
        }

        int opt = get_int(prompt);

        if (opt < 1 || opt > (add_quit_option ? n + 1 : n)) {
            printf("%s\n", out_of_range_msg);
            continue;
        }

        if (add_quit_option && opt == n + 1) {
            printf("%s\n", quit_msg);
            exit(EXIT_SUCCESS);
        }

        return ops[opt - 1];
    }

    printf(out_of_tries_msg);
    exit(EXIT_FAILURE);
}

现在 main 变得更干净了,我们看到添加额外的操作变得多么容易。

int main(void) {
    option ops[] = { 
        {addop, "Sum"}, {subop, "Subtraction"}, 
        {mulop, "Multiplication"}, {divop, "Division"}, 
        {modop, "Modulo"}
    };    

    while (1) {
        option op = get_option("Choose One option: ", "Invalid input", "Too many mistakes!", 
                               ops, 5, 10,
                               1, "Quit", "Alright! See you soon!");

        int x = get_int("x: ");
        int y = get_int("y: ");
     
        printf("Result: %i\n", op.operation(x, y));
    }

    return 0;
}