• 初学C语言,写给自己的第一个实用程序


    计算器:第一个实用程序

    在 C 语言编程的学习之路上,同学们在了解基本概念,掌握基础语法之后,一定跃跃欲试想要给自己开发一款有意义的实用程序。

    编程实现计算器是一个不错的选择。因为它难度适中,需要用到的知识又恰好涵盖了 C 语言的基本关键点,还具有一定的实用性,是 C 语言初学者比较适合的练手项目。

    在进行下一步练习之前,同学们先对照一下自己是否掌握以下知识:

    • 数据类型:整型、字符型、浮点型、枚举、数组、结构体,以及指针等;
    • 基本语句:顺序、循环、分支、跳转等;
    • 算术运算:加、减、乘、除等;
    • 输入输出处理:字符串的格式化输入输出,实现命令行交互。

    如果上述知识点都已经掌握,那么我们来考察一下计算器程序都有哪些功能。

    大家都使用过手持式计算器,它有一个窗口可以显示输入的数字和计算的结果,还有若干包含数字和运算符的按键,我们通过按键输入数字和运算符完成计算。

    以手持式计算器作为参考,我们可以将程序设计为命令行式交互,接收键盘输入的数字和运算符,计算后将结果显示在屏幕上。这里面需要考虑如何对四则运算表达式求值、数据的验证、交互的友好性等问题。

    我们现在开始手撸一个计算器程序吧。

    手写计算器

    在动手写代码前,我们要先确定具体要实现的功能。因为在没想清楚时就一头扎到代码的细节里,写着就会发现难度比自己想象中要大。例如四则运算的混合运算就要判断运算符的优先级,这对于初学者来说实现起来并不容易。

    所以我们可以遵循最小可用原则,即规划功能尽量从简单实现开始,但要保证核心功能是完备的。在完成一个版本之后,再增加复杂度,不断迭代前进。

    这样既可以保证每一步都能得到可用的程序,还让自己的信心逐渐增强。对于第一版计算器程序,规划以下核心功能:

    • 只实现两个数之间的四则运算;
    • 输入序列为[第一个数] [运算符号] [第二个数]
    • 使用switch-case分支语句处理计算逻辑;
    • 对无效数字和无效符号进行判断。

    根据上述功能规划,实现的第一版程序,同学们可以参考一下。

    #include 
    #include 
    
    int main(int argc, char *argv[]) {
        double num1, num2, result;  // 声明变量
        char op;
    
        printf("请输入第一个数字:");
        scanf("%lf", &num1);
    
        printf("请输入运算符:");
        scanf(" %c", &op);
    
        printf("请输入第二个数字:");
        scanf("%lf", &num2);
    
        switch(op) {  // 根据运算符进行相应运算
            case '+':
                result = num1 + num2;
                break;
            case '-':
                result = num1 - num2;
                break;
            case '*':
                result = num1 * num2;
                break;
            case '/':
                if(num2 == 0) {  // 处理除数为0的情况
                    printf("错误:除数不能为0\n");
                    exit(1);
                }
                result = num1 / num2;
                break;
            default:  // 处理无效运算符的情况
                printf("错误:%c 是无效运算符\n", op);
                exit(1);
        }
    
        printf("%.2f %c %.2f = %.2f\n", num1, op, num2, result);
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    审查上述代码,我们以double类型来定义待计算的变量,以char类型将运算符作为字符型存储,然后通过switch-case条件分支语句对运算符进行识别并处理。

    我们可以在 Linux 环境下使用 gcc 工具编译、运行调试、测试示例代码。

    正常运行示例:
    在这里插入图片描述

    错误的符号运行示例,判断出&是无效字符:
    在这里插入图片描述

    判断出除数不能为零的错误运行示例:
    在这里插入图片描述

    至此,一个能完成两个数之间四则运算的简单计算器程序就开发好了。同学们一定会发现这个程序还有许多地方是可以优化的,例如输入的不是数字,而是字符串,会发生什么?或者交互方式是不是还可以更加友好一些?

    所有有待改进之处,同学们都可以去积极探索。接下来我们就将挑战一个更有难度的功能,就是如何实现复杂表达式的计算。

    更进一步:复杂表达式的计算

    作为一款实用计算器,要能够依据运算符的优先级,实现对多个数的混合四则运算,并且还能支持括号的优先级处理。

    这里需要引入一个数据结构——栈(stack),它的特点是“先进后出”,只能在栈顶执行压入(push)和弹出(pop)操作。我们需要创建两个栈:一个操作数栈和一个运算符栈。简单起见,栈可以用数组来实现。

    有了栈之后,就要对表达式进行解析,通过对运算符和操作数的入栈、出栈操作,完成整个表达式的计算工作。根据运算符和括号的优先级顺序,从左至右遍历表达式,下面以伪代码的形式说明求值规则。

    #define STACK_SIZE 128
    
    double eval_expr(char* expr) {
    	// 定义运算符栈和操作数栈
    	char op_stack[STACK_SIZE];
    	double num_stack[STACK_SIZE];
        
        对于每个token in expr:
            如果 token 是操作数:
                将 token 解析为操作数,并压入 num_stack
            如果 token 是运算符:
                当 op_stack 非空 且 栈顶运算符的优先级 >= token 的优先级:
                    弹出栈顶运算符,从 num_stack 弹出两个操作数进行运算,并将结果压入 num_stack
                将 token 压入 op_stack
        
        当 op_stack 非空:
            弹出栈顶运算符,从 num_stack 弹出两个操作数进行运算,并将结果压入 num_stack
        
        return num_stack 的栈顶元素
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    为了更好地理解 ,来观察一个混合运算示例:“3 * 4 + (2 - 1) / 5 ^ 2”。

    // 在“3 * 4”入栈后,栈中数据如下
    num_stack = [3, 4];
    op_stack = [*];
    // 遇到 + 号,它的优先级低于 * 号,暂停入栈,将 3 * 4 出栈先行计算,再将结果12入栈
    num_stack = [12];
    op_stack = [+];
    // “(2-1”入栈之后数据如下
    num_stack = [12, 2, 1];
    op_stack = [+, (, -];
    // 遇到右括号,停止入栈,要匹配左括号,并弹出栈中数据进行计算
    num_stack = [12, 1];
    op_stack = [+];
    // “/5^2”入栈后数据如下
    num_stack = [12, 1, 5, 2];
    op_stack = [+, /, ^];
    // 接下来依次对出栈数据进行计算,得到结果
    num_stack = [12.04];
    op_stack=[];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    同学们可以在上一节完整示例的基础上添加功能,将伪代码改写为具体的功能实现。这个功能更为复杂,实现的时候需要保持耐心,把握住细节,同时多考虑错误处理和异常情况。

    通过这个主题,同学们了解如何使用 C 语言构建一个简单的计算器,并掌握处理用户输入、表达式解析和求值的基本技术。同时可以进一步扩展计算器的功能或进行其他有趣的项目,以便继续发展和挑战自己。

  • 相关阅读:
    【GAMES101】作业 6: 加速结构
    uniapp小程序使用uQRCode.js生成二维码
    word文档怎么转换成pdf?几个实用文档转换方法
    Java 变量和数据类型
    网络安全(加密技术、数字签名、证书)
    人工智能第2版学习——盲目搜索3
    【vue】使用less报错:显示this.getOptions is not a function
    next_permutation(全排列)
    驱动开发:内核无痕隐藏自身分析
    iOS描述文件(.mobileprovision)一键申请
  • 原文地址:https://blog.csdn.net/michaeluo/article/details/133934445