c++字符串操作给我奇怪的/不一致的/错误的结果

C++ string operations giving me weird/inconsistent/wrong results

本文关键字:不一致 错误 结果 字符串 操作 c++      更新时间:2023-10-16

我正试图读取一个应该以以下形式出现的序列:<<strong>变量/strong> 操作符变量操作符变量。等等,其中"变量"由A、B或C组成,"操作符"是四个基本操作符中的一个+ -/*,如果符合给定形式,则简单地打印为有效,如果不符合则打印为无效。此外,条件是序列必须以单个变量开始,然后由操作符尾随(中间允许有空格)。

我已经编写了一些代码,其中我接受字符串输入,只是有一个名为'check'的函数来查看它是否返回false,使程序打印'Invalid'。下面是我的主要函数:

using namespace std;
int main() {
    string m;
    cout<<"Please enter a sequence: "<<endl;
    getline(cin,m);
    bool allow = check(m);
    if(allow == true){
        cout<<"nnCorrect format "<<endl;
    }
    else{
        cout<<"nnIncorrect format n"<<endl;
    }
    system("PAUSE");
    return 0;
}

这是我的检查函数:

bool check(string mi){
    int c=0; //using c as an index,
    mi.append("0"); //append a 0 as a signal to when the string ends
    while(c < mi.length()){
        if(mi.at(c)=='0'){}
        else if(isblank(mi.at(c))){} //So it will accept spaces between the input
        else if(mi.at(c) == 'A' ||mi.at(c) == 'B' ||mi.at(c) == 'C'){ 
            //The sequence must start with a variable...
            c +=1;    //increment to start at the next character...
            while(c < mi.length()){ //This whole loop is to check if the next 
                                //significant character is one of the operators
                if(isblank(mi.at(c))){} 
                else if(mi.at(c) !='+' ||mi.at(c) != '-' ||mi.at(c) != '/' || mi.at(c) != '*' || mi.at(c) !='0'){
                    cout<<"n(Log)  Character at "<<c<<" was not an operator? Value: "<<mi.at(c);
                    //Why does it always come here even if the value was an operator?
                    return false;
                }
                c++;    
            }
        }
        c++;
    }
    return true; //Assume true if there are no errors...
}

即使我输入了正确的序列,比如a +B+C,它仍然是无效的。我已经将问题追溯到上面的特定代码行。为什么会这样呢?

因为你的布尔逻辑不正确。

表达式:

mi.at(c) !='+' || mi.at(c) != '-' || mi.at(c) != '/' || mi.at(c) != '*' || mi.at(c) !='0'

每次都会计算为真。例如,如果mi.at(c)是'-',那么mi.at(c) != '+'的计算结果为true,并进入您不想进入的那部分代码。同样地,如果i.at(c)是一个'+',那么mi.at(c) != '-'的计算结果为真,你的条件计算结果再次为真。

我相信你想把你的布尔"或"(||)改成"与"(&&)。

对于一些未经请求的建议,我个人建议花点时间将问题视为状态机。这将使您能够以可支持和可扩展的方式清理并思考它正在做什么。我不是c++程序员,但我将在c中把它作为状态机来处理。你应该能够把它翻译成c++:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
main() {
    char* VARS   = "ABC";
    char* OPS   = "+-/*";
    char  c     = EOF;
    int   state = 0;
    while (((c = getchar()) != EOF) && (state < 3)) {
        // move on to next character if we have a blank or end-of-line
        if (c == ' ' || c == 'n')
            continue;
        // test to see if the character is a var or op
        int isvars = (strchr(VARS, c) != NULL);
        int isops  = (strchr(OPS,  c) != NULL);
        // based upon character type and current state, determine next state
        if (!isvars && !isops) // character is neither a valid var nor op
            state = 3;
        else if (isvars) // character is a var
            if ((state == 0) || (state == 2))
                state = 1;
            else if (state == 1)
                state = 3;
        else if (isops) // character is an op
            if ((state == 0) || (state == 2))
                state = 3;
            else if (state == 1)
                state = 2;
    }
    puts((state > 1) ? "bad" : "good");
} 

并且,下面是编译为'varop'后的结果:

$ echo "" | ./varop
good
$ echo "A" | ./varop
good
$ echo "+" | ./varop
bad
$ echo "A+" | ./varop
bad
$ echo "AA" | ./varop
bad
$ echo "A+" | ./varop
bad
$ echo "A+A" | ./varop
good
$ echo "A++" | ./varop
bad
$ echo "A + B" | ./varop
good
$ echo "   A + B" | ./varop
good
$ echo "D" | ./varop
bad
$ echo "%" | ./varop
bad

你的问题是正确的,但问题是你的基本逻辑。因为您使用||而不是&&,这意味着您的语句将始终求值为真(即:在第一种情况下,"+"将计算为false,但在检查非-时将计算为true。您需要做的是将罪魁祸首行的||操作符替换为&&,然后您的检查函数应该按预期运行。

此外,作为样式说明,在检查函数的第8行,为了保持一致性,您应该使用c++而不是c += 1

试一下,它会编译并给出所需的输出。但是,它仍然没有强制操作符后面必须跟一个字符。但是我想你能弄明白的。

using namespace std;

为了提供帮助,我创建了一个可能的操作符数组,以及一个检查字符是否为操作符的函数。

unsigned char operators[] = { '+','-','/','*' };

bool isOperator(const unsigned char &m) {
    for (int n = 0; n < 4; n++) if (m == operators[n]) return true;
    return false;
}

在你的检查中只需要一个循环,而for循环更方便。注意逻辑,当字符是a或B或C或为空时,i继续。

bool check(string mi){
    for (int c = 0; c < mi.size(); c++) {
        cout << mi.at(c);
        if (isblank(mi.at(c))) continue;
        if (mi.at(c) == 'A' || mi.at(c) == 'B' || mi.at(c) == 'C') continue;
        if (!isOperator(mi.at(c))) {
            cout<<"n(Log)  Character at " << c <<" was not an operator? Value: "<<mi.at(c);
            return false;
        }
    }
    return true; //Assume true if there are no errors...
}
int main() {
    string m;
    cout<<"Please enter a sequence: "<<endl;
    getline(cin,m);
    cout << "nn" << string(check(m) ? "Correct":"Incorrect") << " format." << endl;
    system("PAUSE");
    return 0;
}
输出:

Please enter a sequence:
A+B+C
A+B+C
Correct format.
Press any key to continue . . .

我建议使用std::istringstream和使用std::copy将单独的组件转换为std::vector的字符。然后很容易遍历vector,只检查有效的组件。

为了帮助使用std::copy将组件放入矢量,我建议您阅读std::istream_iteratorstd::back_inserter