Поведение fstream в C ++ - PullRequest
       8

Поведение fstream в C ++

0 голосов
/ 13 ноября 2018

Я сделал следующий скрипт, который должен читать из файла:

    char match[] = "match";

    int a;
    int b;

    inp >> lin;
    while(!inp.eof()) {
        if(!strcmp(lin, match)) {
            inp >> a >> b;
            cout << a << " " << b <<endl;
        }
        inp >> lin;
    }

    inp.close();
    return num_atm;
}

Предполагается прочитать все слова, и если строка начинается с совпадения, она также должна вывести остальную часть строки.

Мой входной файл:

match 1 2 //1
match 5 2 //2
nope 3 6 //3
match 5 //4
match 1 4 //5
match 5 9 //6

Он правильно напечатает 1 2, 5 2 и пропустит 3 6. Но затем он застрянет, продолжит печатать 5 0 и продолжит печатать 5 0 навсегда. Я понимаю, что совпадение помещается в b, которое является целым числом, но я не понимаю, почему это зациклено. Разве ввод не должен прочитать совпадение 4 один раз, попытаться прочитать / записать 5 и сопоставить, а затем сделать это со строкой 4 и совпадением из строки 5? Затем он должен затем прочитать цифры 1 и 4, а затем сопоставить с номером 6.

Я бы также понял, что из-за того, что слово не помещается в целое число, оно снова будет читать совпадение в пятой строке, но это не то, что он делает.

Возвращается к совпадению в четвертой строке, которое он уже прочитал, и читает его снова. Почему это?

1 Ответ

0 голосов
/ 14 ноября 2018

Когда вы читаете с >>, концы строк обрабатываются так же, как пробелы: они просто пропускают больше пробелов. Это означает, что вы видите

match 1 2 
match 5 2 
nope 3 6 
match 5 
match 1 4 
match 5 9 

Но программа видит

match 1 2 match 5 2 nope 3 6 match 5 match 1 4 match 5 9 

Давайте перенесемся туда, куда все пойдет на юг

Содержимое потока:

nope 3 6 match 5 match 1 4 match 5 9 

Обработка

inp >> lin; // reads nope stream: 3 6 match 5 match 1 4 match 5 9 
if(!strcmp(lin, match)) { // nope != match skip body
}
inp >> lin; // reads 3 stream: 6 match 5 match 1 4 match 5 9 
if(!strcmp(lin, match)) { // 3 != match skip body
}
inp >> lin; // reads 6 stream: match 5 match 1 4 match 5 9 
if(!strcmp(lin, match)) { // 6 != match skip body
}
inp >> lin; // reads match stream: 5 match 1 4 match 5 9 
if(!strcmp(lin, match)) { // match != match Enter body
    inp >> a >> b; // reads 5 and fails to parse match into an integer.
                   // stream: match 1 4 match 5 9 
                   // stream now in failure state
    cout << a << " " << b <<endl; // prints 5 and garbage because b was not read

}
inp >> lin; // reads nothing. Stream failed
if(!strcmp(lin, match)) { // match != match Enter body
    inp >> a >> b; // reads nothing. Stream failed
                   // stream: match 1 4 match 5 9 
                   // stream now in failure state
    cout << a << " " << b <<endl; // prints g and garbage because b was not read

}

Поскольку ничего не читается, while(!inp.eof()) совершенно бесполезен. Конец файла никогда не может быть достигнут. Программа зациклится навсегда, вероятно, напечатав все, что прочитало в последний раз. Успешно прочитано.

Исправление этого зависит полностью от того, что вы хотите сделать, если у вас есть строка match без 2 цифр, но типичная структура выглядит примерно так:

std::string line;
while(std::getline(inp, line) // get a whole line. Exit if line can't be read for any reason.
{
    std::istringstream strm(line);
    std::string lin;
    if(strm >> lin && lin == match) // enters if lin was read and lin ==  match
                                    // if lin can't be read, it doesn't matter. 
                                    // strm is disposable
    {
        int a;
        int b;

        if (strm >> a >> b) // enters if both a and b were read
        {
            cout << a << " " << b <<"\n"; // endl flushes. Very expensive. just use a newline.
        }
    }
}

Вывод из этого должен быть что-то вроде

1 2 
5 2 
1 4 
5 9 

Если вы хотите использовать match 5 ... Что ж, вам решать, что вы хотите вставить в b, если в файле нет b.

...