Program przestaje działać - odczyt z pliku tekstowego

0

Hej, w trakcie wykonywania program zawiesza się.
Z zasady działania miał pobrać dane z pliku, zapisać je w pamięci i wyświetlić pogrupowane. Samo wyświetlanie działa i tam problemu raczej nie ma co szukać, bo wcześniejsze zadanie bez odczytu z pliku przekopiowałem i działało więc na 90% chodzi o odczyt z pliku. I tutaj nie jestem pewien czy dobrze rozumiem w jaki sposób jest to odczytywane (moje wątpliwości dodałem w zakomentowaniu)

Ogólnie plik tekstowy wygląda tak

5
Marta Jakas
2000
Los Cos
6000
NieJa
12000
Pieskulawanoga
123456
Plugawy Janek
98765

A kod programu

#include <fstream>
#include <iostream>
#include <cstdlib>
#include <cstring>

using namespace std;
int ilu_daroczyncow;
struct sponsor
{
string nazwisko;
double wplata;
};
string znaki;
int nr = 1;
int nr_struktury = 0;


int main()
{
    fstream plik;
    plik.open("daroczyncy.txt", ios::in);
    if (!plik.is_open())
    {
        cout << "Nie odnaleziono pliku. Zamykam program";
        exit(EXIT_FAILURE);
    }
    getline(plik, znaki); // pobieram pierwsza linie
    znaki = ilu_daroczyncow;
    sponsor * sponsorzy = new sponsor[ilu_daroczyncow];
    while (getline(plik, znaki)) // tutaj rozumiem pobiera od lini 2giej już? Bo nie wiem czy na zlym typie danych sie nie wyklada
    {
        switch(nr)
        {
            case 1: sponsorzy[nr_struktury].nazwisko = znaki;
                break;

            case 2: sponsorzy[nr_struktury].wplata = atoi(znaki.c_str());
                break;
        }
        nr++;
        if (nr == 3)
        {
            nr = 1;
            nr_struktury++;
        }
    }
    int bogaci = 0;
    cout << "\n\n\nNASI WSPANIALI SPONSORZY!!!\n\n";
    for (int i=0; i < ilu_daroczyncow; i++)
    {
        if (sponsorzy[i].wplata >= 10000)
        {
            cout << sponsorzy[i].nazwisko << " " << sponsorzy[i].wplata << endl;
            bogaci++;
        }
    }
    if (bogaci == 0)
        cout << "brak";
    cout << endl << endl << endl;
    cout << "Nasi sponsorzy\n\n";
    int biedni = 0;
      for (int i=0; i < ilu_daroczyncow; i++)
    {
        if (sponsorzy[i].wplata <= 10000)
        {
            cout << sponsorzy[i].nazwisko << " " << sponsorzy[i].wplata << endl;
            biedni++;
        }
    }
    if (biedni == 0)
        cout << "brak" << endl;
    delete[] sponsorzy;
    plik.close();
    return 0;
}

2

Przypuszczam, ze program się zawiesza, bo nie wychodzi z pętli while.

Funkcja getLine nie zwraca true/false

istream& getline (istream& is, string& str);

Użyłabym konstrukcji:

while(!plik.eof())
0

Dalej to samo :(
Właściwie wydaje mi się, że zapis który zastosowałem też jest poprawny ( dopóki pobiera linię wykonuje się, jak nie ma co pobrać to koniec pętli)

2
    getline(plik, znaki); // pobieram pierwsza linie
    znaki = ilu_daroczyncow;
    sponsor * sponsorzy = new sponsor[ilu_daroczyncow];

To nie ma sensu.

Poza tym: pozbądź się zmiennych globalnych i nie używaj nagiego new ( https://dsp.krzaq.cc/post/176/ucze-sie-cxx-kiedy-uzywac-new-i-delete/ )

1

Funkcja getLine nie zwraca true/false

Stan strumienia jest konwertowany na true, false, więc zapis z pętlą while jest poprawny.

edit:

getline(plik, znaki); // pobieram pierwsza linie
    znaki = ilu_daroczyncow;
    sponsor * sponsorzy = new sponsor[ilu_daroczyncow];

Jeśli w pierwszej linii pobierasz liczbę, to pobierz ją operatorem >> z pliku do zmiennej liczbowej,
lub musisz przekonwertować pobrany string na liczbę, aby poprawnie użyć jej jako wartości dla rozmiaru alokowanej tablicy.

...i

    znaki = ilu_daroczyncow;

byłoby przypisaniem w niewłaściwą stronę, bo to znaki ma jakąś wartość,
a ilu_darczyncow ma wartość 0.
Zmienne globalne też są złym wyborem dla tego ćwiczenia.
Warto kod podzielić na funkcje.

0

Dzięki za informacje! Już widzę też błąd. Biorę się za dalsze działanie i zapoznawanie z linkiem.

1
szarotka napisał(a):

Przypuszczam, ze program się zawiesza, bo nie wychodzi z pętli while.

Funkcja getLine nie zwraca true/false

istream& getline (istream& is, string& str);

Użyłabym konstrukcji:

while(!plik.eof())

@szarotka: To Twoja konstrukcja jest błędna, jeśli po danych są jakiekolwiek białe znaki... SeekEof w Pascalu załatwiało to, ale eof (i w C++, i w Pascalu) tego nie bierze pod uwagę. A konstrukcje

while(getline(plik, x))
while(plik >> x >> y >> z)

są jak najbardziej w porządku, bo istream (a także ostream) konwertuje się na bool w kontekstach logicznych (jak while czy if).

0
YooSy napisał(a):

Zmienne globalne też są złym wyborem dla tego ćwiczenia.

Zmienne globalne są zawsze złym wyborem. :)

0

Do rozdzielania biednych i bogatych sponsorów możesz użyć std::partition

  auto middle = std::partition( std::begin( sponsorzy ), std::end( sponsorzy ), [](const auto& value){ return value.wplata <= 10000; } );

  // wypisanie biedoty
  for( auto iter = std::begin( sponsorzy ); iter != middle; ++iter ) {
    std::cout << iter->nazwisko << " " << iter->wplata << "\n";
  }

  // wypisanie bogaczy
  for( auto iter = middle; iter != std::end( sponsorzy ); ++iter ) {
    std::cout << iter->nazwisko << " " << iter->wplata << "\n";
  }

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