programowanie w C++ dla OWK Biblioteka obiektowa C++ klasa string - parę przykładów programów Opracowanie: dr hab. Mirosław R. Dudek, prof. UZ 1
Streszczenie W tym rozdziale podamy kilka najprostszych przykładów programów korzystających z biblioteki obiektowej string w C++. Często programiści C++, którzy wcześniej przez długie lata programowali w języku C z przyzwyczajenia ograniczają się do klasy string.h rodem z języka C (w programach C++ włącza się ją poprzez polecenie #include <cstring>) unikając biblioteki obiektowej. Niepotrzebnie. W poniższych przykładach skorzystamy dodatkowo z klasy kontenerowej vector. Wybrane przykłady Na wstępie rozważmy program string1.cc który nie wymaga dłuższego tłumaczenia. Komentarze w źródle kodu powinny wystarczyć. Z kodu można zrozumieć w jaki sposób obiektom z klasy string przypisać łańcuchy znakowe, jak dodawać do siebie obiekty klasy string. Przede wszystkim uderzająca jest prostota tych poleceń, są bardziej proste niż przy korzystaniu z pomocy biblioteki cstring wymagającej dodatkowej wiedzy nt tablic typu znakowego. 2 #include <s t r i n g > // b i b l o t e k a j e z y k a C++ nie mylic z // z b i b l i o t e k a lancuchow znakowych j e z y k a C 4 using namespace std ; 6 int main ( ) { 8 s t r i n g imie, nazwisko ; // d e k l a r a c j a obiektow z k l a s y s t r i n g 9 // sa p uste i c h d l u g o s c =0; 10 s t r i n g s ; // t e z pusta d e k l a r a c j a. Zeby zobaczyc d l u g o s c 11 // t a k i e g o lancucha korzystamy z metody l e n g t h ( ) 12 1 cout<<endl<<" uruchamiamy metode length(), tj. podaj dlugosc" ; 14 1 cout<<imie. l e n g t h ()<<endl ; //wydrukowana z o s t a n i e d l u g o s c lancuch=0 16 // bo j e s t pusty 1 18 cout<<" Podaj swoje imie"<<e n d l ; 19 cin>>imie ; // t u t a j z o s t a n i e o b i e k t o w i imie przypisana wartosc 20 cout<<" Wpisales imie: "<<imie<<e n d l ; 21 22 cout<<"dlugosc lancucha imie="<<imie. length()<<endl ; 2 24 cout<<" Podaj swoje nazwisko"<<e n d l ; 2 26 2 28 29 cin>>nazwisko ; // t u t a j z o s t a n i e o b i e k t o w i imie przypisana wartosc 0 1 s=imie+nazwisko ; // o b i e k t y typu s t r i n g mozna dodawac 2 cout<<"---------------------------------------------"<<endl ; 4 cout<<" Dzien dobry "<<s<<e n d l ; cout<<"---------------------------------------------"<<endl ; 6 // Nie wyglada to j e s z c z e dobrze d l a t e g o 8 // t e r a z wstawimy s p a c j e pomiedzy imie i nazwisko i a na koncu dodamy buzke 9 2
40 s=imie + " " + nazwisko + " :)" ; 41 42 cout<<" Dzien dobry "<<s<<e n d l ; 4 44 4 return 0 ; 46 } Łańcuchy możemy prównywać ze sobą analogicznie jak zmienne numeryczne. Świadczy o tym poniższy przykład string2.cc. 2 #include <s t r i n g > 4 using namespace std ; 6 int main ( ) { 8 cout<<" Porownujemy obiekty typu string"<<e n d l ; 9 10 s t r i n g wyraz1, wyraz2 ; 11 12 cout<<" Wpisz dwa wyrazy: " ; 1 14 c i n >>wyraz1>>wyraz2 ; 1 16 i f ( wyraz1!=wyraz2 ){ 1 cout<<" Wyrazy nie sa te same"<<e n d l ; 18 i f ( wyraz1>wyraz2 ) cout<<wyraz1<<" jest wiekszy niz "<<wyraz2<<e n d l ; 19 e l s e cout<<wyraz1<<" jest mniejszy "<<wyraz2<<e n d l ; 20 } 21 e l s e cout<<wyraz1<<" = "<<wyraz2<<e n d l ; 22 return 0 ; 2 } Rozważymy teraz trochę trudniejszy przykład, w którym pokażemy jak z wprowadzonego łańcucha znakowego można wydrukować każdy znak niezależnie i jak podmienić grupę znaków innymi znakami. W tym celu rozważmy program string.cc. 2 #include <s t r i n g > 4 using namespace std ; 6 int main ( ) { 8 s t r i n g Wyraz ; // d e k l a r a c j a obiektow, kore sa lancuchami 9 // sa p uste i c h d l u g o s c =0; 10 11 12 cout<<" Teraz wpisz jakis wyraz"<<e n d l ; 1 cin>>wyraz ; // t u t a j z o s t a n i e o b i e k t o w i Wyraz przypisana wartosc 14 1 int dlugosc=wyraz. l e n g t h ( ) ; 16 1 cout<<"dlugosc wpisanego tekstu wynosi "<<dlugosc <<endl ; 18 19
20 21 char znak=wyraz [ 0 ] ; // p i e r w s z y znak wpisanego t e k s t u 22 2 cout<<" Pierwszy wpisany znak Twojego tekstu to: "<<znak<<e n d l ; 24 2 znak=wyraz [ dlugosc 1]; 26 cout<<" Ostatni znak Twojego teksu to: "<<znak<<e n d l ; 2 28 29 cout<<endl<<endl<<"a teraz wypiszemy wszystkie znaki w Twoim tekscie"<<e n d l ; 0 1 for ( int i =0; i<dlugosc ; i ++){ 2 cout<<i <<"\t"<<wyraz [ i ]<<endl ; 4 } 6 cout<<"********************"<<endl ; cout<<" Wpisz dlugi wyraz zawierajacy slowo aku"<<e n d l ; 8 s t r i n g inny ; 9 cin>>inny ; 40 41 // t e r a z zapytamy o numer znaku w ktorym z n a j d u j e s i e poszukiwany 42 // lancuch znakowy np. slowo aku 4 //W tym c e l u uruchamiamy metode f i n d ( ) 44 4 int numer=inny. f i n d ( "aku" ) ; 46 4 cout<<" lancuch znakow aku znajduje sie na "<<numer<<" miejscu"<<e n d l ; 48 cout<<"w wyrazie :"<<e n d l ; 49 cout<<inny<<endl ; 0 return 0 ; 1 } Zauważmy że nasz wyraz (łańcuch znakowy) musi być politycznie poprawny tzn. nie może zawierać spacji. Wszystko psuje się. W kolejnym przykładzie zobaczymy że jednak możemy włączyć spacje w przypadku gdzy obiektowi z klasy string przypisujemy literał znakowy. 2 #include <s t r i n g > 4 using namespace std ; 6 int main ( ) { 8 9 s t r i n g zdanie ; // przypiszemy mu l i t e r a l znakowy 10 //w przypadku podania w a r t o s c i poprzez l i t e r a l lancuch znakowy 11 //moze zawierac s p a c j e 12 1 z d a n i e=" Ma powstac tekst byle dlugi lub krotki" ; 14 cout<<zdanie<<endl ; 1 cout<<"--------------------------------------------------"<<endl ; 16 cout<<" Znajdziemy w tym zdaniu slowo dlugi i zamienimy slowem jaki"<<e n d l ; 1 18 s t r i n g ZnalezioneZnaki ( "dlugi" ) ; 19 s t r i n g NoweZnaki ( "jaki " ) ; // dajemy jedna s p a c j e w i e c e j aby 20 // i c h b y l o t y l e i l e zastepowanych znakow slowa d l u g i 4
21 22 // bedziemy p r z e g l a d a c lancuch zdanie od p o z y c j i 0 2 // i szukac slowa d l u g i 24 2 int n = zdanie. f i n d ( ZnalezioneZnaki, 0 ) ; // zmienna n podaje p o l o z e n i e 26 2 // pojawi s i e pewna l i c z b a c a l k o w i t a 28 cout<<s t r i n g : : npos<<endl ; 29 0 //Sprawdzamy czy slowo d l u g i z o s t a l o z n a l e z i o n e 1 // i j e s l i tak to zstepujemy nowymi znakami 2 i f ( n!= s t r i n g : : npos ){ zdanie. r e p l a c e (n, NoweZnaki. s i z e ( ), NoweZnaki ) ; 4 } 6 // wydruk zdania cout<<zdanie<<endl ; 8 return 0 ; 9 } Poniżej jest źródło string.cc w którym wykorzystujemy kontenerową klasę vector do której będziemy wrzucać obiekty klasy string. Komentarze w źródle tego programu pozwolą korzystać ze składni klasy kontenerowej bez wstępnego jej omówienia. 2 #include <s t r i n g > #include <vector > // k l a s a kontenerowa 4 //do kontenera mozna wkladac o b i e k t y dowolnych k l a s // a l e w tym p r z y k l a d z i e bedziemy w k o n t e r n e r z e umieszczac 6 // t y l k o o b i e k t y k l a s y s t r i n g 8 using namespace std ; 9 10 int main ( ) { 11 12 // bedziemy s k l a d a c wyrazy zdania w kontenerze zdanie 1 14 vector <s t r i n g > zdanie ; // a l o k a c j a kontenera zdanie 1 //do kontenera wrzucamy wyrazy o d d z i e l o n e s p a c j a 16 s t r i n g wyraz ; 1 cout<<" Wpisz zdanie zakonczone przez nacisniecie klawisza ENTER"<<e n d l ; 18 while ( cin>>wyraz ){ // s p a c j e o d d z i e l a j a p o s z c z e g o l n e wyrazy 19 zdanie. push back ( wyraz ) ; //metoda push back ( ) s l u z y do wkladania 20 i f ( c i n. peek()== \n ) break ; // obiektow do kontenera 21 } 22 2 cout<<" Napisane zostalo zdanie: " ; 24 2 for ( int i =0; i <zdanie. s i z e ( ) ; i ++){ 26 cout<<zdanie [ i ]<<" " ; 2 } 28 cout<<endl ; 29 0 1 return 0 ; 2 }
Dla części młodego pokolenia programistów kontenery będą wygodniejsze niż stosowanie tablic. To że nie jest to trudne widać z kolejnego przykładu kontener1.cc. 1 // z d e f i n i u j e m y wlasna k l a s e 2 // k t o r e j o b i e k t y umiescimy w kontenerze 4 #include <iostream> #include <vector > // kontener v e c t o r 6 #include <c s t d l i b > 8 using namespace std ; 9 10 class Czlowiek { // d e f i n i u j e m y k l a s e Czlowiek 11 private : 12 int wiek ; 1 double waga ; 14 public : 1 Czlowiek (){} // k o n s t r u k t o r bezparametrowy 16 Czlowiek ( int w){ wiek=w; } // k o n s t r u k t o r z parametrem 1 18 void WpiszWiek ( int a ){ wiek=a ; } 19 int PodajWiek ( ) { return wiek ; } 20 21 void WpiszWage ( double w){ waga=w; } 22 double PodajWage ( ) { return waga ; } 2 } ; 24 2 26 int main ( ) { 2 28 typedef std : : vector <Czlowiek > Rodzina ; // s k l a d n i a d l a d e f i n i c j i 29 // kontenera Rodzina 0 Rodzina Kowalscy ; // pusty kontener Kowalscy 1 Rodzina Wojewodzki ; // pusty kontener Wojewodzki 2 // rodzina Kowalskich osoby 4 for ( int n=0;n<;n++){ 6 Kowalscy. push back (new Czlowiek ) ; // wkladanie obiektow do kontenera } 8 9 // rodzina Wojewodzki 2 osoby 40 41 Wojewodzki. push back (new Czlowiek ( ) ) ; 42 Wojewodzki. push back (new Czlowiek ( 0 ) ) ; 4 44 double waga ; 4 46 for ( int n=0;n<kowalscy. s i z e ( ) ; n++){ // losowe p r z y p i s a n i e wagi 4 waga=random ()/(1.0+RAND MAX) 1 0 0. 0 ; 48 Kowalscy [ n] >WpiszWage ( waga ) ; 49 } 0 1 for ( int n=0;n<wojewodzki. s i z e ( ) ; n++){ 2 waga=random ()/(1.0+RAND MAX) 1 0 0. 0 ; Wojewodzki [ n] >WpiszWage ( waga ) ; 4 } 6
cout<<" Rodzina Kowalscy:"<<e n d l ; 6 for ( int n=0;n<kowalscy. s i z e ( ) ; n++){ cout<<kowalscy [ n] >PodajWage()<<" kg"<<e n d l ; 8 } 9 60 61 62 return 0 ; 6 } Biblioteke string można też wykorzystać do kopiowania łańcuchów znakowych z pliku do innego pliku. Mozliwości te widać z kolejnego przykładu gdzie nie martwimy sie już wielkością strumienia wejściowego bo o wszystko dba biblioteka string. 1 // Inny p r z y k l a d kopiowania binarnego p l i k u na inny p l i k binarny 2 #include <iostream> 4 #include <fstream> 6 using namespace std ; 8 main ( int argc, char argv ) 9 { 10 i f ( argc!=){ 11 cout<<" Poprawny format polecenia: "<<e n d l ; 12 cout<<argv [0] <<" nazwa_pliku_do_skopiowania nazwa_nowego_pliku"<<e n d l ; 1 return 1 ; 14 } 1 16 s t r i n g l i n i a ; 1 fstream WE,WY; 18 19 // kopiowanie binarne ma dodatkowo i o s : : binary 20 //Do kopiowania t e k s t u w y s t a r c z y l o b y WE. open ( argv [ 1 ], i o s : : in ) d l a c z y t a n i a z p l i k u 21 // i WY. open ( argv [ 2 ], i o s : : out ) do z a p i s u do p l i k u 22 2 WE. open ( argv [ 1 ], i o s : : in i o s : : binary ) ; 24 WY. open ( argv [ 2 ], i o s : : out i o s : : binary ) ; 2 26 i f (WE. good ( ) == f a l s e WY. good ( ) == f a l s e ) { 2 cout << "Nie moge otworzyc jednego z plikow" << endl ; 28 return ( 1 ) ; 29 } 0 1 2 while (1){ 4 g e t l i n e (WE, l i n i a ) ; 6 i f (WE. e o f ( ) ) break ; 8 WY<<l i n i a <<endl ; 9 40 } 41 42 4 return 0 ;
44 } 8