Biblioteka obiektowa C++ klasa string
Transkrypt
Biblioteka obiektowa C++ klasa string
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. 1 #include <i o s t r e a m > 2 #include <s t r i n g > // b i b l o t e k a j e z y k a C++ n i e m y l i c z 3 // z b i b l i o t e k a lancuchow znakowych j e z y k a C 4 using namespace s t d ; 5 6 int main ( ) { 7 8 s t r i n g imie , nazwisko ; // d e k l a r a c j a o b i e k t o w z k l a s y s t r i n g 9 // sa p u s t e i c h d l u g o s c =0; 10 s t r i n g s ; // t e z p u s t a d e k l a r a c j a . Zeby z o b a c z y c d l u g o s c 11 // t a k i e g o l a n c u c h a k o r z y s t a m y z metody l e n g t h ( ) 12 13 cout<<endl <<" uruchamiamy metode length (), tj. podaj dlugosc " ; 14 15 cout<<i m i e . l e n g t h ()<< e n d l ; // wydrukowana z o s t a n i e d l u g o s c l a n c u c h=0 16 // bo j e s t p u s t y 17 18 cout<<" Podaj swoje imie"<<e n d l ; 19 c i n >>i m i e ; // t u t a j z o s t a n i e o b i e k t o w i i m i e p r z y p i s a n a w a r t o s c 20 cout<<" Wpisales imie: "<<imie <<e n d l ; 21 22 cout<<" dlugosc lancucha imie="<<i m i e . l e n g t h ()<< e n d l ; 23 24 cout<<" Podaj swoje nazwisko "<<e n d l ; 25 26 27 28 29 c i n >>nazwisko ; // t u t a j z o s t a n i e o b i e k t o w i i m i e p r z y p i s a n a w a r t o s c 30 31 s=i m i e+nazwisko ; // o b i e k t y t y p u s t r i n g mozna dodawac 32 33 cout<<" ---------------------------------------------"<<e n d l ; 34 cout<<" Dzien dobry "<<s<<e n d l ; 35 cout<<" ---------------------------------------------"<<e n d l ; 36 37 // Nie w y g l a d a t o j e s z c z e d o b r z e d l a t e g o 38 // t e r a z wstawimy s p a c j e pomiedzy i m i e i n a z w i s k o i a na koncu dodamy b u z k e 39 2 40 41 42 43 44 45 46 s=i m i e + " " + nazwisko + " :)" ; cout<<" Dzien dobry "<<s<<e n d l ; return 0 ; } Łańcuchy możemy prównywać ze sobą analogicznie jak zmienne numeryczne. Świadczy o tym poniższy przykład string2.cc. 1 #include <i o s t r e a m > 2 #include <s t r i n g > 3 4 using namespace s t d ; 5 6 int main ( ) { 7 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 : " ; 13 14 c i n >>wyraz1>>wyraz2 ; 15 16 i f ( wyraz1 != wyraz2 ) { 17 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 ; 23 } 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 string3.cc. 1 #include <i o s t r e a m > 2 #include <s t r i n g > 3 4 using namespace s t d ; 5 6 int main ( ) { 7 8 s t r i n g Wyraz ; // d e k l a r a c j a o b i e k t o w , k o r e sa lancuchami 9 // sa p u s t e i c h d l u g o s c =0; 10 11 12 cout<<" Teraz wpisz jakis wyraz "<<e n d l ; 13 c i n >>Wyraz ; // t u t a j z o s t a n i e o b i e k t o w i Wyraz p r z y p i s a n a w a r t o s c 14 15 int d l u g o s c=Wyraz . l e n g t h ( ) ; 16 17 cout<<" Dlugosc wpisanego tekstu wynosi "<<d l u g o s c <<e n d l ; 18 19 3 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 char znak=Wyraz [ 0 ] ; // p i e r w s z y znak w p i s a n e g o t e k s t u cout<<" Pierwszy wpisany znak Twojego tekstu to: "<<znak<<e n d l ; znak=Wyraz [ d l u g o s c − 1 ] ; cout<<" Ostatni znak Twojego teksu to: "<<znak<<e n d l ; cout<<endl <<endl <<"A teraz wypiszemy wszystkie znaki w Twoim tekscie "<<e n d l ; f o r ( int i =0; i <d l u g o s c ; i ++){ cout<<i <<"\t"<<Wyraz [ i ]<< e n d l ; } cout<<" ******************** "<<e n d l ; cout<<" Wpisz dlugi wyraz zawierajacy slowo aku"<<e n d l ; s t r i n g inny ; c i n >>inny ; // t e r a z zapytamy o numer znaku w ktorym z n a j d u j e s i e p o s z u k i w a n y // l a n c u c h znakowy np . s l o w o aku //W tym c e l u uruchamiamy metode f i n d ( ) int numer=inny . f i n d ( "aku" ) ; cout<<" lancuch znakow aku znajduje sie na "<<numer<<" miejscu "<<e n d l ; cout<<"w wyrazie :"<<e n d l ; cout<<inny<<e n d l ; return 0 ; } 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. 1 #include <i o s t r e a m > 2 #include <s t r i n g > 3 4 using namespace s t d ; 5 6 int main ( ) { 7 8 9 s t r i n g z d a n i e ; // p r z y p i s z e m y mu l i t e r a l znakowy 10 //w p r z y p a d k u podania w a r t o s c i p o p r z e z l i t e r a l l a n c u c h znakowy 11 // moze z a w i e r a c s p a c j e 12 13 z d a n i e="Ma powstac tekst byle dlugi lub krotki " ; 14 cout<<z d a n i e <<e n d l ; 15 cout<<" --------------------------------------------------"<<e n d l ; 16 cout<<" Znajdziemy w tym zdaniu slowo dlugi i zamienimy slowem jaki"<<e n d l ; 17 18 s t r i n g Z n a l e z i o n e Z n a k i ( " dlugi " ) ; 19 s t r i n g NoweZnaki ( "jaki " ) ; // dajemy j e d n a 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 z a s t e p o w a n y c h znakow s l o w a d l u g i 4 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 // bedziemy p r z e g l a d a c l a n c u c h z d a n i e od p o z y c j i 0 // i s z u k a c s l o w a ” d l u g i ” int n = z d a n i e . f i n d ( Z n a l e z i o n e Z n a k i , 0 ) ; // zmienna n p o d a j e p o l o z e n i e // p o j a w i s i e pewna l i c z b a c a l k o w i t a cout<<s t r i n g : : npos<<e n d l ; // Sprawdzamy c z y s l o w o d l u g i z o s t a l o z n a l e z i o n e // i j e s l i t a k t o z s t e p u j e m y nowymi znakami i f ( n != s t r i n g : : npos ) { z d a n i e . r e p l a c e ( n , NoweZnaki . s i z e ( ) , NoweZnaki ) ; } // wydruk z d a n i a cout<<z d a n i e <<e n d l ; return 0 ; } Poniżej jest źródło string5.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. 1 #include <i o s t r e a m > 2 #include <s t r i n g > 3 #include <v e c t o r > // k l a s a kontenerowa 4 // do k o n t e n e r a mozna w k l a d a c o b i e k t y dowolnych k l a s 5 // 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 u m i e s z c z a c 6 // t y l k o o b i e k t y k l a s y s t r i n g 7 8 using namespace s t d ; 9 10 int main ( ) { 11 12 // bedziemy s k l a d a c wyrazy z d a n i a w k o n t e n e r z e z d a n i e 13 14 v e c t o r <s t r i n g > z d a n i e ; // a l o k a c j a k o n t e n e r a z d a n i e 15 // do k o n t e n e r a 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 ; 17 cout<<" Wpisz zdanie zakonczone przez nacisniecie klawisza ENTER "<<e n d l ; 18 while ( c i n >>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 z d a n i e . push back ( wyraz ) ; // metoda p u s h b a c k ( ) s l u z y do w k l a d a n i a 20 i f ( c i n . peek()==’\n’ ) break ; // o b i e k t o w do k o n t e n e r a 21 } 22 23 cout<<" Napisane zostalo zdanie : " ; 24 25 f o r ( int i =0; i <z d a n i e . s i z e ( ) ; i ++){ 26 cout<<z d a n i e [ i ]<<" " ; 27 } 28 cout<<e n d l ; 29 30 31 return 0 ; 32 } 5 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 k o n t e n e r z e 3 4 #include <i o s t r e a m > 5 #include <v e c t o r > // k o n t e n e r v e c t o r 6 #include <c s t d l i b > 7 8 using namespace s t d ; 9 10 c l a s s Czlowiek { // d e f i n i u j e m y k l a s e C z l o w i e k 11 private : 12 int wiek ; 13 double waga ; 14 public : 15 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 17 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 ; } 23 } ; 24 25 26 int main ( ) { 27 28 typedef s t d : : v e c t o r <Czlowiek∗> Rodzina ; // s k l a d n i a d l a d e f i n i c j i 29 // k o n t e n e r a Rodzina 30 Rodzina Kowalscy ; // p u s t y k o n t e n e r Kowalscy 31 Rodzina Wojewodzki ; // p u s t y k o n t e n e r Wojewodzki 32 33 // r o d z i n a K o w a l s k i c h − 3 o s o b y 34 35 f o r ( int n=0;n<3;n++){ 36 Kowalscy . push back (new Czlowiek ) ; // w k l a d a n i e o b i e k t o w do k o n t e n e r a 37 } 38 39 // r o d z i n a Wojewodzki − 2 o s o b y 40 41 Wojewodzki . push back (new Czlowiek ( 3 5 ) ) ; 42 Wojewodzki . push back (new Czlowiek ( 7 0 ) ) ; 43 44 double waga ; 45 46 f o r ( int n=0;n<Kowalscy . s i z e ( ) ; n++){ // l o s o w e p r z y p i s a n i e wagi 47 waga=random ( ) / ( 1 . 0 +RAND MAX) ∗ 1 0 0 . 0 ; 48 Kowalscy [ n]−>WpiszWage ( waga ) ; 49 } 50 51 f o r ( int n=0;n<Wojewodzki . s i z e ( ) ; n++){ 52 waga=random ( ) / ( 1 . 0 +RAND MAX) ∗ 1 0 0 . 0 ; 53 Wojewodzki [ n]−>WpiszWage ( waga ) ; 54 } 6 55 56 57 58 59 60 61 62 63 cout<<" Rodzina Kowalscy :"<<e n d l ; f o r ( int n=0;n<Kowalscy . s i z e ( ) ; n++){ cout<<Kowalscy [ n]−>PodajWage()<<" kg"<<e n d l ; } return 0 ; } 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 k o p i o w a n i a b i n a r n e g o p l i k u na inny p l i k b i n a r n y 2 3 #include <i o s t r e a m > 4 #include <f s t r e a m > 5 6 using namespace s t d ; 7 8 main ( int argc , char ∗∗ argv ) 9 { 10 i f ( a r g c !=3){ 11 cout<<" Poprawny format polecenia : "<<e n d l ; 12 cout<<argv [0]<<" nazwa_pliku_do_skopiowania nazwa_nowego_pliku "<<e n d l ; 13 return 1 ; 14 } 15 16 s t r i n g l i n i a ; 17 f s t r e a m WE,WY; 18 19 // k o p i o w a n i e b i n a r n e ma dodatkowo i o s : : b i n a r y 20 //Do k o p i o w a n i a t e k s t u w y s t a r c z y l o b y WE. open ( a r g v [ 1 ] , i o s : : i n ) d l a c z y t a n i a z p l i k u 21 // i WY. open ( a r g v [ 2 ] , i o s : : o u t ) do z a p i s u do p l i k u 22 23 WE. open ( argv [ 1 ] , i o s : : i n | i o s : : b i n a r y ) ; 24 WY. open ( argv [ 2 ] , i o s : : out | i o s : : b i n a r y ) ; 25 26 i f (WE. good ( ) == f a l s e | | WY. good ( ) == f a l s e ) { 27 c o u t << "Nie moge otworzyc jednego z plikow " << e n d l ; 28 return ( 1 ) ; 29 } 30 31 32 33 while ( 1 ) { 34 35 g e t l i n e (WE, l i n i a ) ; 36 i f (WE. e o f ( ) ) break ; 37 38 WY<<l i n i a <<e n d l ; 39 40 } 41 42 43 return 0 ; 7 44 } 8