`std::find()` 用字符串产生奇怪的结果

Posted

技术标签:

【中文标题】`std::find()` 用字符串产生奇怪的结果【英文标题】:`std::find()` producing weird results with strings 【发布时间】:2020-04-11 09:31:18 【问题描述】:

我的大学作业是为给定的假设指令集编写汇编程序。我已经实现了它,当我调试时,我实现的std::find() 函数给出了奇怪的结果。请帮忙。

#include <bits/stdc++.h>

//imperative keywords
std::list<std::string> Mn_imp =  "READ","PRINT","MOVER","MOVEM","ADD","SUB","MUL","DIV" ;

//declarative keywords
std::list<std::string> Mn_dcl =  "DS","DS" ;

//assembler directives
std::list<std::string> Mn_drc =  "START","STOP","LTORG","EQU" ;

struct Row 
    std::string name;
    long LC_val;
    Row(std::string _name, long LC) : name(_name), LC_val(LC)  
    bool operator==(const Row& row) 
        return ((this->name == row.name) && (this->LC_val == row.LC_val));
    
;

long LOCCTR = 0;

std::vector<Row> SYMTAB;
std::vector<Row> LITTAB;

std::vector<int> POOLTAB;

std::string getToken(std::string& buffer) 
    std::string retToken;
    int i = 0;
    while (1) 
        if (i == buffer.size()) 
            buffer.clear();
            break;
        
        else if (buffer[i] == ' ' || buffer[i] == ',') 
            i++;
            std::string newString(buffer.begin() + i, buffer.end());
            buffer.clear();
            buffer = newString;
            break;
        
        retToken += buffer[i];
        i++;
    
    return retToken += '\0';


bool getNumber(char* str, long* num_ptr) 
    bool flag = false;
    int i = 0;
    *num_ptr = 0;
    char ch = ' ';
    while (ch != '\0') 
        ch = *(str + i);
        if (ch >= '0' && ch <= '9') 
            *num_ptr = (*num_ptr) * 10 + (long)(ch - 48);
            flag = true;
        
        i++;
    
    return flag;


short process_imp(std::vector<std::string> statement) 
    auto isRegister = [](const std::string& token) 
        return (token == "AREG" || token == "BREG" || token == "CREG" || token == "DREG");
    ;

    auto find = [](std::string str, char c) 
        for (const auto& ch : str) 
            if (ch == c) 
                return true;
            
        
        return false;
    ;

    //first argument
    if (!isRegister(statement[1])) 
        if (find(statement[1], '='))    //isLiteral
            if (std::find(LITTAB.begin(), LITTAB.end(), Row(statement[1], -1)) != LITTAB.end())    //check for presence
                LITTAB.push_back(Row(statement[1], -1));
            
        
        else if (statement[1][1] == 'F')   //isNumber
            long number = 0;
            getNumber(const_cast<char*>(statement[1].c_str()), &number);
        
        else   //isVariable
            for (const auto& row : SYMTAB) 
                if (row.name == statement[1]) 
                    return 0;
                
            
            SYMTAB.push_back(Row(statement[1], -1));
            return 0;
        
    

    //second argument
    if (!isRegister(statement[2])) 
        if (find(statement[2], '='))    //isLiteral
            if (std::find(LITTAB.begin(), LITTAB.end(), Row(statement[2], -1)) != LITTAB.end())    //check for presence
                LITTAB.push_back(Row(statement[2], -1));
            
        
        else if (statement[2][1] == 'F')   //isNumber
            long number = 0;
            getNumber(const_cast<char*>(statement[2].c_str()), &number);
        
        else   //isVariable
            for (auto& row : SYMTAB) 
                if (row.name == statement[2]) 
                    return 0;
                
            
            SYMTAB.push_back(Row(statement[2], -1));
            return 0;
        
    
    return 0;


short process_drc(std::vector<std::string> statement) 
    if (statement.front() == std::string("START")) 
        if (statement.size() > 1) 
            getNumber(const_cast<char*>(statement[1].c_str()), &LOCCTR);
        
    
    else if (statement.front() == std::string("LTORG")) 
        int i = POOLTAB.back();
        for (; i < LITTAB.size(); i++) 
            LITTAB[i].LC_val = LOCCTR++;
        
        POOLTAB.push_back(LITTAB.size());
    
    else if (statement.front() == std::string("EQU")) 
        for (auto& row : SYMTAB) 
            if (row.name == statement[0]) 
                for (auto& _row : SYMTAB) 
                    if (_row.name == statement[2]) 
                        row.LC_val = _row.LC_val;
                        return 0;
                    
                
            
        
    
    else if (statement.front() == "STOP") 
        return 1;
    


