POLITECHNIKA WARSZAWSKA Instytut Automatyki i Robotyki ZASADY PROGRAMOWANIA KOMPUTERÓW ZAP zima 2015 Język programowania: Środowisko programistyczne: C/C++ Qt Wykład 4 : Napisy. Tablice dwuwymiarowe. Formaty wydruku.
Instrukcja SWITCH (1) 2 inaczej: Instrukcja wielokrotnego wyboru switch (ksztalt) { case serce : na_niebiesko; break; case trojkat : na_zielono; break; case ksiezyc : na_czerwono; break; default: na_zolto; }
Instrukcja SWITCH (2) 3 Ogólna postać instrukcji: switch (selektor) { case stała: case stała:... instrukcja; instrukcja;... break; case stała: case stała:... instrukcja; instrukcja;... break;... case stała: case stała:... instrukcja; instrukcja;... break; default: instrukcja; instrukcja;... } można pominąć break - instrukcja przerywająca działanie instrukcji switch. Instrukcja ta nie jest konieczna jeśli jej nie będzie, wykonanie switch przejdzie do następnego przypadku (co może być niekiedy przydatne).
Instrukcja SWITCH (3) 4 Selektor może być wyrażeniem jednego z typów porządkowych (przeliczalnych), tzn. może być typu int, char, a nawet bool, ale nie może być typu rzeczywistego ani typu string. Każda z pozycji stała może być: stałą (np. 5, true czy 'a'), typu takiego samego jak selektor lub umożliwiającego jednoznaczne rzutowanie typów wyrażeniem stałym, dającym się policzyć na etapie kompilacji. char zn; cin>>zn; switch (zn) { Instrukcja switch jest mniej uniwersalna niż if-else, bo nie obsługuje zakresów (od do ) ani selektorów rzeczywistych. case a : cout << male a ; break; case ( : case ) : cout << nawiasy okragle ; break; case [ : case ] : cout << nawiasy kwadratowe ; break; case { : case } : cout << nawiasy klamrowe ; break; default: cout << inny znak ; }
Operacje na napisach (łańcuchach) 5 Do znaków w łańcuchu odwołujemy się jak do elementów tablicy jednowymiarowej, poprzez indeksy, zaczynając od 0. Rozmiar łańcucha, czyli liczbę jego znaków można wyznaczyć za pomocą funkcji size( ). UWAGA: funkcja ta nie ma parametrów (wnętrze nawiasów jest puste). Łańcuchy można ze sobą łączyć za pomocą operatora + 0 1 2 3 4 W I T E K imie[0]... imie[1] imie.size( ) jest tu równe 5 imie[4] string imie = "WITEK"; string mama ("ASIA"); dwa sposoby inicjowania napisów cout << imie[0]; // drukuje pierwszy znak napisu cout << imie [imie.size( )-1]; // drukuje ostatni znak napisu cout << imie + ".cpp " // wyświetli się "WITEK.cpp"
Tablice dwuwymiarowe 6 Definicja TABLICY typ_elementów nazwa_tablicy [ilosc_wierszy] [ilosc_kolumn] ; lub: typ_elementów nazwa_tablicy [ilosc_wierszy] [ilosc_kolumn] = {...,...,...,,...}; // inicjalizacja tablicy wartości początkowe Wartości początkowe w przypadku inicjalizacji tablicy wstawiane są do kolejnych wierszy tablicy. Przykłady: const int N=4, W=5, K=7; // tak można zdefiniować kilka stałych char zn [W] [K]; // tablica o nazwie zn i W wierszach oraz K // kolumnach int a[n] [N]= { 12,9,47,48,17,8,39,8,48,46,18,20,8,18,3,21 }; // tablica kwadratowa o N wierszach i N kolumnach // - zobacz obok efekt tej inicjalizacji kolumny Uwaga: wiersze i kolumny tablic dwuwymiarowych też numerowane są (indeksowane) od zera. wiersze
Tablice dwuwymiarowe - wczytywanie 7 Przykład wczytywania danych do tablicy - wierszami const int W=4, K=4; int a[w][k]; // definicja tablicy a...... for (int i = 0; i < W; i++) // dla każdego wiersza i tablicy for (int j = 0; j < K; j++) // przejdź przez wszystkie kolumny j cin >> a[i] [j] // wczytaj element o indeksach i, j...
Tablice kwadratowe 8 UWAGA: po przekątnych (a także po pojedynczych wierszach i kolumnach) poruszamy się w pętli pojedynczej (!). Przykład: Zerujemy elementy głównej przekątnej: Zerujemy elementy drugiej przekątnej: for (int i = 0; i < N; i++) a[i][i] =0; for (int i = 0; i < N; i++) a[i][n-1-i] =0;
Tablica kwadratowa wypełnianie nad główną przekątną 9 Pod i nad przekątnymi poruszamy się w pętli podwójnej, w której zmienna sterująca pętli wewnętrznej zmienia się w sposób zależny od wartości zmiennej sterującej pętli zewnętrznej (j jest zależne od i). Przykład: elementy nad główną przekątną należy wypełnić kolejnymi liczbami naturalnymi, poczynając od 1 i poruszając się wierszami.
Tablica kwadratowa wypełnianie po ukosie 10 Tablicę wypełnić kolejnymi liczbami naturalnymi, poczynając od 1 i poruszając się wzdłuż kolejnych linii ukośnych o numerach od 1 do 7 (jak zaznaczone kółeczkami na rysunku). p = 1; for (k=n-1; k>=0; k--) for (i=0; i<n-k; i++) a[i][i+k] = p++; for (k= 1; k<n; k++) for (i=k; i<n; i++) a[i][i-k] = p++;
Generowanie liczb losowych 11 Jest przydatne do szybkiego wypełniania tablic: rand ( ) - funkcja standardowa bez parametrów, z biblioteki cstdlib, generuje liczbę losową całkowitą o rozkładzie jednostajnym z przedziału <0, RAND_MAX>, gdzie RAND_MAX typu int jest stałą (równą 32767) Jak używać funkcji rand( ): #include <cstdlib> // biblioteka zawierająca funkcje rand, srand i stałą RAND_MAX #include <ctime> // biblioteka zawierająca funkcję time... // instrukcja srand inicjuje generator liczb losowych wartością przypadkową, // otrzymaną z zegara systemowego funkcją time (jest to tzw. zarodek liczb losowych) // dzięki temu za każdym razem program losuje inne liczby: srand (time(0)); cout << rand( ); // generuje liczbę losową całkowitą z przedziału <0, RAND_MAX> cout << rand( ) / double(rand_max); // generuje liczbę losową double z przedziału <0, 1> cout << a+(b-a)*rand( ) / double(rand_max); // generuje liczbę losową double z przedziału <a, b> // Prościej jest użyć funkcji modulo, choć nie zapewnia to rozkładu w pełni jednostajnego: cout << rand( )%100; // generuje liczbę losową całkowitą z przedziału <0, 99> cout << a+ rand( )%(b+1-a); // generuje liczbę losową całkowitą z przedziału <a,b> cout << rand( )%101/100.0; // generuje liczbę losową double z przedziału <0,1> z rozdzielcz. 2 miejsc cout << a+ (b-a)*rand( )%1001/1000.0; // generuje liczbę losową double (3 m-ca) z przedziału <a,b>
Formaty wydruku 12 Instrukcja zapisywania (drukowania) - przypomnienie cout << wyrażenie_1 << wyrażenie_2 <<... wyrażenie_n Każde zapisywane wyrażenie może być jednego z następujących typów: liczbowy (int, double,...) char string bool (drukuje się jako 0 lub 1) Standardowo liczby rzeczywiste drukowane są z dokładnością 6 cyfr znaczących w tzw. formacie ogólnym. Jeżeli liczba nie daje się zapisać z taką ilością cyfr, drukowana jest w postaci wykładniczej. Format wydruku można zmienić za pomocą tzw. standardowych manipulatorów, po dołączeniu pliku nagłówkowego <iomanip>, na jeden z następujących formatów: format stały (fixed) - w postaci naturalnej, z kropką dziesiętną: cout << fixed; // manipulator fixed ustawia format stały format naukowy (scientific) - w postaci wykładniczej, z literą e: cout << scientific; // ustawia format naukowy
Precyzja i szerokość pola wydruku 13 1. Precyzję wyświetlania liczb ustawia się następująco: cout << setprecision(2); Co oznacza precyzja? dla formatu ogólnego - maksymalną liczbę cyfr dla formatu stałego i naukowego - liczbę cyfr po kropce 2. Szerokość pola wydruku ustawia się następująco (dla najbliższej drukowanej wartości, potem powrót do szerokości domyślnej): cout << setw(5); Domyślna szerokość pola wydruku jest równa zeru, co oznacza, że drukowana wartość zajmie minimalną potrzebną szerokość na wydruku. Przykład: cout << fixed << setprecision(3); cout << setw(10) << "suma= " << setw(5) << suma; lub: cout << fixed << setprecision(2) << setw(8) << suma; UWAGA: Możliwe jest też używanie - zamiast powyższych manipulatorów - funkcji fixed, precision, width, co nie wymaga dołączania <iomanip>, ale jest mniej wygodne i mniej uniwersalne, zwłaszcza w przypadku wydruku w kolumnach.
Wydruk wyników w kolumnach 14 Aby uzyskać wydruk liczb, znaków czy napisów w ładnych, równych kolumnach (o jakiejś szerokości w) i z wymaganą precyzją d miejsc po kropce dziesiętnej (dla liczb), najlepiej jest dołączyć bibliotekę <iomanip> i używać manipulatorów w sposób następujący: a) przed drukowaniem czegokolwiek ustawić stały format wydruku za pomocą manipulatora fixed (tzn. w postaci naturalnej, z kropką dziesiętną) oraz precyzję wydruku, czyli liczbę miejsc po kropce, używając manipulatora setprecision, w sposób następujący: cout << fixed << setprecision (d); gdzie wartość d (liczba cyfr po kropce) może być konkretną liczbą, stałą, zmienną, a nawet wyrażeniem. b) w pętli zawierającej instrukcję drukowania - przed każdym wyprowadzeniem jakiejś wartości podać za pomocą manipulatora setw, jaką szerokość w (tu może być stała, zmienna, wyrażenie) ma ta drukowana wartość zająć, np.: cout << setw(6) << x << setw(6) << y << endl; albo: cout << setw(8) << x[i][j]; Precyzję wydruku też można ustawiać tak jak szerokość wydruku - w pętli, do każdej drukowanej wartości inną. UWAGA: zamiast ustawiać szerokość wydruku, można też zastosować (jak dotąd) znak tabulacji '\t' lub ''\t'' po każdej drukowanej wartości, ale wyrównanie kolumn jest wtedy gorsze.