AoC 2018 – nie rozumiem dlaczego "data.eof() == false" jest koniecznością

0
#include <iostream>
#include <fstream>

int main()
{
    std::fstream data;
    data.open("input.txt", std::ios::in); {
        int freq = 0;
        int num = 0;

        while (data.eof() == false)
        {
                data >> num;

            if (data.eof() == false) 
            {
                std::cout << freq << " " << num << " = ";

                freq += num;
                std::cout << freq << std::endl;
            }
        } 

    } data.close();

    std::cin.get();
    return 0;
}

Nie rozumiem dlaczegoif (data.eof() == false) jest koniecznością.
Przy wczytaniu końcowej liczby ustawia się eofbit albo failbit więc dlaczego po ponownym wczytaniu eof dodaje tą samą liczbę do końca?

1

A dlaczego nie tak?

while(data >> num) {
}
0

Poczytaj o RAII. Obiekt pliku w trakcie tworzenia może otrzymać plik a poprzez użycie std::ifstream, otwierasz go do wprowadzania danych. W trakcie niszczenia obiekt pliku, sam zamyka plik.

#include <iostream>
#include <fstream>

int main()
{
    {
        std::ifstream data("input.txt");
        // TODO: Sprawdzenie czy powiodło się otwarcie
        int freq = 0;
        int num = 0;

        while (data >> num)
        {
            std::cout << freq << " " << num << " = "; 
            freq += num;
            std::cout << freq << std::endl;
        } 
    }

    std::cin.get();
    return 0;
}

Poza tym lepiej pokazywać docelowe intencje działania programu ale rozumiem że ćwiczysz.

2

Czemu to nie działa: while (data.eof() == false)
Powodów jest kilka:

  1. Trywialny: na końcu pliku masz białe znaki. operator>> czyta ostatnią liczbę, zostają jeszcze białe znaki, idzie następna iteracja, operator>> czyta te białe znaki i napotyka koniec pliku, a nie wczytał żadnej liczby. Gdyby twój plik nie zawierał na końcu białych znaków, to ostatnia wywołanie operator>> czyta sekwencje cyfr, aż do napotkania czegoś co nie jest cyfrą, więc operator ten spróbuje czytać poza końcem pliku i flaga się ustawi.
  2. Średni: Flaga eof nie jest informacją o osiągnięciu końca pliku, ale o próbie czytania poza końcem strumienia. dowód podczas czytania znak po znaku
  3. Zaawansowany: czemu eof tak działa? Bo jest pewna klasa strumieni, których rozmiar nie jest znany. Czasami mimo, że osiągnięto koniec strumienia, to nie wiadomo, że to będzie jego koniec jeszcze przez jakiś czas. Przykładowo źródłem danych może być: inny proces, inny komputer, skaner.
0

No dobra, teraz jest kolejny problem. Bardzo podobny ale odwrotny.
Nie wczytuję danych w taki sposób data >> num a za pomocą getline(istream& is, string& str);

#include <iostream>
#include <fstream>
#include <array>
#include <vector>
#include <string>
#include <sstream>

struct rectangle
{
    std::size_t id;
    std::size_t posX, posY;
    std::size_t width, height;
};

std::string prepareData(std::string& str)
{
    //effect of this function:

    //#2 @ 153,186: 20x26
    //prepareData()
    // 2   153 186  20 26
    //id, posX, posY, width, height

    for (auto itr = str.begin(); itr != str.end(); itr++)
    {
        if (*itr == '#')
            *itr = ' ';

        else if (*itr == ',')
            *itr = ' ';

        else if (*itr == '@')
            *itr = ' ';

        else if (*itr == ':')
            *itr = ' ';

        else if (*itr == 'x')
            *itr = ' ';
    }
    return str;
}

int main()
{
    std::size_t x, y; //area size

    std::vector<rectangle> Rects;

    std::ifstream file("input.txt");
    if (file.is_open())
    {                                   
        rectangle rect;
        std::string buf;
        int num;

        while (!file.eof())
        {
            //get line of rect info
            getline(file, buf);

            //prepare data
            buf = prepareData(buf);

            // loading rect info to string stream
            std::stringstream sstream(buf);

            // getting id
            sstream >> buf;
            rect.id = std::stoi(buf);

            //getting posX and posY
            sstream >> buf;
            rect.posX = std::stoi(buf);
            sstream >> buf;
            rect.posY = std::stoi(buf);

            //getting width and height
            sstream >> buf;
            rect.width = std::stoi(buf);
            sstream >> buf;
            rect.height = std::stoi(buf);

            //Adding rectangle to data base
            Rects.push_back(rect);

            if (rect.id == 1399)
                break;
        }

        file.close();
    }
    else { std::cerr << "Error opening file!" << std::endl; }

    //std::array<std::array<std::size_t, x>, y>;

    for (auto &p : Rects)
        std::cout << "ID#" << p.id << " pos: " << p.posX << "," << p.posY << " dims: " << p.width << "x" << p.height << std::endl;

    std::cin.get();
}

No i nie wiem jak sprawić, żeby pętla zatrzymała się w odpowiednim momencie. Getlinie nie zwraca bool :/
Zjechałem na sam koniec pliku i sprawdziłem końcową wartość, rzuciłem taki warunek i działa ale no ten...

            if (rect.id == 1399)
                break;

I czy takie podejście odczytywania danych jest poprawne ? Zmieniam dane tak, żeby były wygodne dla mnie.

1
while(getline(file, buf)) {
    // ...
}
1

https://stackoverflow.com/que[...]hats-wrong-with-cplusplus-com

https://en.cppreference.com/w/cpp/string/basic_string/getline

Co do drugiego pytania: jak to upraszcza parsowanie i wiesz co robisz to czemu nie. Choć w tym zadaniu, jak i każdym innym, rozwiązania ekstrahujące dane za pomocą regexów wydają się czytelniejsze.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0