short process_dcl(std::vector<std::string> statement) 
    for (auto& row : SYMTAB) 
        if (row.name == statement[0]) 
            row.LC_val = LOCCTR++;
            return 0;
        
    
    SYMTAB.push_back(Row(statement[0], LOCCTR));
    LOCCTR++;
    return 0;



int process_line(std::string line) 
    auto find = [](std::list<std::string> list, std::string str)       //could have used std::find()
        for (const auto& var : list) 
            if (std::string(var) == str) 
                return true;
            
        
        return false;
    ;

    int retVal = 0;
    std::vector<std::string> token_vec;
    while (line != "") 
        token_vec.push_back(getToken(line));
    
    //start processing the tokenised array
    auto token = token_vec.begin();
    std::string tok = token_vec.front();
    //pop the label
    if (tok[tok.size() - 1] == ':')        
        SYMTAB.push_back(Row(tok, LOCCTR));
        token_vec.pop_back();
    
    //find the type of statement
    unsigned short type = 0;
    if (std::find(Mn_imp.begin(), Mn_imp.end(), tok) != Mn_imp.end()) 
        type = 1;
    
    else if (std::find(Mn_drc.begin(), Mn_drc.end(), tok) != Mn_drc.end()) 
        type = 2;
    
    else 
        type = 3;
    
    switch (type) 

    case 1: //imperative statement
        retVal = process_imp(token_vec);
        break;

    case 2: //assembler directive
        retVal = process_drc(token_vec);
        break;

    case 3: //declarative statement
        retVal = process_dcl(token_vec);
        break;

        //default: (not needed)

    
    return retVal;


int main(int argc, const char** argv) 
    std::vector<std::string> code;
    std::ifstream infile;
    infile.open(argv[1]);
    while (!infile.eof()) 
        std::string str;
        std::getline(infile, str);
        code.push_back(str);
    
    infile.close();
    //Now we have the code in a string vector

    //check for a proper end
    if (code.back() != "STOP") 
        std::cerr << "Where do I stop?? Perhaps you forgot to put an end (STOP) statement?\n";
        return -1;
    
    //if code is proper then begin pass1
    for (int i = 0; ; i++) 
        auto line = code[i];
        short success = process_line(line);
        if (success == -1) 
            std::cerr << "Something wrong at line number " << i + 1 << std::endl;
            break;
        
        else if (success == 0) 
            //silence is golden :P
        
        else if (success == 1) 
            std::cout << "Pass1 completed successfully :)" << std::endl;
            break;
        
    
    return 0;

通过奇怪的结果,我的意思是在 stl 字符串类中重载的 operator== 似乎不起作用。问题是,我尝试编写自己的查找函数:

lambda 函数:

for(auto& item : list) 
    if (item == str)         //str was passed to this lambda function
     printf("purr"); 

即使 itemstr 相等,它也从未进入,正如调试器显示的那样

就像 std::find 一样,它总是转到 type = 3

【问题讨论】:

请比“给出奇怪的结果”更具体。您预计会发生什么,实际会发生什么? 非常注意===之间的区别。 ***.com/a/31816096/430766 @bitmask,是的,我知道。完成代码后,我通常将其替换为标题。非常感谢。这种习惯实际上源于竞争性编码。???? 我能够以某种方式摆脱写using namespace std 的烦人习惯。这个习惯也会过去:) 【参考方案1】:

您在解析时向标记添加了一个空字符:

return retToken += '\0';

这个字符在调试器中是不可见的,这意味着它看起来像是在比较 "AREG""AREG" 而实际上是在比较 "AREG""AREG\0"。 这些是不相等的;它们的长度甚至都不一样。

去掉不必要的空字符。

(可能还有其他错误,但这应该可以解决您的比较问题。)

【讨论】:

叫做debuggin:ericlippert.com/2014/03/05/how-to-debug-small-programs

以上是关于`std::find()` 用字符串产生奇怪的结果的主要内容,如果未能解决你的问题,请参考以下文章

为啥减去这两次(在 1927 年)会产生奇怪的结果?

std::find 条件语句未按预期工作

char + String 给出奇怪的结果

C++ 使用 std::find() 在数组中定位字符串时遇到问题

用std::find查找文件流中的内容

简单的字数 MapReduce 示例产生奇怪的结果