【问题标题】:How do I loop through characters with char*'s in C?如何在 C 中循环使用 char* 的字符?
【发布时间】:2016-01-22 22:06:34
【问题描述】:

我正在尝试在 C 中创建一个计算器。我确信我的 eval 函数中的 (char* String) 参数是正确的,但我真的不明白为什么或如何正确使用它。我的 eval 函数将以后缀表示法输入数学表达式。所以这是我到目前为止的代码,基本上我正在尝试接收一个字符串,将所有数字推入一个字符串堆栈,然后如果找到一个运算符,则从字符串堆栈中弹出两个“字符串”,将这些字符串转换为整数(这是我不确定该怎么做的另一件事),进行计算,将结果推送到 int 堆栈上。搜索完所有输入后,循环遍历 int 堆栈并添加所有 int。这是我的代码:(忽略包含)/*

int eval(char* String);   //implicit declarations
int bourneLongPush(int);
char* bournePop(void);
int bournePush(char *string);
int bourneLongPop(void);
int bourneGetLongStackSize(void);

int eval(char* String)
{
    int result = 0;
    int index = 0;
    int arg1;
    int arg2;
    char* endptr;

    while(String[index] != '\0'){                      //while our     String pointer is not equal to null,
        if(strtoimax(String, &endptr, 10) == NULL){    //if the character isn't a number,
            switch(String[index]){                     //switch on the operator
            case "+":  
                arg2 = bournePop();
                arg1 = bournePop();//*** how do I change char*'s to ints?
                bourneLongPush(arg2+arg1);
                break;
            case "-":
                arg2 = bournePop();
                arg1 = bournePop();
                bourneLongPush(arg2-arg1);
                break;
            case "/":
                arg2 = bournePop();
                arg1 = bournePop();
                bourneLongPush(arg2/arg1);
                break;
            case "*":
                arg2 = bournePop();
                arg1 = bournePop();
                bourneLongPush(arg2*arg1);
                break;
            case ">":
                arg2 = bournePop();
                arg1 = bournePop();
                bourneLongPush(arg2>>arg1);
                break;
            case "<":
                arg2 = bournePop();
                arg1 = bournePop();
                bourneLongPush(arg2<<arg1);
                break;
            case "^":
                arg2 = bournePop();
                arg1 = bournePop();
                bourneLongPush(pow(arg2, arg1));
                break;
            case "|":
                arg2 = bournePop();
                arg1 = bournePop();
                bourneLongPush(arg2|arg1);
                break;
            case "&":
                arg2 = bournePop();
                arg1 = bournePop();
                bourneLongPush(arg2&arg1);
                break;
            case "%":   
                arg2 = bournePop();
                arg1 = bournePop();
                bourneLongPush(arg2%arg1);
                break;
            default:
                break;
        }
        else{                                //a number was found
        int check = bournePush(String[index]);//push the number into string stack
            if(check == 1)
            {
                //error in push due to size
            }
        }
    index++;
    }
}
//Our input was read in as null so no more input needs to be read
    for(int j = 0; j<(int)bourneGetLongStackSize; j++)
    {
        int num = bourneLongPop();
        result += num;
    }
    return result;
}

【问题讨论】:

  • 你不能把arg2 = bournePop(); arg1 = bournePop();移到switch语句之前吗?

标签: c stack calculator


【解决方案1】:

所以,我建议不要将所有字符推入堆栈,然后将它们转换为整数并应用运算符,我们为什么不将它们转换为整数,然后再将它们推入堆栈然后应用运算符。

因此,循环中的else 条件应如下所示::

int num = 0;
while() {
    if(the character isn't a number) { //I do not exactly understand the condition you used here, but I hope you have got it figured
        bournePush(num);
        num = 0;
        switch(String[index]) {
        ...
        ...
        //remains same
        }
    }
    else {
        convertToNum(num, string[index]);
    }
}

这里我使用num来存储当前在字符串中的数字值,所以说如果我在字符串中遇到123,我将使用convertToNum函数将int 123存储在num中,所以当我命中一个运算符,我只需将完整的num 压入堆栈,然后将其重新初始化为0,以便我可以使用它来存储下一个数字。

这就是convertToNum 的样子 ::

void convertToNum(int &num, char digit) {
    int numDigit = digit - '0';
    num = num*10 + numDigit;
}

这将回答您关于如何将字符转换为整数的问题。这里我通过引用传递num,以便我在converToNum 中所做的任何更改也可以在main 中看到。然后在numDigit 中,我从digit 中减去char 0,这将从char digit 中减去char 0 的ASCII 值,并得到该字符表示的整数值。然后我用10 做一个简单的乘法并加上下一个数字,只是简单的数学运算。

此外,这大大简化了 bournePopborneLongPop 函数,因为现在你的堆栈只是整数,所以你不需要分离函数,现在你只需从堆栈中弹出一个值并使用与switch 中的运算符一起使用。

我希望这会有所帮助!

编辑 ::

我假设你的后缀字符串之间有空格来表示单独的数字,所以你实际上可能有一个这样的字符串 ::

123 456 +

所以,上面的代码实际上会失败,因为在456 之后它会遇到空间,在该空间上它将进入if 条件并将456 推入堆栈,然后当它到达+ 时它将推入0 入栈,然后在0 and 456 上应用+,这是错误的,所以我们只有在遇到空间时才将bournePushnum 放在栈中。所以你的最终代码应该是这样的::

int num = 0;
while() {
    if(the character isn't a number) { //I do not exactly understand the condition you used here, but I hope you have got it figured
        if(String[index] == ' ') {
            bournePush(num);
            num = 0;
        } else {
            switch(String[index]) {
            ...
            ...
            //remains same
            }
        }
    }
    else {
        convertToNum(num, string[index]);
    }
}

此外,我不完全认为您的​​ switch 会起作用,因为当您编写 switch(String[index]) 时,您已经为 char 定义了 switch,当您编写 case "+" 时,您将案例条件定义为我相信它会给出一个编译错误的字符串。所以,你所有的case都应该改成这样case '+',这样就可以了。

此外,检查字符是否为数字的更简单方法是::

int checkNum(char a) {
    if(a >= '0' && a <= '9')
        return 0;
    return 1;
}

这个检查a是否在09之间,否则返回0(false)和1(true),只是建议!

【讨论】:

    【解决方案2】:

    1) if(strtoimax(String, &amp;endptr, 10) == NULL){ 不是测试转换是否有效的好方法。

    intmax_t value = strtoimax(String, &endptr, 10);
    if (endptr != String) {
      // endptr now points to the next part of the string to parse
      ConversionWorked(value);
    } else
      ConversionFailed();
    }
    

    代码可以清除errno 以检测溢出

    errno = 0;
    intmax_t = value = strtoimax(String, &endptr, 10);
    if (endptr != String) {
      if (errno) ConversionOverflowed(value)
      else ConversionWorked(value);
    } else
      ConversionFailed();
    }
    

    2) 错误的switch() 用法

    switch(String[index]) {
      // case "+": 
      case '+': // String[index] is a `char`, not a string
    

    3) 可能的其他问题,例如bournePush() - 但需要查看未发布的代码才能解决..

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-15
      • 2013-04-29
      • 2021-02-04
      • 2015-11-26
      • 1970-01-01
      • 2021-07-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多