[c++] Wczytywanie do końca linii oraz zliczanie (praca na plikach)

 

Mam do zrobienia uniwersalny program, który pracuje na macierzach - tablice dwu-wymiarowe.

Zrobiłem większość funkcjonalności i mam mały problem z wczytywaniem. Macierz może być dowolna, np 2x2:

29 5

7 0

 

Chciałem żeby użytkownik nie musiał podawał liczby kolumn i wierszy, lecz żeby program je zliczał

 mój kod wygląda następująco

 

 

fstream plik;
       plik.open("text.txt", ios::in);
       int dl;//ilosc kolumn macierzy
       int ilosc_konca=0;//ilosc wierszy
       int ilosc_bialych = 0;//białe znaki
       if (plik.good() == true) //start sprawdzania długosci wiersza 
       {
           char bufor1[1000];
           char bufor2[1000];
           int uu = 0;
           while (uu != 1000)
           {
               //pobierz znaki    
               bufor2[uu] = bufor1[1];
               bufor1[uu] = plik.get();
               
               if (bufor1[uu] == '\r'|| bufor2[uu]=='\n') //jezeli znaki sa koncem wiersza +++++++
               {
                    
                   dl = plik.tellg(); // gdzie on jest
                   cout << dl << endl; // tego nie wyswietla 
                   
                   ilosc_konca++;//zwieksz zmienna sumuje ilosc koncow znakow

               }
               if (bufor1[uu] != '\r' || bufor2[uu] == '\n')//jesli zwykly bialy znak
               {
                   ilosc_bialych++;

               }
           }
uu++;
       }
       dl = (dl - 2)- ilosc_bialych; // przetwarzanie, biorac ze na koncu lini sa dwa znaki
       plik.close();
       cout << dl << endl;//to jest bardzo duże 

 

mam  błąd w warunkach gdyż nie wchodzi mi w warunek (zaznaczyłem w kodzie +++++++). Czy dobrze rozumiem ze w windowsowym pliku txt znajdują się te dwa znaki końca?

Istnieje magiczne getline - użyj tego, zamiast implementować je ręcznie powolnym czytaniem bajt po bajcie. :wink:

 

std::ifstream plik("macierz.txt");
std::string linia;
std::getline(plik, linia);

Lecz moja tablica jest dwumiarowa i typu double… więc string nie pomoże.

Pod Windowsem koniec linii jest oznaczany dwoma znakami \r\n, ale w C++ przy odczycie w trybie tekstowym (domyślnym) sekwencja \r\n zamieniana jest na \n

Więc tablice _char_ów też nie powinny Ci pomóc :wink:

A na serio, ze stringa możesz czytać przy użyciu strumienia typu std::istringstream (nagłówek <sstream>)

std::ifstream plik("macierz.txt");
std::string linia;
std::getline(plik, linia);
//---
std::istringstream strlinia(linia);
double x;
strlinia >> x;

Otwórz plik w trybie binarnym ios::binary. Znaki końca na Win (notatnik) to zwykle \r\n (0x0D 0x0A) czyli dwa znaki.

ps. tellg liczy te znaki końca.

Pytałeś o czytanie z pliku do końca linii. Służy do tego getline (i nie rób tego ręcznie w jeszcze inny sposób, jak sugeruje MetaX).

Parsować dane z pliku i tak musisz jakoś. Możesz tak jak napisał Rolek0. Jeśli chcesz wcześniej policzyć ile Twoja macierz ma kolumn, to policz w stringu wystąpienia spacji (czy ciągów spacji, jeśli dane są wizualnie wyrównane w pliku). I/O z dysku jest wolne. I/O z dysku bajt po bajcie jest bardzo wolne. Lepiej odczytać linię raz, przelecieć dwa razy dane w pamięci (zliczanie spacji + parsowanie odpowiedniej liczby zmiennoprzecinkowych wartości) niż próbować na bieżąco parsować dane znak po znaku.

Ja bym proponował czytać kolejne liczby, aż do pierwszego niepowodzenia (metoda strumienia fail zwraca true jeśli poprzednia próba odczytu się nie powiodła) i zliczać udane odczyty.

 

Bufory systemowe powinny nas uratować :mrgreen:

Z dysku i tak trzeba czytać całymi sektorami, jeśli systemowi nie brakuje pamięci operacyjnej to zapamięta odczytany sektor (a prawdopodobnie nawet wczyta kilka następnych sektorów tego pliku) w nadziei, że pewnie będą te dane niedługo potrzebne.

Poza tym, strumienie też mają własne bufory, żeby nie wywoływać funkcji systemowych zbyt często :slight_smile:

Po co cokolwiek liczyć skoro jest vector, oraz strumienie o których pisał Rolek0  ;))

Bo autor pytania wyraźnie lubi na piechotę. :wink: A poważnie: macierz trzymana jako wektor wektorów nie brzmi szczególnie użytecznie. :slight_smile:

A różni się to czymś od wskaźnika do tablicy wskaźników, czy tam tablicy nadmiarowej ?

Zależy od dwóch rzeczy: 1. od implementacji wektorów, 2. od tego jak chcesz wykorzystywać macierz.

W pierwszym wypadku nie wydaje mi się (ale standard czytałem dawno temu), że narzucane jest wektorowi ułożenie danych w pamięci. Wektor zdefiniowany jest przez interfejsy i charakterystyki czasowe operacji (zamortyzowane lub nie). Jakieś dwa tygodnie temu widziałem kod, który zakładał że można w każdej chwili wyłuskać element zerowy wektora i potraktować wnętrzności jako tablicę. Okazało się to być prawdziwym założeniem w Linuksie z GCC, ale nie w Windowsie z MSVC.

W drugim przypadku typ macierzy i jej docelowe wykorzystanie mają znaczenie. Macierz możesz chcieć przechować wierszowo, kolumnowo, po krzywej Hilberta, jako macierz macierzy albo na kilka innych sposobów, jeśli to macierz rzadka. Każda z tych metod ma swoje zastosowania i zależy od tego, co autor chce z macierzami robić. Niewiele mi mówi “uniwersalny program do operacji na macierzach”. :wink: