[C++] String jako tabela char?

Transatlantyk
Użytkownik
Użytkownik
Posty: 52
Rejestracja: 30 cze 2014, o 15:08
Płeć: Kobieta
Lokalizacja: Ziemia

[C++] String jako tabela char?

Post autor: Transatlantyk »

Witam, mam w zasadzie tylko pytanie kontrolne, czy mogę potraktować zmienną string jako tabelę znaków char w sposób następujący

Kod: Zaznacz cały

int n;
string data="abdcef ghh";
char sign;
sign= data[n]

chodzi mi oczywiście o to, że czy w takim momencie zmienna sign przyjmie wartość np d o ile ofc n==3? i co ze znakiem pustym? jak w takim momencie zachowuje się program?


pytam ponieważ potrzebuję napisać funkcję która wczyta linijkę dowolnego tekstu w zmienną string(właśnie, czy to odpowiednia zmienna?) a następnie znak po znaku ją odczyta.

słyszałam też o zmiennej

Kod: Zaznacz cały

vector <char> data;
czy nie lepiej użyć jej i do niej wpisać daną linijkę? końcowym wynikiem jaki ma mi dać ta funkcja to ilość znaków w wierszu(również pustych) ale też zliczenie dwuznaków("cz", "sz"...)

dlatego zastanawiam się nad drugą opcją
Ostatnio zmieniony 27 sty 2017, o 21:11 przez Afish, łącznie zmieniany 1 raz.
Powód: Poprawa wiadomości.
kalwi
Użytkownik
Użytkownik
Posty: 1931
Rejestracja: 29 maja 2009, o 11:58
Płeć: Mężczyzna
Lokalizacja: Warszawa
Podziękował: 145 razy
Pomógł: 320 razy

[C++] String jako tabela char?

Post autor: kalwi »

chodzi mi oczywiście o to, że czy w takim momencie zmienna sign przyjmie wartość np d o ile ofc n==3?
Zgadza się
i co ze znakiem pustym? jak w takim momencie zachowuje się program?
Pojedyńczy znak nie potrzebuje znaku końca stringa, tj.

Kod: Zaznacz cały

sign == 'd'
zresztą jak sobie dasz

Kod: Zaznacz cały

cout << 'd';
To wyświetli się tylko ten znak.
pytam ponieważ potrzebuję napisać funkcję która wczyta linijkę dowolnego tekstu w zmienną string

Kod: Zaznacz cały

getline(string_name, input_stream);
Koniec funkcji.
a następnie znak po znaku ją odczyta.

Kod: Zaznacz cały

 for(size_t i = 0; i < string_name.size(); ++i)
        cout << string_name[i];
końcowym wynikiem jaki ma mi dać ta funkcja to ilość znaków w wierszu(również pustych)

Kod: Zaznacz cały

cout << "ilosc znakow w wierszu to " << string_name.size();
ale też zliczenie dwuznaków("cz", "sz"...)
Służy do tego funkcja find():

Kod: Zaznacz cały

http://www.cplusplus.com/reference/string/string/find/


Przestań używać chara w C++, bo to jest bez sensu. To nie jest język C i nie trzeba tu wszystkie implementować od zera, bo już jest to zrobione w bibliotekach standardowych (i jest pewność, że są tą funkcję bardzo wysokiej jakości).
Transatlantyk
Użytkownik
Użytkownik
Posty: 52
Rejestracja: 30 cze 2014, o 15:08
Płeć: Kobieta
Lokalizacja: Ziemia

[C++] String jako tabela char?

Post autor: Transatlantyk »

Ok, zorientowałeś się że nie jestem zbyt biegła w temacie, próbowałam coś skleić i wyszło mi coś niekompletnego:

Kod: Zaznacz cały

double search(string * filein)//plik oczywiście do odczytu
{
	double dw = 0;//zmienna którą zliczę wszystkie dwuznaki w tekscie
	fstream plik("filein", std::ios::in);
	string data;
	string ds;
	int found;
	int x = data.length();
	int d = x;//zmienna sumująca znaki
	int find(const char* ds, int pos = 0)const;//rozumiem że muszę jakoś zapisać tę funkcję, 
                                                                 //choć nie wiem co robi tam na końcu const
	do {
		getline(plik, data);
		d = d + x;
		found = data.find(ds);//wartość ds będę zmieniać w zależności od szukanego dwuznaku, to już jakoś sobie ogarnę
		if (found!= )//i co teraz?? znaczy że znak znaleziony czy nie i po co wcześniejsze zapisy typu'pos'??
	} while (!plik.eof());

	}
zapewne wszystko zagmatwałam, ale chyba oczywiste jest co chcę osiągnąć, więc co mam teraz zrobić żeby ten kod zrozumieć i potem obronić? ^
kalwi
Użytkownik
Użytkownik
Posty: 1931
Rejestracja: 29 maja 2009, o 11:58
Płeć: Mężczyzna
Lokalizacja: Warszawa
Podziękował: 145 razy
Pomógł: 320 razy

[C++] String jako tabela char?

Post autor: kalwi »

Nie!!! Funkcja find() już jest w bibilotece!!! Nie dajesz żadnej deklaracji czy definicji, po prostu z tego korzystasz (wywalasz 10-tą linijkę).

Poza tym

Kod: Zaznacz cały

 double dw = 0;
Po co ta zmienna jest typu double? czy ilość dwuznaków może być ułamkiem? No chyba nie

Piszesz

Kod: Zaznacz cały

 int x = data.length();
int d = x;//zmienna sumująca znaki
a potem

Kod: Zaznacz cały

    getline(plik, data);
      d = d + x;
Źle.
Dublujesz ilość znaków z pierwszego wiersza pliku.

Po prostu zmień to na

Kod: Zaznacz cały

int x = 0; int d = 0;

Kod: Zaznacz cały

d = d + x;
to można zapisać jako

Kod: Zaznacz cały

d += x;

Kod: Zaznacz cały

 found = data.find(ds);//wartość ds będę zmieniać w zależności od szukanego dwuznaku, to już jakoś sobie ogarnę
      if (found!= )//i co teraz?? znaczy że znak znaleziony czy nie i po co wcześniejsze zapisy typu'pos'??
funkcja find działa w ten sposób, że szuka znaku i jak znajdzie, to zostawia w tym miejscu znacznik (offset). Jeśli nie znajdzie, to ten znacznik zostaje na ostatniej pozycji stringa. Maksymalna długość stringa to string::npos, czyli inaczej mówiąc maksymalna wartość typu size_t. Po przeczytaniu tylu elementów przestaje dalej wyszukiwać.

Kod: Zaznacz cały

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
    size_t ilosc_dwuznakow = 0;//zmienna którą zliczę wszystkie dwuznaki w tekscie
    ifstream plik("file_in.txt");
    string data;
    string dwuznak = "rz";
    size_t znalezionaPozycja;
    size_t suma = 0;
    bool found = false;

    while(getline(plik, data))
    {
        suma += data.length();
        znalezionaPozycja = data.find(dwuznak);
        if(znalezionaPozycja == std::string::npos){
            found = false;
        }
        else
            found = true;
        if(found)
        {
            do{
                ++ilosc_dwuznakow;
                znalezionaPozycja = data.find(dwuznak, znalezionaPozycja + 1);

            }while(znalezionaPozycja != std::string::npos );
        }
    }
    cout << ilosc_dwuznakow << endl;

    return 0;
}
Tak ten kod powinien wyglądać. Przeanalizuj go sobie i spróbuj zaimplementować u siebie. Tutaj masz jak to u mnie wygląda:
Transatlantyk
Użytkownik
Użytkownik
Posty: 52
Rejestracja: 30 cze 2014, o 15:08
Płeć: Kobieta
Lokalizacja: Ziemia

[C++] String jako tabela char?

Post autor: Transatlantyk »

no dobrze, na podstawie Twojego kodu napisałam własny, powinien działać, o ile dobrze zrozumiałam, że

Kod: Zaznacz cały

znalezionaPozycja = data.find(dwuznak, znalezionaPozycja + 1);
oznacza, że kolejne wyszukiwanie rozpoczyna się od poprzedniego znalezionego dwuznaku?
a jeżeli nie to wytłumacz proszę, gdzie taka instrukcja znajduje się w Twoim kodzie lub podpowiedz jak to uzyskać. A to już mój kod:

