Typy danych przeznaczone do obsługi znaków i tekstów:
char pojedynczy znak, np. char a = ’k’;
stały znak umieszczamy w pojedynczych apostrofach
string łańcuch znaków, np. string b = ”kot”;
stały łańcuch umieszczamy w podwójnych apostrofachJak wczytać daną typu string:
ze standardowego wejścia | ze strumienia wejściowego cin |
---|---|
char Z[100]; // pomocnicza tablica znaków Z string s; scanf("%s",Z); s=Z; |
string s; cin >> s; |
String nie jest tym samym co tablica znaków char[]. String jest obiektem. Ma inną organizację danych w pamięci.
Ma wbudowane różne funkcje, które ułatwiają życie programistom, np. length() zwraca liczbę znaków w obiekcie:
string s = ”placki”;
int n = s.length(); // n będzie równe 6
Znaki w stringu są poindeksowane (ponumerowane) począwszy od 0.
Można odwołać się do pojedynczego znaku w stringu, podając nazwę stringa i indeks znaku w nawiasach kwadratowych, np. s[3] zwróci literę ‘c’.
Kod programu z zajęć:
#include <iostream>
#include <algorithm> // potrzebny do sortowania i permutacji
using namespace std;
int main() {
string s;
cout<<"daj slowo ";
cout<<s<<endl;
int n = s.length();
cout<<"liczba znakow w slowie = " << n << endl;
cout<<endl;
cout<<"przeliterujmy: ";
for (int i=0; i<n; i++) {
cout<<s[i];
if (i<n-1) cout<<"-";
}
cout<<endl;
cout<<"odwrocmy kolejnosc znakow: ";
for (int i=n-1; i>=0; i--) cout<<s[i];
cout<<endl;
cout<<"zobaczmy jak slowo "<<s<<" 'wyglada' w pamieci komputera: ";
for (int i=0; i<n; i++)
cout << (int)s[i] << " ";
cout<<endl;
cout<<"\nzamienmy wszystkie znaki na wielkie litery: ";
for (int i=0; i<n; i++)
s[i] = toupper(s[i]);
cout<<s<<endl;
cout<<"posortujmy litery w porzadku alfabetycznym: ";
sort(s.begin(), s.end()); // wymaga #include <algorithm>
cout << s << endl;
cout<<"wyswietlmy i zliczmy wszystkie anagramy Twojego slowa: \n";
int licznik = 0;
do {
licznik ++;
cout << licznik << "\t" << s << endl;
} while (next_permutation(s.begin(),s.end())); // wymaga #include <algorithm>
cout<<endl;
return 0;
}
Przykładowe działanie programu:
Zastosowaliśmy w programie funkcje:
toupper() – Pobiera znak jako parametr. Jeśli ten zank jest małą literą, to zwraca odpowiadającą mu wielką literę, w przeciwnym razie zwraca nie zmieniony znak.
Istnieje też funkcja tolower() która zamienia wielkie litery na małe.
sort – Sortuje elementy w porządku rosnącym.
Pobiera dwa parametry: adres pierwszego elementu i adres za ostatnim elementemnext_permutation – jeśli jest możliwe wykonanie następnej permutacji w porządku alfabetycznym, to ją wykonuje (przestawiając elementy w podanym obiekcie) i zwraca wartość true, w przeciwnym razie zwraca wartość false.
Pobiera dwa parametry: adres pierwszego elementu i adres za ostatnim elementem.
Więcej informacji o przetwarzaniu łańcuchów znaków – na następnej stronie.
Kodowanie znaków
ASCII - American Standard Code for Information Interchange – jest to standard zapisu znaków w 7-bitowym kodzie. Liczbom z zakresu 0-127 przyporządkowano jednoznacznie: litery alfabetu angielskiego, cyfry, znaki przestankowe i inne symbole oraz polecenia sterujące, np.: 65 - A, 32 – spacja, 8 - backspace.
Ósmy bit jest różnie wykorzystywany w różnych stronach kodowych. Kodom od 128 do 255 odpowiadają znaki semigraficzne: cieniowanie ░ ▒ ▓ █, ramki ╩ ▀ ▄ ┌ ┐└ ┘ oraz znaki specjalne języka, np. ąęść.
Unicode - sposób kodowania znaków przy użyciu 16-bitówych. Na razie nie będziemy tego używać w programach.
Domyślnie aplikacja konsoli Windows używa strony kodowej 852, zaś DEV, Notatnik itp używają strony kodowej 1250
C - Łańcuchy zakończone znakiem o kodzie 0
W języku C teksty można przechowywać jako tablice znaków.
Kolejne znaki łańcucha zapisane są jako kody ASCII w kolejnych bajtach pamięci, każdy znak na jednym bajcie.
Długość łańcucha można odczytać funkcją strlen(łańcuch). Zwraca ona liczbę znaków w łańcuchu.
Jednak kiedy sprawdzisz funkcją sizeof() ile bajtów zajmuje łańcuch, wynik będzie o 1 większy niż liczba znaków. Dlaczego?
Koniec łańcucha jest sygnalizowany dodatkowym bajtem o kodzie 0. A więc w rzeczywistości łańcuch zajmie o 1 bajt pamięci więcej niż to wskazuje funkcja strlen().
char imie [] = "Kazik";
cout<<imie<<" ma znakow "<<strlen(imie)<<" i zajmuje bajtow"<<sizeof(imie)<<endl;
// wyświetli kolejne kody ASCII, na końcu '\0'
for (int i=0; i<sizeof(imie);i++) cout<<(int)imie[i]<<" ";
cout<<endl;
Można zadeklarować rozmiar tablicy znakowej.
Wówczas jednak przypisywany tekst będzie musiał mieć dokładnie tyle znaków ile zadeklarowano.
Jeżeli tekst ma mniej znaków, to nie można go wprost przypisać do tablicy. Trzeba go skopiować funkcją strcpy(tablica,"tekst")
char nazwisko [20];
// nazwisko = "Staszewski"; // będzie błąd kompilacji, bo tekst ma mniej niż 20 znaków
strcpy(nazwisko,"Staszewski");
cout<<imie<<" "<<nazwisko<<endl;
A jeśli tekst ma więcej znaków nić zadeklarowano? Funkcja strcpy posłusznie skopiuje cały tekst do pamięci, wpisując nadmiarowe znaki do kolejnych bajtów, nie zarezerwowanych już dla tekstu, bez żadnego ostrzeżenia. Jeśli były tam jakieś ważne dane, to już ich nie ma!
C++ - Stringi
W języku C++ można oczywiście używać tablic znakowych zakończonych kodem '\0'.
Ale jest zdefiniowana klasa string, która bardzo ułatwia życie programistom. W obiektach klasy string jest lepsza kontrola pamięci i są wbudowane dodatkowe funkcje, które pozwalają na łatwą manipulację znakami łańcucha.
Do funkcji obiektu można odwołać się przy pomocy notacji kropki: nazwaObiektu.nazwaFunkcji(parametry)
string s = "Hello World"; // przykład deklaracji i inicjacji obiektu klasy string
s[i] // i-ty znak łańcucha s
s.length(); // zwraca liczbę znaków w łańcuchu
s.find(char lub string, int odIndeksu) // wyszukuje znak lub tekst począwszy od podanego indeks,
// zwraca indeks znalezionego, lub -1 jeśli nie ma
s.substr(odIndeksu, int ileZnaków) // zwraca podłańcuch
s.insert(odIndeksu, string t) // wstawia t w miejsce określone podanym indeksem
s.erase(odIndeksu, ileZnaków) // usuwa znaki
s.replace(odIndeksu, ileZnaków, string t) // zastepuje podany zakres znaków łańcuchem t
s.append(string t)