fscanf一个人在第一行就卡住了

fscanf stucks on the first line alone

本文关键字:一行 一个人 fscanf      更新时间:2023-10-16

我在这里做一个入门级词汇分析器。我的代码是

 bool DfaTab :: isAccepted(string s){
        FILE *fp1;
        int i;
        fp1 = fopen("javalist.dat","r");
        while(!(feof(fp1))){
            fscanf(fp1,"%s%d%[^n]",tkname.c_str(),&tkval);
            if(strcmp(s.c_str(),tkname.c_str()) == 0){
                setTkVal(tkval);
                setTkName(tkname.c_str());
                state = true;
                return state;
                break;
            }
            else{
                //What should I do here to skip to next line
            }
        }
        return state;
        fclose(fp1);
    }

从这里开始调用:

while (!(feof(src))) {
        fscanf(src,"%s[^t^ ^n]",sym.c_str());
        if (d.isAccepted(sym)) {
            fprintf(des,"<%s, %d>n",d.getTkName().c_str(),d.getTkVal());
        }
        else{
            cout << "Can not find symbol " << d.getTkName().c_str();
            cout << "Rejected.n";
            break;
        }
    }

我的问题是,isAccepted()函数中的fscanf()函数不会跳到新行,并重复打印在执行的剩余部分打印开始时读取的第一行。我现在该怎么办?

该文件包含:

//javalist.dat
    boolean     0
    brake       1
    case        2
    catch       3
    const       4
    continue    5
    default     6
    ....

在对文件执行读取操作之前调用feof是不正确的。您可能应该将代码重组为这样:

// some reasonble max size
char buf[1024];
// read in a line
while(fgets(buf, sizeof(buf), fp1)) {
    // parse the contents of that line
    sscanf(buf, ...); //
    // the rest of your code...
}

此外,您的代码中有一个严重的错误。

fscanf(fp1,"%s%d%[^n]",tkname.c_str(),&tkval);

tkname.c_str()的结果是NOT一个可写字符串,它是一个const char *。您可能不会将其传递给要写入的fscanf,这是未定义的行为,很容易导致崩溃。相反,您需要分配一个新的缓冲区,读取该缓冲区,然后将其分配给字符串。

或者,您可以使用iostreams来解决这个简单得多的问题:

bool DfaTab :: isAccepted(string s){
    std::ifstream file("javalist.dat");
    std::string line;
    std::string name;
    int val;
    // read a line
    while(std::getline(file, line)) {
        // get the data out of the line
        std::stringstream ss(line);
        if(ss >> name >> val) {
            if(name == s) {
                setTkVal(val);
                setTkNamename.c_str()); // if this method takes a std::string, no need for the .c_str()
                state = true;
                return state;
            } else{
                // just ignore this line and it'll continue
            }
        } else {
            // an invalid line, handle as you please...
        }
    }    
    return state;
}

请注意,这个解决方案实际上总体上更简单。