【问题标题】:Calculator with Decimal, Octal and Hexal Numbers十进制、八进制和十六进制数的计算器
【发布时间】:2019-04-29 05:33:29
【问题描述】:

我想制作一个能够用十进制数进行计算并能够以各自的二进制、八进制或十六进制表示形式返回十进制值的计算器。

到目前为止,在 main 方法中程序读取命令行,我可以通过两种方式调用程序。

第一种方法是使用 3 个值:

"number1" "operator" "number2".

第二种方法是使用 4 个值:

“希望输出的数字系统”“number1”“operator”“number2”。

对于希望的数字系统,输出 b 代表二进制,o 代表八进制,h 代表十六进制。在这两种方式中,用户都应该能够为输入 number1 和 number2 输入十进制、八进制和十六进制数。

#include "zahlen.h"
#include <stdio.h>
#include "stringTOint.h"   

int main(int argc, char *argv[]) {
    char o,op,sx[DIGITS+1],sy[DIGITS+1],sz[DIGITS+1];
    int x,y,z;
    char flag_x,flag_y;

    /* 1) Read Commandline */
    if (argc != 4 && argc != 5) {
        printf("Aufruf: %s -o <x> <op> <y> \n",argv[0]);
        return 1;
    } else if(argc == 4) {
        x = stringTOint(argv[1]);
        op = argv[2][0];
        y = stringTOint(argv[3]);
    } else if(argc == 5) {
        o = argv[1][0];
        x = stringTOint(argv[2]);
        op = argv[3][0];
        y = stringTOint(argv[4]);
        if(o != 'b' && o != 'o' && o != 'h') {
            printf("Wrong Operation\n");
            return 1;
        }
    }

    /* 2) Solve the equation */
    if(argc==4) {
        printf("solve: %s %c %s \n", argv[1], op, argv[3]);
        z = solve(x, op, y);
    } else if(argc==5) {
        printf("solve: %s %c %s \n", argv[2], op, argv[4]);
        z = solve(x, op, y);
    }

    /* 3) Calculate the Representation of the wished Numeral System */
    switch(o) {
        case 'b':
            intTObinaer(x, sx);
            intTObinaer(y, sy);
            intTObinaer(z, sz);
            break;

        case 'o':
            intTOoctal(x,sx);
            intTOoctal(y,sy);
            intTOoctal(z,sz);
            break;

        case 'h':
            intTOhexal(x,sx);
            intTOhexal(y,sy);
            intTOhexal(z,sz);
            break;

        default:
            intTObinaer(x, sx);
            intTObinaer(y, sy);
            intTObinaer(z, sz);
            break;
    }

    /* 4) Return the results */
    printf("\n  %s %d\n%c %s %d\n= %s %d\n", sx,x,op,sy,y,sz,z);

    return 0;
}

方法 intTObinaer、intTOoctal 和 intTOhexal 仅在十进制数被除的基数上有所不同。

intTObinaer(int i, char str[]) {
    unsigned int zahl = i;
    int j;

    /* Fill Array with zeros */
    int x = 0;
    for (x; x < DIGITS+1; x++) {
        str[x] = '0';
    }

    /*Calculate the Binary representation of the given Decimal integer */
    for (j = DIGITS-1; j > 0; j--) {
        /* This base gets changed to 8 or 16 for octal and hexal representation */
        str[j] = (char) (zahl % 2) + '0';
        zahl = zahl / 2;
        if (zahl == 0) {
            break;
        }
    }

    /* Set the end of the Array */
    str[DIGITS] = '\0';
}

实际方程在求解方法中得到求解,其中 number1 和 number2 的正确操作由 switchcase 选择,其中不同的情况可以通过用户在两个数字之间输入的字符操作来选择。

#include <stdio.h>

int solve(int x, char op, int y) {
    int ergebnis = 0;
    switch(op) {
        case '+':
            ergebnis = x + y;
            break;

        case '-':
            ergebnis = x - y;
            break;

        case '*':
            ergebnis = x * y;
            break;

        case '/':
            ergebnis = x / y;
            break;

        case '&':
            ergebnis = x & y;
            break;

        case '|':
            ergebnis = x | y;
            break;

        default:
            printf("Wrong input\n");
    }

    return ergebnis;
}

我现在的问题是由于用户应该能够输入不同的数字系统(例如十进制、八进制或十六进制)我如何识别不同的数字系统然后将它们转换为十进制以便我可以计算结果。之后,必须将这些十进制数字转换回用户想要的所需数字系统。

【问题讨论】:

  • 如果没有任何指示符,就无法知道像3 这样的数字是属于八进制、十六进制还是十进制。您必须要求用户指定每个输入将在哪个系统中。
  • 所以在我的情况下,我会不使用十进制值的前缀,使用零作为八进制数的前缀,使用 0x 作为十六进制数的前缀
  • @Trikalium 输入错误的数字(如0128、0x12abx)会发生什么?
  • 如果出现 '0x12abx' 或 '0128' 之类的情况,最好在 stringTOint 转换期间发出警告

