1 Wstęp do informatyki- wykład 4 Deklaracja zmiennych Typy Instrukcja selekcji if-else Treści prezentowane w wykładzie zostały oparte o: S. Prata, Język C++. Szkoła programowania. Wydanie VI, Helion, 2012 www.cplusplus.com Jerzy Grębosz, Opus magnum C++11, Helion, 2017 B. Stroustrup, Język C++. Kompendium wiedzy. Wydanie IV, Helion, 2014 S. B. Lippman, J. Lajoie, Podstawy języka C++, WNT, Warszawa 2003.
2 #include <iostream> #include <string> using namespace std; Operator >> -przykład int main() { string imie; int wzrost; double waga; cout << "Podaj imie, wzrost i wage: "; cin >> imie >> wzrost >> waga; cout << imie << ", masz " << wzrost << " cm wzrostu i wazysz " << waga << " kg" << endl; return 0;
3 Operator >> Wartości danych wpisywane z klawiatury muszą zgadzać się co do typu z tym, czego oczekuje program: w powyższym programie oczekiwane są dane typu string (napis), int (liczba całkowita) i double (liczba rzeczywista, być może z nieznikającą częścią ułamkową) i w takiej kolejności należy je wpisać. Poszczególne elementy danych wejściowych wpisujemy oddzielając je dowolnie długą niepustą sekwencją białych znaków. Białe znaki przed pierwszą daną są ignorowane, każda następna niepusta sekwencja białych znaków jest traktowana jako separator oddzielający dane. W szczególności wynika stąd, że tą metodą nie da się wczytać napisów, które zawierają białe znaki, np. odstęp.
Inicjalizacja zmiennych. Przy okazji deklarowania zmiennych można ustalać ich wartości, co nazywa się inicjalizacją. 1 sposób. Deklarację z inicjalizacją zapisujemy następująco: nazwa_typu nazwa_zmiennej = wyrażenie; Na przykład: int a = 3; co jest skróconą formą od: int a; a = 3; W tym przypadku wyrażeniem inicjującym był literał. Ogólnie może być to dowolne wyrażenie. Np. int a = 3; int b = a + 1;//deklaracja zmiennej b //i ustalenie wartości na 4 4
Inicjalizacja zmiennych. 5 2 sposób. Drugi sposób inicjalizacji zmiennych tzw. constructor initialization ma postać nazwa_typu nazwa_zmiennej(wartość_początkowa); np: int x (0); 3 sposób. Trzeci ze sposobów wprowadzony w standardzie C++11 w ramach jednolitej inicjalizacji(uniform initialization) tzw. brace-init : nazwa_typu nazwa_zmiennej{wartość_początkowa; nazwa_typu nazwa_zmiennej = {wartość_początkowa; np. int x {0; int a{; //ustawia a na 0 int b = {7;
Inicjalizacja zmiennych. 6 PRZYKŁAD: inicjalizacja zmiennych #include <iostream> using namespace std; int main () { int a = 5; // Inicjalizacja wartością : 5 int b(3); // Inicjalizacja wartością : 3 int c{2; // Inicjalizacja wartością : 2 int result; // wartość początkowa nie określona a = a + b; // a = 8 result = a c; // result = 6 cout << result; return 0;
7 Inicjalizacja zmiennych - porównanie. Porównajmy dwie inicjalizacje, w przypadku gdy (omyłkowo) typ wartości nie pasuje do typu obiektu: int y = 12.9; //milczące obcięcie do wartości int tj.12 int x {12.9; // alarm kompilatora Jak widać, wartością przypisywaną do typu int jest tu liczba rzeczywista (a nie: całkowita). W przypadku inicjalizacji zmiennej y kompilator zawęzi (obetnie) nie informując nas o tym liczbę rzeczywistą 12.9 do wartości całkowitej 12 i to wstawi do zmiennej y. W przypadku inicjalizacji zmiennej x wartość umieszczona została w nawiasach klamrowych, a to jest informacja dla kompilatora, że typ inicjalizatora (czyli tej liczby) musi być zgodny z typem obiektu (tu: int). Jeśli typy się nie zgadzają, to kompilator ma sygnalizować błąd.
8 Podstawowe typy danych. Typy całkowitoliczbowe Przedstawimy teraz standardowe typy całkowite w C/C++. W nawiasach podane są typowe długości danych tych typów w bajtach. Typowe, bo standard określa tylko minimalne długości oraz to, że długości wymienionych poniżej typów muszą tworzyć ciąg niemalejący. Tak więc typy całkowite to: char (1), short (2), int (4), long (4 na maszynie 32 bitowej lub 8 na 64-bitowej), long long (8). Wszystkie te typy występują w dwu różnych postaciach: mogą być bez znaku (unsigned) lub ze znakiem (signed).
9 Podstawowe typy danych. Typy całkowitoliczbowe Nazwa typu bez znaku jest taka sama jak nazwa odpowiadającego typu ze znakiem, tylko poprzedzona słowem kluczowym unsigned (np. unsigned int) do nazw typów ze znakiem można zresztą również dodać jawnie signed, choć nie ma takiej potrzeby. Samo słowo unsigned może być użyte zamiast bardziej dosłownego unsigned int. W zmiennych bez znaku poszczególne bity maszynowej reprezentacji liczby interpretowane są jako zera i jedynki w normalnym zapisie dwójkowym tej liczby. Dla zmiennych ze znakiem wyraz przy najwyższej potędze dwójki brany jest z minusem. Zatem jest to tzw. kod uzupełnień do dwóch. Ogólnie, jeśli liczba zapisana jest na n bitach, to dla odpowiedniego typu unsigned zakresem wartości będzie [0, 2 n - 1], natomiast dla typu signed będzie to [- 2 n-1, 2 n-1-1].
10 Podstawowe typy danych. Typy całkowitoliczbowe Integer types (signed) Typy całkowite ze znakiem. signed char Taki rozmiar jak char. Przynajmniej 8 bitów. signed short int Nie mniejsze niż char. Przynajmniej 16 bitów. signed int Nie mniejsze niż short. Przynajmniej 16 bitów. signed long int Nie mniejsze niż int. Przynajmniej 32 bity. signed long long int Nie mniejsze niż long. Przynajmniej 64 bity. Integer types (unsigned) Typy całkowite bez znaku. (Typy te mają taki sam rozmiar jak ich odpowiedniki ze znakiem) unsigned char unsigned short int unsigned int unsigned long int unsigned long long int
11 Podstawowe typy danych. Typy całkowitoliczbowe LITERAŁY (STAŁE) CAŁKOWITOLICZBOWE Literał całkowity (np. 12345) będzie zinterpretowany jako literał typu int (czyli signed int). Jeśli chcemy wymusić zinterpretowanie go jako literału typu bezznakowego, dodajemy na końcu literę 'U' (dużą lub małą), a jeśli ma to być literał typu long, dodajemy literę 'L' lub 'l' lub 'LL' dla typu long long. Modyfikatory te można łączyć w dowolnej kolejności. Tak więc np. '13UL' jest literałem liczby 13 typu unsigned long, a '1LL' literałem liczby 1 typu long long. Literały liczbowe (całkowite) można też zapisywać w systemie ósemkowym (oktalnym), szesnastkowym (heksadecymalnym) i dwójkowym (binarnym).
12 Podstawowe typy danych. Typy całkowitoliczbowe Aby literał był potraktowany jako zapis liczby w systemie ósemkowym, poprzedzamy go cyfrą 0 (zero). Tak np. 037 zostanie zinterpretowane jako literał typu int liczby o wartości dziesiętnej 3*8 + 7 = 31. Literały w układzie szesnastkowym poprzedzamy zerem i literą 'X' (dużą lub małą). A zatem 0x2D to dziesiętnie 2*16 + 13 = 45. W literałach szesnastkowych jako cyfr od 10 do 15 używamy liter od A do F (dużych lub małych). Literały w zapisie binarnym (dwójkowym) wprowadzono w C++14 ( ale często już kompilatory C++11 pozwalają na ten typ) zaczynają się one od znaków: "0b" np. int bin = 0b100; // stała dosłowna w zapisie dwójkowym
13 Podstawowe typy danych. Typy całkowitoliczbowe #include <iostream> using namespace std; int main() { unsigned long int ul1 = 13UL; unsigned long ul2 = 0xD; // 13 szesnastkowo signed short ss1 = 015; // 13 ósemkowo short s2 = 13; // 13 dziesiętnie cout<< ul1<<" " <<ul2<<endl; cout<< ss1<<" " <<s2<<endl; return 0; 13 13 13 13
Podstawowe typy danych. Operator sizeof Jeśli chcemy poznać ograniczenia liczb całkowitych w używanym systemie możemy skorzystać z operatora sizeof, który zwraca wyrażoną w bajtach wielkość typu lub zmiennej. Plik nagłówkowy climits zawiera natomiast informacje o ograniczeniach typów. #include <iostream> #include <climits> using namespace std; int main() { long n_long = LONG_MAX; cout<<"int ma "<< sizeof(int) <<" bajty"<<endl; cout<<"short ma "<< sizeof(short) <<" bajty"<<endl; cout<<"long ma "<< sizeof n_long <<" bajty"<<endl; cout<<"long long ma "<< sizeof(long long) <<" bajty"<<endl; 14
Podstawowe typy danych. Wartości maksymalne climits cout<<"wartosci maxymalne: "<<endl; cout<<"int "<<INT_MAX<<endl; cout<<"short "<<SHRT_MAX<<endl; cout<<"long "<<LONG_MAX<<endl; cout<<"long long "<<LLONG_MAX<<endl; cout<<"wartosc min w int "<<INT_MIN<<endl; Output: int ma 4 bajty short ma 2 bajty long ma 4 bajty long long ma 8 bajty Wartosci maxymalne: int 2147483647 short 32767 long 2147483647 long long 9223372036854775807 Wartosc min w int -2147483648 15
Podstawowe typy danych. Typ char znaki i małe liczby Ostatnim typem całkowitoliczbowym jest typ char. Ma on służyć do przechowywania znaków. Ponieważ języki programowania zamiast znaków przechowują ich kody, dlatego jest on typem liczbowym. Zgodnie ze standardem typ ten ma umożliwić przechowywanie znaków z podstawowego zestawu:litery, cyfry, znaki przestankowe itd. Wartości liczbowe zmiennych tych typów odpowiadają zwykle (choć nie musi tak być) kodom ASCII znaków. Większość obecnie istniejących programów opiera się na założeniu, że znaki kodowane są według standardu ASCII. Tylko pierwsze 128 znaków ASCII (o kodach od 0 do 127) ma określone znaczenie - interpretacja pozostałych może zależeć od platformy. 16
Podstawowe typy danych. Typy znakowe Chociaż typ char (tak jak pozostałe typy znakowe) jest typem całkowitym, to jest traktowany inaczej niż typy liczbowe, gdyż w zasadzie służy do reprezentowania znaków. Z tego powodu nie powinniśmy, choć jest to formalnie możliwe, używać zmiennych znakowych w operacjach arytmetycznych, np. char zn = M ;//przypisanie zmiennej kodu ASCII M int i = zn; //zapis tego kodu jako wartości int cout<< Kod ASCII znaku <<zn<< to <<i<<endl;//77 zn = zn + 1;//zmiana kodu znaku o 1 i = zn; cout<< Kod ASCII znaku <<zn<< to <<i<<endl;//78 Typ char (1B) domyślnie nie jest typem ze znakiem. W różnych implementacjach bywa różnie: char może on być ekwiwalentny z signed char lub unsigned char. Wszystkie trzy typy są dla kompilatora różne! 17
18 Podstawowe typy danych. Typy znakowe Zwykły typ char może przeważnie służyć do przechowywania tylko znaków z podstawowego zestawu 256 liter i znaków. Wśród nich nie ma np. polskich ogonków. Aby ułatwić internacjonalizację programów, istnieją jeszcze trzy dodatkowe typy reprezentujące znaki. Są one zawsze unsigned - ich wersje signed nie istnieją. Typy te to: wchar_t (ang. wide character znak szeroki) wystarczający do reprezentowania znaków najszerszego zestawu znaków na danej platformie char16_t przynajmniej 2 bajty interpretowane jako kod Unicode 16; char32_t przynajmniej 4 bajty interpretowane jako kod Unicode 32.
19 Podstawowe typy danych. Typy znakowe int main() { unsigned char a1 = 65; signed char a2 = 'A'; // ASCII('A') = 65 int a3 = 65; int a4 = 'A'; A A 65 65 A char cout << a1 << " " << a2 << endl << a3 << " " << a4 << endl << a5 << endl; a5 = '\x41'; //65 szesnastkowo
Podstawowe typy danych. Typ bool Typ logiczny w C++ nazywa się bool. Literałami wartości typu bool są oczywiście false i true są to słowa kluczowe języka i nie mogą być przedefiniowane, np. bool ok = true; bool gotowy = false; Literały te można rzutować na typ int: int zm1 = true; //zm1 wartość 1 int zm2 = false; //zm2 wartosc 0 Rolę zmiennej typu bool może pełnić dowolna zmienna typu całkowitego lub wskaźnikowego, przy czym wartość 0 jest równoważna false, a dowolna wartość niezerowa true: bool start = -10, stop = 0;//start- true, stop- false 20
Typy zmiennopozycyjne 21 Standardowe typy zmiennopozycyjne (zmiennoprzecinkowe) float, double i long double umożliwiają pracę na liczbach rzeczywistych z różną dokładnością. Dane typu float (ang. floating point zmienny przecinek, pojedyncza precyzja - 6-7 cyfr znaczących mantysy ) zajmują zwykle 4 bajty, dane typu double (ang. double precision -podwójna precyzja - 15-16 cyfr znaczących mantysy) 8 bajtów Reprezentacja nie jest przez standard języka określona, ale we wszystkich współczesnych implementacjach C/C++ jest ona zgodna ze standardem IEEE 754 (IEEE 854 dla typu long double). Dane typu long double zajmują zwykle 12 lub 16 bajtów. (ang. long długi) oznacza wydłużoną, ulepszoną wersję typu o podwójnej precyzji.
Typy zmiennopozycyjne 22 Rzadko używane są zmienne typu float. Operacje arytmetyczne na zmiennych tego typu są i tak wykonywane po ich konwersji do typu double, więc ich stosowanie w zasadzie nie daje żadnych korzyści, a może wydłużyć czas wykonania i pogorszyć dokładność obliczeń. Jeśli nie wiesz, którego z tych trzech typów zmiennoprzecinkowych użyć w definicji swojego obiektu, to użyj typu double. Literały wartości typów zmiennopozycyjnych. Można używać zapisu z kropką dziesiętną lub notacji naukowej z literą e lub E, pomiędzy mantysą a wykładnikiem potęgi dziesięciu, przez którą mantysa ma być pomnożona (kropka w mantysie nie jest konieczna). Wykładnik musi być całkowity, może być poprzedzony znakiem plus lub minus.
Typy zmiennopozycyjne 23 Domyślnie literał liczbowy zmiennopozycyjny (a więc z kropką lub z częścią potęgową po literze e) jest traktowany jako literał wartości typu double. Jeśli chcemy wymusić traktowanie literału jako literału wartości typu float lub long double, opatrujemy go odpowiednio literą F lub L float k = 1.23F, m =.1F, n = 3.F; double x = 1.2, y = 50., z = 5e-3, v = 0.1E2; long double u = 1.23L, v = 30.4e-20L; Wartość z wynosi 5*10-3 = 0.005, a v ma wartość 0.1*10 2 = 10
Problemy z dokładnością liczb zmiennoprzecinkowych #include <iostream> using namespace std; int main() { float a = 2.34E+22f; float b = a + 1.0f; cout << "a = " << a << endl; cout << "b - a = " << b - a << endl; return 0; Output: a = 2.34e+022 b - a = 0 Liczba a ma 23 cyfry na lewo od przecinka, zatem dodając 1 dodajemy je do 23 cyfry, a dokładność float to 6-7 cyfr. 24
Instrukcja warunkowa if-else Instrukcja warunkowa (ang. conditional statement) występuje w dwóch postaciach. Prostsza to if ( wyr ) instr gdzie wyr jest wyrażeniem o wartości logicznej, a instr jest instrukcją. Przypomnijmy, że w C/C++ również liczbowe wartości całkowite i wskaźnikowe mogą być trakowane jako wartości logiczne: cokolwiek różnego od zera jest traktowane jako true, a wartość zerowa jako false. Opracowanie instrukcji warunkowej w tej formie polega na obliczeniu wartości wyr a następnie: wykonaniu instrukcji instr, jeśli obliczoną wartością wyr okazało się true, zakończeniu wykonywania całej instrukcji, jeśli obliczoną wartością wyr okazało się false. 25
26 Instrukcja warunkowa if-else Zauważmy, że składnia mówi o jednej instrukcji instr. Jeśli zachodzi potrzeba wykonania (lub zaniechania wykonania) większej liczby instrukcji, to należy ująć je w nawiasy klamrowe, tak aby uczynić z nich jedną instrukcję złożoną (grupującą)- blok { instrukcja1; instrukcja2; instrukcja3;
27 Instrukcja warunkowa if-else Druga forma instrukcji warunkowej to if ( wyr) instr1 else instr2 gdzie, jak poprzednio, wyr jest wyrażeniem o wartości logicznej a instr1 i instr2 są instrukcjami prostymi lub złożonymi. Wykonanie instrukcji warunkowej w tej formie polega na obliczeniu wartości wyr, a następnie: wykonaniu instrukcji instr1, jeśli obliczoną wartością wyr okazało się true, wykonaniu instrukcji instr2, jeśli obliczoną wartością wyr okazało się false. I znów składnia mówi o jednej instrukcji instr1 i jednej instrukcji instr2. Jeśli zachodzi potrzeba użycia kilku instrukcji,to należy, jak poprzednio, zastosować instrukcję złożoną.
Instrukcja warunkowa if-else 28
if - przykład //program pobiera wiek i wyświetla gratulacje //dla stulatków tj. wiek >= 100 #include <iostream> using namespace std; int main() { int wiek; cout << "Podaj swoj wiek: "; cin >> wiek; if ( wiek >= 100) { cout << "Gratulacje!!!" <<endl; return 0; 29
if-else - przykład //Napisz program, który wczyta liczbę całkowitą, //a następnie wyświetli informację, //czy jest to liczba 5, czy nie. int main () { int i; cout<<"podaj liczbę "<<endl; cin>>i; if (i!= 5) //lub if (i-5) -true gdy i-5!=0 cout << "Liczba rozna niż 5" << endl; else cout << "Liczba rowna 5" << endl; return 0; 30
31 if-else - przykład //program sprawdza czy pobrana liczba całkowita jest >= 0, <0 #include <iostream> using namespace std; int main() { int n; cout << "Podaj liczbe calkowita: "; cin >> n; if ( n >= 0) { cout << "Podales liczbe nieujemna: " << n << endl; else { cout << "Podales liczbe ujemna: " << n << endl; return 0;
if-else instrukcja zagnieżdżona 32 Każda z instrukcji instr1 i instr2 może z kolei też być instrukcją warunkową. Instrukcję if można zatem zagnieżdżać (wybór wielowariantowy), przy czym else odpowiada wówczas najbliższy poprzedzający go if, po którym nie było jeszcze else i który jest zawarty w tym samym bloku na tym samym poziomie zagnieżdżenia co ten else. if (wyrażenie1) isntrukcja1; else if (wyrażenie2) instrukcja2; else if (wyrażenie3) instrukcja3; else if (wyrażenie4) instrukcja4;
33 if-else instrukcja zagnieżdżona // Program sprawdza czy liczba jest dodatnia, ujemna czy rowna 0 int main() { int n; cout << "Podaj liczbe calkowita: "; cin >> n; if ( n > 0) { cout << "Podales liczba dodatnia: " << n << endl; else if (n < 0) { cout << "Podales liczba ujemna: " << n << endl; else //n==0 { cout << "Podales 0." << endl; return 0;