Kod: Zaznacz cały

	fstream plik("filein", std::ios::in);
	string data, ds;
	bool found;
	int dw = 0;
	int suma = 0;
	int x;
	const int n = 21;
	string board[n] = { "ch","ck","cs","cz","dz","gh","gl","gn","ly","ng","ny","ph","qu","rz","sc","sh","sz","th","xh","zh","zs" };
	do {
		getline(plik, data);
		suma +=data.length();
		for (int i = 0; i < n; i++)
		{
			ds = board[i];
			do {
				x = data.find(ds, x++);
				if (x != string::npos)
					dw++;
			} while (x == string::npos);
		}
	} while (!plik.eof());
kalwi
Użytkownik
Użytkownik
Posty: 1931
Rejestracja: 29 maja 2009, o 11:58
Płeć: Mężczyzna
Lokalizacja: Warszawa
Podziękował: 145 razy
Pomógł: 320 razy

[C++] String jako tabela char?

Post autor: kalwi »

Transatlantyk pisze:no dobrze, na podstawie Twojego kodu napisałam własny, powinien działać
Kod piszemy w ten sposób, że po napisaniu - testujemy.
oznacza, że kolejne wyszukiwanie rozpoczyna się od poprzedniego znalezionego dwuznaku?
Prawie. Rozpoczyna się od

Kod: Zaznacz cały

 znalezionaPozycja + 1
czyli znaku dalej (no bo inaczej by się stworzyła nieskończona pętla, jakby tego +1 nie było)

No to tak, do paru rzeczy można by się przyczepić.

Kod: Zaznacz cały

string board[n]
Nie musisz tego n pisać, można po prostu dać

Kod: Zaznacz cały

string board[]={...}
i kompilator sam ustali rozmiar tablicy (bo po co to zliczać ręcznie?)

A jeszcze lepiej by to było dać w wektor, czyli

Kod: Zaznacz cały

   vector<string> board{ "ch","ck","cs","cz","dz","gh","gl","gn","ly","ng","ny","ph","qu","rz","sc","sh","sz","th","xh","zh","zs" };
A potem zamiast

Kod: Zaznacz cały

      for (int i = 0; i < n; i++)
piszesz

Kod: Zaznacz cały

      for (int i = 0; i < board.size(); i++)
Chodzi o to, że tak jest wygodniej - oraz bezpieczniej (bo co, jeśli byś tych dwuznaków miała tysiąc? Też byś je liczyła?)

Potem, napisałaś

Kod: Zaznacz cały