标签: c binary hex octal


【解决方案1】:

我想建议另一种方法来解决这个问题。

您执行的许多解析可以直接由sscanf 函数执行,唯一的情况是需要以不同方式实现的二进制情况。

实现遵循 3 个主要步骤:

  1. 使用sscanf函数(或ConvCharToBin用于二进制值)解析输入并将值存储在变量a和b中;
  2. 执行运算并将结果存储在res变量中;
  3. 使用printf 解析(或循环为二进制大小写)打印输出结果。

实现如下:

#include<stdio.h>
#include<string.h>

typedef struct stack {
    unsigned char data[32];
    int size;
} stack_t;

int ConvCharToBin(char* input);

int main(int argc, char *argv[]) {

    char numSys = 'd', op;
    char** param = argv;
    int a, b, res;

    param++;

    //error case
    if(argc != 4 && argc != 5) {
        //not a valid input
        printf("Not a valid input");
        return -1;
    }

    if(argc == 5) {
        numSys = param[0][0];
        param++;
    }

    op = param[1][0];

    switch(numSys) {
        case 'b':
            a = ConvCharToBin(param[0]);
            b = ConvCharToBin(param[2]);
            break;

        case 'd':
            sscanf(param[0], "%d", &a);
            sscanf(param[2], "%d", &b);
            break;

        case 'h':
            sscanf(param[0], "%x", &a);
            sscanf(param[2], "%x", &b);
            break;

        case 'o':
            sscanf(param[0], "%o", &a);
            sscanf(param[2], "%o", &b);
            break;

        default:
            //no viable number system
            return -1;
    }

    switch(op) {
        case '+':
            res = a + b;
            break;

        case '-':
            res = a - b;
            break;

        case '/':
            res = a / b;
            break;

        case '*':
            res = a * b;
            break;

        case '&':
            res = a & b;
            break;

        case '|':
            res = a | b;
            break;

        default:
            //no valid operand
            printf("invalid operation\n");
            return -1;
    }

    stack_t tmp;
    tmp.size = 0;
    int i;

    switch(numSys) {
            case 'b':
                while (res) {
                    if (res & 1) {
                        tmp.data[tmp.size] = '1';
                        tmp.size++;
                    } else {
                        tmp.data[tmp.size] = '0';
                        tmp.size++;
                    }
                    res >>= 1;
                }
                for(i = tmp.size - 1; i >= 0; i--) {
                    printf("%c", tmp.data[i]);
                }
                printf("\n");
                break;

            case 'd':
                printf("%d\n", res);
                break;

            case 'h':
                printf("%x\n", res);
                break;

            case 'o':
                printf("%o\n", res);
                break;
        }

    return 0;

}

int ConvCharToBin(char* input) {
    char* idx;
    int res = 0x00000000;

    for(idx = input; idx < input + strlen(input); idx++) {
        res <<= 1;
        if(*idx == '1') {
            res |= 0x00000001;
        }
    }

    return res;
}

sscanf 从字符串中读取格式化数据(在您的情况下为argv 字符串)

这可以使用以下方式解析:

  • %d 为十进制;
  • %x 表示十六进制;
  • %o 八进制。

不幸的是,没有使用sscanf 解析二进制文件的 C 标准,所以这是使用 stdout 分开完成的。

我还要指出,这个实现有两个限制

  • 输入/输出限制为 32 位无符号(因此从 0 到 4294967295),但稍作修改即可扩展;
  • 不对输入值进行错误检查,这也很容易实现。

【讨论】:

  • for(idx = input; idx &lt; input + strlen(input); idx++) 相当新颖。来个简单的for(idx = input; *idx; idx++) 怎么样?
  • 抱歉,我不明白我的指针 (*idx) 的内容如何用作for loop exit condition。在输入字符串中找到0后循环不会结束吗?
  • 是的,只要在输入字符串中找到 0,循环就会结束。这不是目标,在读取 null 字符 时结束循环吗?
  • 啊,明白了!我只是忘记了该值是 ASCII 编码的。干杯:)
【解决方案2】:

看起来您只需要添加两行即可:

#include "stdlib.h"

#define stringTOint(arg) ((int)strtol(arg,NULL,0))

或者更好的是,将stringTOint() 的调用替换为相应的strtol() 调用(当然还要添加#include)。

strtol() 使用与 C 文字相同的前缀:0 用于八进制,0x 用于十六进制,没有前缀是十进制。

【讨论】:

  • 谢谢@chux,我不知道我是怎么搞砸的
猜你喜欢
  • 1970-01-01
  • 2011-08-21
  • 2016-09-04
  • 1970-01-01
  • 1970-01-01
  • 2015-12-12
  • 2014-03-11
  • 2021-06-08
  • 2011-12-09
相关资源
最近更新 更多