1 Wstęp do informatyki- wykład 4 Deklaracja zmiennych Typy 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 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).
8 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].
9 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
10 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.
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; 11
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 12
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. 13
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! 14
15 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.
16 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 17
Typy zmiennopozycyjne 18 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 19 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 20 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. 21
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. 22
23 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;
24 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 25
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; } 26
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; 27
28 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; }