do {
      getline(plik, data); 
      ....
while (!plik.eof());
To jest ok. Ale równie dobrze można napisać

Kod: Zaznacz cały

    while(getline(plik, data))
Ponieważ getline po dojściu do końcu pliku również zwróci eofbit, a to jest równoważne false dla while'a. Po prostu - parę linijek kodu mniej oraz większa czytelność.

No i dobra, zobaczmy co tu się dzieje dalej.
Na początku bierzesz wiersz z pliku, wrzucasz go do data, ok.
Potem dodajesz liczbę znaków tego wiersza do suma, ok.
ds - nie mam pojęcia od czego to jest skrót. Tak samo x - zmień te nazwy na coś mówiące.
Analogicznie

Kod: Zaznacz cały

string board
słówko board oznacza po angielsku tablicę, ale taką szkolną, po której pisze się kredą. Tablica w znaczeniu jak w programowaniu to jest array

Wracając do programu, ustalasz sobie ds jako i-ty dwuznak, ok.
Natomiast cały ten kolejny do...while nie jest dobrze zrobiony. Jeśli we wczytanym wierszu by nie było szukanego dwuznaku, to otrzymasz nieskończoną pętlę. Spójrz jeszcze raz, jak to u mnie jest zrobione.
Transatlantyk
Użytkownik
Użytkownik
Posty: 52
Rejestracja: 30 cze 2014, o 15:08
Płeć: Kobieta
Lokalizacja: Ziemia

[C++] String jako tabela char?

Post autor: Transatlantyk »

ok, dzięki za rady, kad prawie gotowy, wygląda mi dobrze ale nie kompiluje się, podam go i jeden błąd i ostrzeżenie które znajduje, nie wiem czemu, bo stosowałam się do Twoich wytycznych. Mam też inne pytanie, treść polecenia, jakie miałam, brzmiało:

"Napisać plik do wyznaczania częstotliwości występowania znaków i dwuznaków w pliku o podanej
nazwie. Plik jest zapisany alfabetem łacińskim (bez znaków diakrytyzowanych). Program wczytuje nazwę pliku z linii poleceń (po przełączniku -i) i zapisuje wynik do pliku, którego nazwa jest podana po
przełączniku -o. Przykładowe wywołanie programu:
program.exe -o wyjscie -i wejscie"

Oczywiście program ma być odporny na błędy i(!) kolejność nazw plików wpisywanych przez użtkownika ma być dowolna. Czy przez to mam rozumieć, że użytkownik ręcznie wpisuje również przełączniki? bo w takim wypadku nie wiem jak takie coś w ogóle stworzyć w kodzie. Jak możesz, wytłumacz na czym polega takie wywoływanie z lini poleceń

a tu mój kod i wypluwane przez kompilator uwagi:

Kod: Zaznacz cały

void search(string  filein, string & fileout)
{
	fstream plik1("filein", std::ios::in);
	string data, ds;
	int dw = 0;
	int suma = 0;
	int wherefound;
	vector <string> array = { "ch","ck","cs","cz","dz","gh","gl","gn","ly","ng","ny","ph","qu","rz","sc","sh","sz","th","xh","zh","zs" };
	while (getline(plik1,data)) 
	{
		getline(plik1, data);
		suma +=data.length();
		for (int i = 0; i < array.size(); i++)
		{
			
			ds = array[i];
			while(data.find(ds)==string::npos)
			{
				wherefound = data.find(ds, wherefound ++);
				if (wherefound != string::npos)
					dw++;
			}
		}
	} 
	plik1.close();
	fstream plik2("fileout", std::ios::out);
	plik2 << "W pliku wystapilo " << dw << " dwuznakow, natomiast " << suma << " znakow.";
	plik2.close();
	}

Kod: Zaznacz cały


Warning	C4018	'<': signed/unsigned mismatch	//chodzi o drugi warunek '<' w pętli if(){}	

Error	C4700	uninitialized local variable 'wherefound' used	//wiadomo czego dot błą, ale dlaczego występuje??

kalwi
Użytkownik
Użytkownik
Posty: 1931
Rejestracja: 29 maja 2009, o 11:58
Płeć: Mężczyzna
Lokalizacja: Warszawa
Podziękował: 145 razy
Pomógł: 320 razy

[C++] String jako tabela char?

Post autor: kalwi »

Oczywiście program ma być odporny na błędy i(!) kolejność nazw plików wpisywanych przez użtkownika ma być dowolna. Czy przez to mam rozumieć, że użytkownik ręcznie wpisuje również przełączniki? bo w takim wypadku nie wiem jak takie coś w ogóle stworzyć w kodzie. Jak możesz, wytłumacz na czym polega takie wywoływanie z lini poleceń
Już to tłumaczyłem.
413474.htm#p5458236
A tu nawet masz gotowiec
413474.htm#p5462255
//wiadomo czego dot błą, ale dlaczego występuje??

Kod: Zaznacz cały

 wherefound = data.find(ds, wherefound ++);
bo najpierw użyje wartości wherefound po prawej stronie, dopiero potem ją przypisze

Kod: Zaznacz cały

Warning   C4018   '<': signed/unsigned mismatch   //chodzi o drugi warunek '<' w pętli if(){}   
nie wiem czego to dotyczy, ja tu nie widzę żadnego "drugiego warunku"

i abstrahując od tego, ten kod nadal nie jest poprawny.

Kod: Zaznacz cały

         while(data.find(ds)==string::npos)
Ta linijka nie ma sensu
Transatlantyk
Użytkownik
Użytkownik
Posty: 52
Rejestracja: 30 cze 2014, o 15:08
Płeć: Kobieta
Lokalizacja: Ziemia

[C++] String jako tabela char?

Post autor: Transatlantyk »

Już sobie z tym błędem poradziła, faktycznie ta linijka jest bez sensu bo mam pętle nieskończoną. program już napisałam, więc temat zamknięty, dziękuję za bezcenne rady (;
ODPOWIEDZ