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


(Idk111) #1

 

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?


(Ryan) #2

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);

(Idk111) #3

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


(Rolek0) #4

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;

(MetaX) #5

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.


(Ryan) #6

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.


(Rolek0) #7

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:


(Drobok) #8

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


(Ryan) #9

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:


(Drobok) #10

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


(Ryan) #11

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: