Ć
wiczenia 15 maja 2012
TABLICE TEKSTOWE
Podobnie jak liczby można wczytać jeden znak, a co z całym wyrazem? Ciąg znaków alfanumerycznych
(string, po polsku łańcuch), to znaki kolejno zapisane w pamięci. Najlepiej do zapisania użyć tablicy
przechowującej znaki (typ char). Kończymy zawsze znakiem specjalnym NULL (‘\0’)
Przykład
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
char ciag_znak[ 10 ] = { 'I', 'N', 'F', 'o ', '-', ' ',
'C', '+', '+', '\0' };
char wyraz[ 50 ];
cout << "Podaj swoj tekst: ";
cin >> wyraz;
cout << "Wprowadziles nastepujace znaki: \"" << wyraz
<< "\"" << endl;
cout << "Natomiast poprawny ciag znakow wyglada tak: \""
<< ciag_znak
<< "\"" << endl;
system("PAUSE");
return EXIT_SUCCESS;
}
Jeśli wprowadzamy tekst o długości n znaków, to znak n+1 będzie zawsze równy 0. Dla większości funkcji,
które operują na łańcuchach znaków, jest to informacja, aby zakończyć wyświetlanie kolejnych znaków z
tablicy, czyli tak oznaczamy koniec tekstu.
char niepoprawana_tablicaZnakow[ 5 ] = { 'i', 'n', 'f ', '', 'C' };
nie posiada znaku NULL, dlatego nie przechowuje łańcucha znaków.
Przykład
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
char ciag_znak[ 40 ];
char tekst[ 20 ] = "uczymy sie C++ ";
cout << "Podaj swoje imie i nazwisko programisto:) "
<< endl;
cin >> ciag_znak;
cout << "Nazywasz sie: " << ciag_znak
<< endl;
system("PAUSE");
return EXIT_SUCCESS;
}
Wczytaliśmy łańcuch za pomocą strumienia cin. Warto zauważyć, że wczytuje on znaki do zmiennej, aż do
napotkania białego znaku (spacja, tabulator, enter,…). Powyżej napisaliśmy dwa wyrazy oddzielone spacją i
drugi nie został wczytany. Pamiętajmy również, iż zmiana jakiegokolwiek znaku w łańcuchu na znak
zerowy, będzie oznaczało jego skrócenie.
OPERACJE NA ŁAŃCUCHACH
Porównywanie łańcuchów znaków
Do porównywania dwóch ciągów znaków należy użyć funkcji strcmp zadeklarowanej w pliku
nagłówkowym string. Jako argument przyjmuje ona dwa napisy i zwraca wartość ujemną, jeżeli napis
pierwszy jest mniejszy od drugiego, 0 jeżeli napisy są równe lub wartość dodatnią jeżeli napis pierwszy jest
większy od drugiego. Ciągi znaków porównywane są na bazie kodów znaków, czyli np. (dla ASCII) "a" jest
mniejsze od "b", ale jest większe od "B".
Czasami możemy chcieć porównać tylko fragment napisu, np. sprawdzić czy zaczyna się od jakiegoś
konkretnego ciągu znaków. W takich sytuacjach pomocna jest funkcja strncmp. W porównaniu do strcmp()
przyjmuje ona jeszcze jeden argument oznaczający maksymalną liczbę znaków do porównania
Kopiowanie napisów
Do kopiowania ciągów znaków służy funkcja strcpy, która kopiuje drugi napis w miejsce pierwszego (w
pierwszym łańcuchu musi być wystarczająco dużo miejsca).
char napis[100];
strcpy(napis, "Ala ma kota.");
Znacznie bezpieczniej jest używać funkcji strncpy, która kopiuje co najwyżej tyle bajtów, ile podano jako
trzeci parametr. Uwaga! Jeżeli drugi napis jest za długi funkcja nie kopiuje znaku null na koniec pierwszego
napisu, dlatego zawsze trzeba to robić ręcznie:
char napis[100] = {'\0'};
strncpy(napis, "Ala ma kota.", sizeof(napis) - 1);
napis[strlen(napis)]= '\0';
Łączenie napisów
Do łączenia napisów służy funkcja strcat, która kopiuje drugi napis do pierwszego. Ponownie jak w
przypadku strcpy musimy zagwarantować, by w pierwszym łańcuchu było wystarczająco dużo miejsca.
char napis1[80] = "hello ";
const const char *napis2 = "world";
strcat(napis1, napis2);
I ponownie jak w przypadku strcpy istnieje funkcja strncat, która skopiuje co najwyżej tyle bajtów ile
podano jako trzeci argument i dodatkowo dopisze znak null. Przykładowo powyższy kod bezpieczniej
zapisać jako:
char napis1[80] = "hello ";
const char *napis2 = "world";
strncat(napis1, napis2, sizeof napis1 - 1);
TABLICE WIELOWYMIAROWE
Do tej pory operowaliśmy na tablicach jedno wymiarowych, przyjrzyjmy się jak tworzy i stosuje tablice
wielowymiarowe. Załóżmy, że chcemy napisać program, która będzie przechowywać określone dane w
macierzy
Przykład
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
const short LICZBA_Wierszy = 6;
const short LICZBA_kolumn = 8;
int i, j;
using namespace std;
char tab1[ LICZBA_Wierszy ][ LICZBA_kolumn ] = {
{ '4', '1', '1', '2', '3', '2', '5', '3' },
{ '3', '1', '1', '3', '9', '9', '7', '3' },
{ '3', '5', '3', '2', '1', '8' , '2', '1'},
{ '8', '1', '1', '4', '3', '3', '2', '1' },
{ '4', '1', '1', '2', '1', '3', '2', '1' },
{ '4', '3', '3', '2', '1', '2', '1', '9' },
};
cout<<" element z ktorego wiersza chcesz wyswietlic? ";
cin>>i;
cout<<" element z ktorej kolumny chcesz wyswietlic? ";
cin>>j;
cout<<" element do wyswietlenia to " << tab1[i][j]<<"\n";
system("PAUSE");
return EXIT_SUCCESS;
}
Zadanie 8.4.
Napisz program
,
który dla tablicy dwuwymiarowej policzy sumę elementów oraz element maksymalny.
Zadanie 9.1
Napisz program, korzystając z tablicy dwuwymiarowej, z tabliczką mnożenia do 100.
Zadanie 9.2
Napisz program (korzystając z tablicy dwuwymiarowej), który dla wczytanego z klawiatury ciągu liczb
całkowitych wypisze sumę cyfr każdej z tych liczb.
PSEUDOLOSOWE LICZBY CAŁKOWITE
Generowanie losowe liczb całkowitych.
Funkcja losująca liczby całkowite pochodzi ze standardowej biblioteki języka C. Bibliotekę, którą należy
dołączyć jest cstdlib.
Funkcja losująca po prostu losuje liczbę całkowitą, która mieści się w przedziale od 0 do RAND MAX (jest
to stała, która zależy od kompilatora i załączonych bibliotek).
Przykład
#include <iostream>
#include <cstdlib>
int main()
{
cout << "losowanie pierwsze: " << rand() << endl;
int liczba = rand();
cout << "losowanie drugie: " << liczba << endl;
liczba = rand();
cout << "losowanie trzecie: " << liczba << endl;
return 0;
}
Konfiguracja maszyny losującej
Jeżeli uruchomimy kilka razy powyższy program to zauważymy, że komputer wylosował nam za każdym
razem te same liczby. Takie zachowanie oczywiście nie jest pożądane, dlatego też wymagane jest
skonfigurowanie generatora liczb losowych.
srand( time( NULL ) );
Powyższą linijkę wystarczy wywołać tylko raz na samym początku programu, kod wygląda teraz tak:
#include <iostream>
#include <cstdlib>
#include <ctime>
int main()
{
srand( time( NULL ) );
cout << "losowanie pierwsze: " << rand() << endl;
int liczba = rand();
cout << "losowanie drugie: " << liczba << endl;
liczba = rand();
cout << "losowanie trzecie: " << liczba << :endl;
return 0;
}
Jeżeli potrzebujemy zmienić zakres to wykorzystać musimy działanie modulo i dodawanie. Najpierw
ustalamy ile liczb mieści się w przedziale z którego chcemy losować, np. 50 liczb. Następnie ustalamy
pierwszą losowaną liczbę np. 7.
int wylosowana_liczba =( rand() % ile_liczb_w_przedziale ) + startowa_liczba;
a dokładnie:
int wylosowana_liczba =( rand() % 50 ) + 7;
Albo dla liczb z dowolnego przedziału <a,b> wypełnimy nimi tablicę: T[i] = a + rand() % (b - a + 1)
Ostatecznie program losujący liczby z przedziału od 7 do 56 będzie więc wyglądał tak:
#include <iostream>
#include <cstdlib>
#include <ctime>
int main()
{
srand( time( NULL ) );
cout << "losowanie pierwsze: " <<(( rand() % 50 ) + 7 ) << endl;
int liczba =( rand() % 50 ) + 7;
cout << "losowanie drugie: " << liczba << endl;
liczba =( rand() % 50 ) + 7;
cout << "losowanie trzecie: " << liczba << endl;
return 0;
}
Zadanie 9.3
Napisz program, który wylosuje pewną ilość liczb (wartość wczytana z klawiatury) z określonego przedziału
(wartości początku i końca przedziału wczytane z klawiatury).
Zadanie 9.4. (domowe)
Napisać grę, która ma działać następująco: 1. Program losuje liczbę z przedziału od 1 do 1000.
2. Użytkownik zgaduje liczbę, która została wylosowana.
3. Jeżeli podana liczba jest za duża (za mała) gra wypisuje stosowny komunikat i powraca do kroku 2.
4. Jeżeli gracz trafi liczbę wylosowaną to pogram kończy działanie, wypisując na ekran wylosowaną liczbę
oraz liczbę 'strzałów', które oddał gracz.
Gra ma być zabezpieczona przed możliwością wprowadzenia błędnych wartości liczbowych.