r04


Rozdział 4.
Wyrażenia i instrukcje
Program stanowi zestaw kolejno wykonywanych instrukcji. Jakość działania programu zależy od
możliwości wykonywania określonego zestawu instrukcji w danych warunkach.
Z tego rozdziału dowiesz się:
" czym są instrukcje,
" czym są bloki,
" czym są wyrażenia,
" jak, w zależności od warunków, kierować wykonaniem programu,
" czym jest prawda i jak działać na jej podstawie.
Instrukcje
W C++ instrukcje kontrolują kolejność działania programu, obliczają wyrażenia lub nie robią nic
(instrukcja pusta). Wszystkie instrukcje C++ kończą się średnikiem (nawet instrukcja pusta, która
składa się wyłącznie ze średnika). Jedną z najczęściej występujących instrukcji jest instrukcja
przypisania:
x = a + b;
W przeciwieństwie do znaczenia, jakie ma w algebrze, ta instrukcja nie oznacza tutaj, że x równa
się a+b. Należy ją traktować jako  przypisz wartość sumy a i b do x lub  przypisz a+b do x lub
 niech x równa się a+b. Choć ta instrukcja wykonuje dwie czynności, nadal jest pojedynczą
instrukcją (stąd tylko jeden średnik). Operator przypisania przypisuje to, co znajduje się po prawej
stronie znaku równości elementowi znajdującemu się po lewej stronie.
Białe spacje
Białe spacje (tabulatory, spacje i znaki nowej linii) są w instrukcjach ignorowane. Omawiana
poprzednio instrukcja przypisania może zostać zapisana jako:
x=a+b;
lub jako:
x =a
+ b ;
Choć ostatni zapis jest poprawny, jest równocześnie niemądry. Białe spacje mogą być używane w
celu poprawienia czytelności programu lub stworzenia okropnego, niemożliwego do
rozszyfrowania kodu. C++ daje do wyboru wiele możliwości, ale ich rozważne użycie zależy od
ciebie.
Znaki białych spacji nie są widoczne. Gdy zostaną wydrukowane, na papierze będą widoczne jako
odstępy.
Bloki i instrukcje złożone
Wszędzie tam, gdzie może znalezć się instrukcja pojedyncza, może znalezć się także instrukcja
złożona, zwana także blokiem. Blok rozpoczyna się od otwierającego nawiasu klamrowego ({) i
kończy nawiasem zamykającym (}). Choć każda instrukcja w bloku musi kończyć się średnikiem,
sam blok nie wymaga jego zastosowania (jak pokazano w poniższym przykładzie):
{
temp = a;
a = b;
b = temp;
}
Ten blok kodu działa jak pojedyncza instrukcja i zamienia wartości w zmiennych a i b.
TAK
Jeśli użyłeś otwierającego nawiasu klamrowego, pamiętaj także o nawiasie zamykającym.
Kończ instrukcje średnikiem.
Używaj rozważnie białych spacji, tak aby kod był czytelny.
Wyrażenia
Wszystko, co staje się wartością, w C++ jest uważane za wyrażenie. Mówi się, że wyrażenie
zwraca wartość. Skoro instrukcja 3+2; zwraca wartość 5, więc jest wyrażeniem. Wszystkie
wyrażenia są jednocześnie instrukcjami.
Możesz zdziwić się, ile miejsc w kodzie kwalifikuje się jako wyrażenia. Oto trzy przykłady:
3.2 // zwraca wartość 3.2
PI // stała typu float zwracająca wartość 3.14
SecondsPerMinute // stała typu int zwracająca 60
Gdy założymy, że PI jest stałą, którą zainicjalizowałem wartością 3.14 i że SecondsPerMinute
(sekund na minutę) jest stałą wynoszącą 60, wtedy wszystkie te trzy instrukcje są wyrażeniami.
Nieco bardziej skomplikowane wyrażenie
x = a + b;
nie tylko dodaje do siebie a oraz b, a wynik umieszcza w x, ale także zwraca wartość tego
przypisania (nową wartość x). Zatem instrukcja przypisania także jest wyrażeniem. Ponieważ jest
wyrażeniem, może wystąpić po prawej stronie operatora przypisania:
y = x = a + b;
Ta linia jest przetwarzana w następującym porządku:
Dodaj a do b.
Przypisz wynik wyrażenia a + b do x.
Przypisz rezultat wyrażenia przypisania, x = a + b, do y.
Jeśli a, b, x oraz y byłyby zmiennymi całkowitymi, zaś a miałoby wartość 2, a b miałoby wartość
5, wtedy zarówno zmiennej x, jak i y zostałaby przypisana wartość 7. Ilustruje to listing 4.1.
Listing 4.1. Obliczanie wyrażeń złożonych
0: #include
1: int main()
2: {
3: using std::cout;
4: using std::endl;
5:
6: int a=0, b=0, x=0, y=35;
7: cout << "a: " << a << " b: " << b;
8: cout << " x: " << x << " y: " << y << endl;
9: a = 9;
10: b = 7;
11: y = x = a+b;
12: cout << "a: " << a << " b: " << b;
13: cout << " x: " << x << " y: " << y << endl;
14: return 0;
15: }
Wynik
a: 0 b: 0 x: 0 y: 35
a: 0 b: 7 x: 16 y: 16
Analiza
W linii 6. deklarowane i inicjalizowane są cztery zmienne. Ich wartości są wypisywane w liniach
7. i 8. W linii 9. zmiennej a jest przypisywana wartość 9. W linii 10., zmiennej b jest
przypisywana wartość 7. W linii 11. zmienne a i b są sumowane, zaś wynik sumowania jest
przypisywany zmiennej x. To wyrażenie (x = a+b) powoduje obliczenie sumy a oraz b i
przypisanie jej do zmiennej x, wartość tego przypisania jest następnie przypisywana zmiennej y.
Operatory
Operator jest symbolem, który powoduje, że kompilator rozpoczyna działanie. Operatory działają
na operandach, zaś wszystkie operandy w C++ są wyrażeniami. W C++ istnieje kilka kategorii
operatorów. Dwie z tych kategorii to:
" operatory przypisania,
" operatory matematyczne.
Operator przypisania
Operator przypisania (=) powoduje, że operand znajdujący się po lewej stronie operatora
przypisania zmienia wartość na wartość operandu znajdującego się po prawej stronie operatora.
Wyrażenie:
x = a + b;
przypisuje operandowi x wynik dodawania wartości a i b.
Operand, który może wystąpić po lewej stronie operatora przypisania jest nazywany l-wartością (l-
value). Natomiast ten, który może znalezć się po prawej stronie, jest nazywany (jak można się
domyślić), r-wartością (r-value).
Stałe są r-wartościami. Nie mogą być l-wartościami. Zatem możesz napisać:
x = 35; // OK
lecz nie możesz napisać:
35 = x; // błąd, 35 nie może być l-wartością!
L-wartość jest operandem, który może znalezć się po lewej stronie wyrażenia. R-wartość jest
operandem, który może występować po prawej stronie wyrażenia. Zwróć uwagę, że wszystkie l-
wartości mogą być r-wartościami, ale nie wszystkie r-wartości mogą być l-wartościami.
Przykładem r-wartości, która nie jest l-wartością, może być literał. Zatem możesz napisać x = 5;,
lecz nie możesz napisać 5 = x; (x może być l- lub r-wartością, lecz 5 może być tylko r-
wartością).
Operatory matematyczne
Piątka operatorów matematycznych to: dodawanie (+), odejmowanie ( ), mnożenie (*), dzielenie
(/) oraz reszta z dzielenia (%).
Dodawanie i odejmowanie działają rutynowo, choć odejmowanie liczb całkowitych bez znaku
może prowadzić do zadziwiających rezultatów gdy wynik będzie ujemny. Z czymś takim
spotkałeś się w poprzednim rozdziale, kiedy opisywaliśmy przepełnienie (przewinięcie wartości).
Listing 4.2 pokazuje, co się stanie gdy odejmiesz dużą liczbę całkowitą bez znaku od małej liczby
całkowitej bez znaku.
Listing 4.2. Przykład odejmowania i przepełnienia wartości całkowitej
0: // Listing 4.2 - Demonstracja odejmowania
1: // i przepełnienia wartości całkowitej.
2: #include
3:
4: int main()
5: {
6: using std::cout;
7: using std::endl;
8:
9: unsigned int difference;
10: unsigned int bigNumber = 100;
11: unsigned int smallNumber = 50;
12: difference = bigNumber - smallNumber;
13: cout << "Roznica to: " << difference;
14: difference = smallNumber - bigNumber;
15: cout << "\nTeraz roznica to: " << difference < 16: return 0;
17: }
Wynik
Roznica to: 50
Teraz roznica to: 4294967246
Analiza
Operator odejmowania jest wywoływany w linii 12., zaś wynik jest wypisywany w linii 13. (taki,
jakiego mogliśmy oczekiwać). Operator odejmowania jest ponownie wywoływany w linii 14.,
jednak tym razem od małej liczby całkowitej bez znaku jest odejmowana duża liczba całkowita
bez znaku. Wynik powinien być ujemny, ale ponieważ wartości są obliczane (i wypisywane) jako
liczby całkowite bez znaku, efektem tej operacji jest przepełnienie, tak jak opisywaliśmy w
poprzednim rozdziale. Ten temat jest szczegółowo omawiany w dodatku C,  Kolejność
operatorów.
Dzielenie całkowite i reszta z dzielenia
Dzielenie całkowite poznałeś w drugiej klasie szkoły podstawowej. Gdy w dzieleniu całkowitym
podzielisz 21 przez 4 (21/4), otrzymasz w wyniku 5 (oraz pewną resztę).
Resztę z dzielenia całkowitego zwraca operator reszty z dzielenia (tzw. operator modulo). Aby
otrzymać resztę, oblicz 21 modulo 4 (21 % 4). W wyniku otrzymasz 1.
Obliczanie reszty z dzielenia może być bardzo przydatne. Możesz na przykład zechcieć
wypisywać komunikat po każdej dziesiątej akcji. Każda liczba, dla której wynikiem reszty z
dzielenia przez 10 jest zero, stanowi pełną wielokrotność dziesięciu. Tak więc 1 % 10 wynosi 1, 2
% 10 wynosi 2, itd., aż do 10 % 10, które ponownie wynosi 0. 11 % 10 to znów 1, wzór ten
powtarza się aż do następnej wielokrotności dziesięciu, którą jest liczba 20. 20 % 0 to ponownie 0.
Tę technikę wykorzystujemy wewnątrz pętli, które zostaną omówione w rozdziale 7.
Często zadawane pytanie
Gdy dzielę 5/3, otrzymuję w wyniku 1. Czy coś robię nie tak?
Odpowiedz
Gdy dzielisz jedną liczbę całkowitą przez inną, w wyniku otrzymujesz także liczbę całkowitą.
Zatem 5/3 wyniesie 1. (W rzeczywistości wynikiem jest 1 i reszta 2. Aby otrzymać resztę,
spróbuj napisać 5%3, uzyskasz w ten sposób wartość 2.)
Aby uzyskać ułamkową wartość z dzielenia, musisz użyć zmiennych zmiennoprzecinkowych.
5.0/3.0 da wartość zmiennoprzecinkową 1.66667.
Jeśli zmiennoprzecinkowa jest dzielna lub dzielnik, kompilator wygeneruje zmiennoprzecinkowy
iloraz.
Aączenie operatora przypisania z
operatorem matematycznym
Często zdarza się, że chcemy do zmiennej dodać wartość, zaś wynik umieścić z powrotem w tej
zmiennej. Jeśli masz zmienną myAge (mój wiek) i chcesz zwiększyć jej wartość o dwa, możesz
napisać:
int myAge = 5;
int temp;
temp = myAge + 2; // czyli 5 + 2 jest umieszczane w zmiennej temp
myAge = temp; // wynik umieszczamy z powrotem w myAge
Ta metoda jest jednak bardzo żmudna i nieefektywna. W C++ istnieje możliwość umieszczenia tej
samej zmiennej po obu stronach operatora przypisania; w takim przypadku poprzedni przykład
można zapisać jako:
myAge = myAge + 2;
Jest to dużo lepsza metoda. W algebrze to wyrażenie nie miałoby sensu, ale w C++ jest traktowane
jako  dodaj dwa do wartości zawartej w zmiennej myAge, zaś wynik umieść ponownie w tej
zmiennej .
Jeszcze prostsze w zapisie, choć może nieco trudniejsze do odczytania, jest:
myAge += 2;
Operator += sumuje r-wartość z l-wartością, zaś wynik umieszcza ponownie w l-wartości. Ten
operator wymawia się jako  plus-równa się , zatem cała instrukcja powinna zostać odczytana jako
 myAge plus-równa się dwa . Jeśli zmienna myAge miałaby początkowo wartość 4, to po
wykonaniu tej instrukcji przyjęłaby wartość 6.
Oprócz operatora += istnieją także operatory -= (odejmowania), /= (dzielenia), *= (mnożenia), %=
(reszty z dzielenia) i inne.
Inkrementacja i dekrementacja
Najczęściej dodawaną (i odejmowaną), z ponownym przypisaniem wyniku zmiennej, wartością
jest 1. W C++ zwiększenie wartości o jeden jest nazywane inkrementacją, zaś zmniejszenie o
jeden  dekrementacją. Służą do tego specjalne operatory.
Operator inkrementacji (++) zwiększa wartość zmiennej o jeden, zaś operator dekrementacji (--)
zmniejsza ją o jeden. Jeśli chcemy inkrementować zmienną C, możemy użyć następującej
instrukcji:
C++; // zaczynamy od C i inkrementujemy
Ta instrukcja stanowi odpowiednik bardziej jawnie zapisanej operacji:
C = C + 1;
którą, jak wiemy, możemy zapisać w nieco prostszy sposób:
C += 1;
UWAGA Jak można się domyślić, język C++ otrzymał swoją nazwę dzięki zastosowaniu
operatora inkrementacji do nazwy języka, od którego pochodzi (C). C++ jest kolejną,
poprawioną wersją języka C.
Przedrostki i przyrostki
Zarówno operator inkrementacji (++), jak i dekrementacji (--) występuje w dwóch odmianach:
przedrostkowej i przyrostkowej. Odmiana przedrostkowa jest zapisywana przed nazwą zmiennej
(++myAge), zaś odmiana przyrostkowa  po niej (myAge++).
W przypadku instrukcji prostej nie ma znaczenia, której wersji użyjesz, jednak w wyrażeniach
złożonych, gdy inkrementujesz (lub dekrementujesz) zmienną, a następnie przypisujesz rezultat
innej zmiennej, różnica jest bardzo ważna. Operator przedrostkowy jest obliczany przed
przypisaniem, zaś operator przyrostkowy  po przypisaniu.
Operator przedrostkowy działa następująco: zwiększ wartość zmiennej i zapamiętaj ją. Operator
przyrostkowy działa inaczej: zapamiętaj pierwotną wartość zmiennej, po czym zwiększ wartość w
zmiennej.
Na początku może to wydawać się dość niezrozumiałe, ale jeśli x jest zmienną całkowitą o
wartości 5, to gdy napiszesz
int a = ++x;
poinformujesz kompilator, by inkrementował zmienną x (nadając jej wartość 6), po czym pobrał tę
wartość i przypisał ją zmiennej a. Zatem po wykonaniu tej instrukcji zarówno zmienna x, jak i
zmienna a mają wartość 6.
Jeśli następnie napiszesz
int b = x++;
to poinformujesz kompilator, by pobrał wartość zmiennej x (wynoszącą 6) i przypisał ją zmiennej
b, po czym powrócił do zmiennej x i inkrementował ją. W tym momencie zmienna b ma wartość
6, a zmienna x ma wartość 7. Zastosowanie i działanie obu wersji operatora przedstawia listing
4.3.
Listing 4.3. Przykład działania operatora przedrostkowego i przyrostkowego
0: // Listing 4.3 - demonstruje użycie
1: // przedrostkowych i przyrostkowych operatorów
2: // inkrementacji i dekrementacji
3: #include
4: int main()
5: {
6: using std::cout;
7:
8: int myAge = 39; // inicjalizujemy dwie zmienne całkowite
9: int yourAge = 39;
10: cout << "Ja mam: " << myAge << " lat.\n";
11: cout << "Ty masz: " << yourAge << " lat\n";
12: myAge++; // inkrementacja przyrostkowa
13: ++yourAge; // inkrementacja przedrostkowa
14: cout << "Minal rok...\n";
15: cout << "Ja mam: " << myAge << " lat.\n";
16: cout << "Ty masz: " << yourAge << " lat\n";
17: cout << "Minal kolejny rok\n";
18: cout << "Ja mam: " << myAge++ << " lat.\n";
19: cout << "Ty masz: " << ++yourAge << " lat\n";
20: cout << "Wypiszmy to jeszcze raz.\n";
21: cout << "Ja mam: " << myAge << " lat.\n";
22: cout << "Ty masz: " << yourAge << " lat\n";
23: return 0;
24: }
Wynik
Ja mam: 39 lat.
Ty masz: 39 lat
Minal rok...
Ja mam: 40 lat.
Ty masz: 40 lat
Minal kolejny rok
Ja mam: 40 lat.
Ty masz: 41 lat
Wypiszmy to jeszcze raz.
Ja mam: 41 lat.
Ty masz: 41 lat
Analiza
W liniach 8. i 9. deklarujemy dwie zmienne całkowite i inicjalizujemy je wartością 39. Ich
wartości są wypisywane w liniach 10. i 11.
W linii 12. zmienna myAge (mój wiek) jest inkrementowana za pomocą operatora przyrostkowego,
zaś w linii 13. zmienna yourAge (twój wiek) jest inkrementowana za pomocą operatora
przedrostkowego. Wyniki wypisywane w liniach 15. i 16. są identyczne (40).
W linii 18. zmienna myAge jest inkrementowana jako część instrukcji wypisywania danych, za
pomocą operatora przyrostkowego. Ponieważ jest to operator przyrostkowy, inkrementacja
odbywa się już po wypisaniu tekstu, dlatego ponownie wypisywana jest wartość 40. Dla
odróżnienia od linii 18., w linii 19. zmienna yourAge jest inkrementowana za pomocą operatora
przedrostkowego. Ponieważ w takim przypadku inkrementacja odbywa się przed wypisaniem
tekstu, zostaje wypisana wartość 41.
Na zakończenie, w liniach 21. i 22., ponownie wypisywane są wartości zmiennych. Ponieważ
instrukcje inkrementacji zostały dokończone, zmienna myAge, podobnie jak zmienna yourAge
przyjmuje wartość 41.
Kolejność działań
Które działanie instrukcji złożonej, takiej jak ta
x = 5 + 3 * 8;
jest wykonywane jako pierwsze: dodawanie czy mnożenie? Gdyby najpierw wykonywane było
dodawanie, wynik wynosiłby 8 * 8, czyli 64. Gdyby najpierw wykonywane było mnożenie,
uzyskalibyśmy wynik 5 + 24, czyli 29.
Każdy operator posiada swój priorytet, który określa kolejność wykonywania działań. Pełną listę
priorytetów operatorów można znalezć w dodatku C.
Mnożenie ma priorytet nad dodawaniem, więc w tym przypadku wartością wyrażenia jest 29.
Gdy dwa operatory matematyczne osiągają ten sam priorytet, są obliczane w kolejności od lewej
do prawej. Zatem w wyrażeniu
x = 5 + 3 + 8 * 9 + 6 * 4;
mnożenia są wykonywane jako pierwsze (najpierw lewe, potem prawe). Otrzymujemy 8*9 = 72
oraz 6*4 = 24. Teraz wyrażenie można zapisać jako
x = 5 + 3 + 72 + 24.
Następnie obliczane są dodawania, od lewej do prawej: 5 + 3 = 8; 8 + 72 = 80; 80 + 24 = 104.
Bądz ostrożny. Niektóre operatory, takie jak operator przypisania, są obliczane w kolejności od
prawej do lewej!
Co zrobić gdy kolejność wykonywania działań nie odpowiada naszym potrzebom? Wezmy na
przykład takie wyrażenie:
TotalSeconds = NumMinutesToThink + NumMinutesToType * 60
W tym wyrażeniu nie chcemy mnożyć zmiennej NumMinutesToType (ilość minut wpisywania)
przez 60, a następnie dodawać otrzymanej wartości do zmiennej NumMinutesToThink (ilość
minut namysłu). Chcemy zsumować obie zmienne, aby otrzymać łączną ilość minut, a dopiero
potem przemnożyć ją przez ilość sekund w minucie, w celu otrzymania łącznej ilości sekund
(TotalSeconds).
W tym przypadku, w celu zmiany kolejności działań użyjemy nawiasów. Działania na elementach
w nawiasach są zawsze wykonywane przed innymi operacjami matematycznymi. Zatem
zamierzony wynik uzyskamy dopiero wtedy, gdy napiszemy:
TotalSeconds = (NumMinutesToThink + NumMinutesToType) * 60
Zagnieżdżanie nawiasów
W przypadku złożonych wyrażeń można zagnieżdżać nawiasy jeden wewnątrz drugiego. Na
przykład, przed obliczeniem łącznej ilości  osobosekund (TotalPersonSeconds) możesz
zechcieć obliczyć łączną ilość sekund oraz łączną ilość osób zajętych pracą:
TotalPersonSeconds = ( ( (NumMinutesToThink+NumMinutesToType) * 60) *
(PeopleInTheOffice + PeopleOnVacation) )
To złożone wyrażenie jest odczytywane od wewnątrz na zewnątrz. Najpierw sumowane są
zmienne NumMinutesToThink oraz NumMinutesToType, gdyż znajdują się w wewnętrznych
nawiasach. Potem ta suma jest mnożona przez 60. Następnie sumowane są zmienne
PeopleInTheOffice (osoby w biurze) oraz PeopleOnVacation (osoby na urlopie). Na koniec
łączna ilość osób jest przemnażana przez łączną ilość sekund.
Z tym przykładem wiąże się jeszcze jedno ważne zagadnienie. To wyrażenie jest łatwe do
zrozumienia przez komputer, lecz jest bardzo trudne do odczytania, zrozumienia lub
zmodyfikowania przez człowieka. Oto to samo wyrażenie, przepisane z użyciem kilku
tymczasowych zmiennych całkowitych:
TotalMinutes = NumMinutesToThink + NumMinutesToType;
TotalSeconds = TotalMinutes * 60;
TotalPeople = PeopleInTheOffice + PeopleOnVacation;
TotalPersonSeconds = TotalPeople * TotalSeconds;
Napisanie tego przykładu wymaga więcej czasu do napisania i skorzystania z większej ilości
tymczasowych zmiennych, lecz sprawi, że będzie on dużo łatwiejszy do zrozumienia. Gdy dodasz
do niego komentarz, opisujący, do czego służy ten kod oraz gdy zamienisz wartość 60 na stałą
symboliczną, otrzymasz łatwy do zrozumienia i modyfikacji kod.
TAK NIE
Pamiętaj, że wyrażenia mają wartość. Nie zagnieżdżaj nawiasów zbyt głęboko, gdyż
wyrażenie stanie się zbyt trudne do zrozumienia
Używaj operatora przedrostkowego
i modyfikacji.
(++zmienna) do inkrementacji lub
dekrementacji zmiennej przed jej użyciem w
wyrażeniu.
Używaj operatora przyrostkowego
(zmienna++) do inkrementacji lub
dekrementacji zmiennej po jej użyciu w
wyrażeniu.
W celu zmiany kolejności działań używaj
nawiasów.
Prawda i fałsz
W poprzednich wersjach C++, prawda i fałsz były reprezentowane jako liczby całkowite; w
standardzie ANSI wprowadzono nowy typ: bool. Typ ten może mieć tylko dwie wartości, true
(prawda) oraz false (fałsz).
Można sprawdzić prawdziwość każdego wyrażenia. Wyrażenia, których matematycznym
wynikiem jest zero, zwracają wartość false. Wszystkie inne wyrażenia zwracają wartość true.
UWAGA Wiele kompilatorów oferowało typ bool już wcześniej, był on wewnętrznie
reprezentowany jako typ long int i miał rozmiar czterech bajtów. Nowe, zgodne z ANSI
kompilatory często korzystają z jednobajtowych zmiennych typu bool.
Operatory relacji
Operatory relacji są używane do sprawdzania, czy dwie liczby są równe, albo czy jedna z nich jest
większa lub mniejsza od drugiej. Każdy operator relacji zwraca prawdę lub fałsz. Operatory relacji
zostaną przedstawione nieco dalej, w tabeli 4.1.
UWAGA Wszystkie operatory relacji zwracają wartość typu bool, czyli wartość true albo
false. W poprzednich wersjach C++ operatory te zwracały albo wartość 0 dla fałszu, albo
wartość różną od zera (zwykle 1) dla prawdy.
Jeśli zmienna całkowita myAge ma wartość 45, zaś zmienna całkowita yourAge ma wartość 50,
możesz sprawdzić, czy są równe, używając operatora  równa się :
myAge == yourAge; // czy wartość myAge jest równa wartości yourAge?
Wyrażenie ma wartość false (fałsz), gdyż wartości tych zmiennych nie są równe. Z kolei
wyrażenie
myAge < yourAge; // czy myAge jest mniejsze od yourAge?
ma wartość true (prawda).
OSTRZEŻENIE Wielu początkujących programistów C++ myli operator przypisania (=) z
operatorem relacji równości (==). Może to prowadzić do uporczywych i trudnych do wykrycia
błędów w programach.
Sześć operatorów relacji to: równe (==), mniejsze (<), większe (>), mniejsze lub równe (<=),
większe lub równe (>=) oraz różne (!=). Zostały one zebrane (wraz z przykładami użycia w
kodzie) w tabeli 4.1.
Tabela 4.1. Operatory relacji
Nazwa Operator Przykład Wynik
== 100 == 50;
Równe false (fałsz)
50 == 50;
true (prawda)
!= 100 != 50;
Nie równe true (prawda)
50 != 50;
false (fałsz)
> 100 > 50;
Większe true (prawda)
50 > 50;
false (fałsz)
>= 100 >= 50;
Większe lub równe true (prawda)
50 >= 50;
true (prawda)
< 100 < 50;
Mniejsze false (fałsz)
50 < 50;
false (fałsz)
<= 100 <= 50;
Mniejsze lub równe false (fałsz)
50 <= 50;
true (prawda)
TAK NIE
Pamiętaj, że operatory relacji zwracają wartość Nie myl operatora przypisania (=) z operatorem
true (prawda) lub false (fałsz).
relacji równości (==). Jest to jeden z
najczęstszych błędów popełnianych przez
programistów C++. Strzeż się go.
Instrukcja if
Program jest wykonywany linia po linii, w takiej kolejności, w jakiej linie te występują w tekście
kodu zródłowego. Instrukcja if umożliwia sprawdzenie spełnienia warunku (na przykład, czy
dwie zmienne są równe) i przejście do wykonania innej części kodu.
Najprostsza forma instrukcji if jest następująca:
if (wyrażenie)
instrukcja;
Wyrażenie w nawiasach może być całkowicie dowolne, ale najczęściej jest to jedno z wyrażeń
relacji. Jeśli wyrażenie to ma wartość false, wtedy instrukcja jest pomijana. Jeśli wyrażenie
jest prawdziwe (ma wartość true), wtedy instrukcja jest wykonywana. Wezmy poniższy
przykład:
if (bigNumber > smallNumber)
bigNumber = smallNumber;
Ten kod porównuje zmienną bigNumber (duża liczba) ze zmienną smallNumber (mała liczba).
Jeśli wartość zmiennej bigNumber jest większa, w drugiej linii tej zmiennej jest przypisywana
wartość zmiennej smallNumber.
Ponieważ blok instrukcji ujętych w nawiasy klamrowe stanowi odpowiednik instrukcji
pojedynczej, warunkowo wykonywany fragment kodu może być dość rozbudowany:
if (wyrażenie)
{
instrukcja1;
instrukcja2;
instrukcja3;
}
Oto prosty przykład wykorzystania tej możliwości:
if (bigNumber > smallNumber)
{
bigNumber = smallNumber;
std::cout << "duza liczba: " << bigNumber << "\n";
std::cout << "mala liczba: " << smallNumber << "\n";
}
Tym razem, jeśli zmienna bigNumber jest większa od zmiennej smallNumber, przypisywana jest
jej wartość zmiennej smallNumber, a ponadto wypisywany jest informacyjny komunikat. Listing
4.4 przedstawia szczegółowo przykład warunkowego wykonywania kodu (z zastosowaniem
operatorów relacji).
Listing 4.4. Przykład warunkowego wykonania kodu (z zastosowaniem operatorów relacji)
0: // Listing 4.5 - demonstruje instrukcje if
1: // używane z operatorami relacji
2: #include
3: int main()
4: {
5: using std::cout;
6: using std::cin;
7:
8: int MetsScore, YankeesScore;
9: cout << "Wpisz wynik dla Metsow: ";
10: cin >> MetsScore;
11:
12: cout << "\nWpisz wynik dla Yankees: ";
13: cin >> YankeesScore;
14:
15: cout << "\n";
16:
17: if (MetsScore > YankeesScore)
18: cout << "Let's Go Mets!\n";
19:
20: if (MetsScore < YankeesScore)
21: {
22: cout << "Go Yankees!\n";
23: }
24:
25: if (MetsScore == YankeesScore)
26: {
27: cout << "Remis? Eeee, nie moze byc...\n";
28: cout << "Podaj mi prawdziwy wynik dla Yanks: ";
29: cin >> YankeesScore;
30:
31: if (MetsScore > YankeesScore)
32: cout << "Wiedzialem! Let's Go Mets!";
33:
34: if (YankeesScore > MetsScore)
35: cout << "Wiedzialem! Go Yanks!";
36:
37: if (YankeesScore == MetsScore)
38: cout << "Coz, rzeczywiscie byl remis!";
39: }
40:
41: cout << "\nDzieki za informacje.\n";
42: return 0;
43: }
Wynik
Wpisz wynik dla Metsow: 10
Wpisz wynik dla Yankees: 10
Remis? Eeee, nie moze byc...
Podaj mi prawdziwy wynik dla Yanks: 8
Wiedzialem! Let's Go Mets!
Dzieki za informacje.
Analiza
Ten program pyta użytkownika o wyniki spotkań dwóch drużyn baseballowych; wyniki są
przechowywane w zmiennych całkowitych. Te zmienne są porównywane w instrukcjach if w
liniach 17., 20. i 25. (W poprzednich wydaniach książki Yankees występowali przeciw Red Sox.
W tym roku mamy inną serię, więc zaktualizowałem przykład!)
Jeśli jeden z wyników jest wyższy niż drugi, wypisywany jest komunikat informacyjny. Jeśli
wyniki są równe, wtedy program przechodzi do bloku kodu zaczynającego się w linii 25. i
kończącego w linii 39. Pojawia się w nim prośba o ponowne podanie drugiego wyniku, po czym
wyniki są porównywane jeszcze raz.
Zwróć uwagę, że gdyby początkowy wynik Yankees był większy niż wynik Metsów, wtedy w
instrukcji if w linii 17. otrzymalibyśmy wynik false, co spowodowałoby że linia 18. nie
zostałaby wykonana. Test w linii 20. miałby wartość true, więc wykonana zostałaby instrukcja w
linii 22.. Następnie zostałaby wykonana instrukcja if w linii 25. i jej wynikiem byłoby false
(jeśli wynikiem w linii 17. była prawda). Tak więc program pominąłby cały blok, aż do linii 39.
Ten przykład ilustruje że otrzymanie wyniku true w jednej z instrukcji if nie powoduje
zaprzestania sprawdzania pozostałych instrukcji if.
Zauważ, że wykonywaną zawartością dwóch pierwszych instrukcji if są pojedyncze linie
(wypisujące  Let s Go Mets! lub  Go Yankees! ). W pierwszym przykładzie (w linii 18.) nie
umieściłem linii w nawiasach klamrowych, gdyż pojedyncza instrukcja nie wymaga ich
zastosowania. Nawiasy klamrowe są jednak dozwolone, więc użyłem ich w liniach 21. i 23.
OSTRZEŻENIE Wielu początkujących programistów C++ nieświadomie umieszcza średnik za
nawiasem zamykającym instrukcję if:
if(SomeValue < 10);
SomeValue = 10;
Zamiarem programisty było tu sprawdzenie, czy zmienna SomeValue (jakaś wartość) jest
mniejsza niż 10, i gdy warunek ten zostałby spełniony, przypisalibyśmy tej zmiennej minimalną
wartość 10. Uruchomienie tego fragmentu kodu pokazuje, że zmienna SomeValue jest zawsze
ustawiana na 10! Dlaczego? Ponieważ instrukcja if kończy się średnikiem (czyli instrukcją
pustą).
Pamiętaj, że wcięcia w kodzie zródłowym nie mają dla kompilatora żadnego znaczenia. Ten
fragment mógłby zostać zapisany (bardziej poprawnie) jako:
if(SomeValue < 10) // sprawdzenie
; // nic nie rób
SomeValue = 10; // przypisz
Usunięcie średnika występującego w pierwszym przykładzie spowoduje, że druga linia stanie
się częścią instrukcji if i kod zadziała zgodnie z planem.
Styl wcięć
Listing 4.3 pokazuje jeden ze stylów  wcinania instrukcji if. Nie ma chyba jednak lepszego
sposobu na wszczęcie wojny religijnej niż zapytanie grupy programistów, jaki jest najlepszy styl
wyrównywania nawiasów klamrowych. Choć dostępne są tuziny ich odmian, wygląda na to, że
najczęściej stosowane są trzy z nich:
" umieszczenie otwierającego nawiasu klamrowego po warunku i wyrównanie nawiasu
klamrowego zamykającego blok zawierający początek instrukcji if:
if (wyrażenie){
instrukcje
}
" wyrównanie nawiasów klamrowych z instrukcją if i wcięcie jedynie bloku instrukcji:
if (wyrażenie)
{
instrukcje
}
" wcięcie zarówno instrukcji, jak i nawiasów klamrowych:
if (wyrażenie)
{
instrukcje
}
W tej książce stosujemy drugą z podanych wyżej wersji, gdyż uważam, że najlepiej pokazuje
gdzie zaczyna się, a gdzie się kończy blok instrukcji. Pamiętaj jednak, że nie ma znaczenia który
styl sam wybierzesz, o ile tylko będziesz go konsekwentnie stosował.
else
Często zdarza się, że w swoim programie chcesz wykonać jakiś fragment kodu, jeżeli spełniony
zostanie pewien warunek, oraz inny fragment kodu, gdy warunek ten nie zostanie spełniony. Na
listingu 4.4 chcieliśmy wypisać komunikat (Let s Go Mets!), pod warunkiem, że pierwszy test
(MetsScore > YankeesScore) da wartość true, lub inny komunikat (Go Yankees!), gdy ten
test da wartość false.
Pokazana już wcześniej metoda  sprawdzenie najpierw pierwszego warunku, a potem drugiego
 działa poprawnie, lecz jest nieco żmudna. Dzięki zastosowaniu słowa kluczowego else
możemy to zamienić na bardziej czytelny fragment kodu:
if (wyrażenie)
instrukcja;
else
instrukcja;
Użycie słowa kluczowego else demonstruje listing 4.5.
Listing 4.5. Użycie słowa kluczowego else
0: // Listing 4.5 - demonstruje instrukcję if
1: // z klauzulą else
2: #include
3: int main()
4: {
5: using std::cout;
6: using std::cin;
7:
8: int firstNumber, secondNumber;
9: cout << "Prosze wpisac wieksza liczbe: ";
10: cin >> firstNumber;
11: cout << "\nProsze wpisac mniejsza liczbe: ";
12: cin >> secondNumber;
13: if (firstNumber > secondNumber)
14: cout << "\nDzieki!\n";
15: else
16: cout << "\nPomylka! Druga liczba jest wieksza!";
17:
18: return 0;
19: }
Wynik
Prosze wpisac wieksza liczbe: 10
Prosze wpisac mniejsza liczbe: 12
Pomylka! Druga liczba jest wieksza!
Analiza
Obliczany jest warunek w instrukcji if w linii 13. Jeśli warunek jest spełniony (prawdziwy),
wykonywana jest instrukcja w linii 14.; jeśli nie jest spełniony (jest fałszywy), wykonywana jest
instrukcja w linii 16. Gdyby klauzula else w linii 15. została usunięta, wtedy instrukcja w linii
16. byłaby wykonywana zawsze, bez względu na to, czy warunek instrukcji if byłby spełniony,
czy nie. Pamiętaj że instrukcja if kończy się po linii 14. Gdyby nie było else, linia 16. byłaby po
prostu kolejną linią programu.
Pamiętaj, że obie instrukcje wykonywane warunkowo można zastąpić blokami kodu ujętymi w
nawiasy klamrowe.
Instrukcja if
Składnia instrukcji if jest następująca:
Forma 1
if (wyrażenie)
instrukcja;
następna instrukcja;
Jeśli wyrażenie ma wartość true, to instrukcja jest wykonywana i program przechodzi do
wykonania następnej instrukcji. Jeśli wyrażenie nie jest prawdziwe, instrukcja jest
ignorowana i program przechodzi bezpośrednio do następnej instrukcji.
Pamiętaj, że instrukcja może być pojedynczą instrukcją zakończoną średnikiem lub blokiem
instrukcji ujętym w nawiasy klamrowe.
Forma 2
if (wyrażenie)
instrukcja1;
else
instrukcja2;
następna instrukcja;
Jeśli wyrażenie ma wartość true, wykonywana jest instrukcja1; w przeciwnym razie
wykonywana jest instrukcja2. Następnie program przechodzi do wykonania następnej
instrukcji.
Przykład 1
if (SomeValue < 10)
cout << "SomeValue jest mniejsze niż 10";
else
cout << "SomeValue nie jest mniejsze niż 10";
cout << "Gotowe." << endl;
Zaawansowane instrukcje if
Warto zauważyć, że w klauzuli if lub else może być zastosowana dowolna instrukcja, nawet
inna instrukcja if lub else. Z tego powodu możemy natrafić na złożone instrukcje if,
przyjmujące postać:
if (wyrażenie1)
{
if (wyrażenie2)
instrukcja1;
else
{
if (wyrażenie3)
instrukcja2;
else
instrukcja3;
}
}
else
instrukcja4;
Ta rozbudowana instrukcja if działa następująco: jeśli wyrażenie1 ma wartość true i
wyrażenie2 ma wartość true, wykonaj instrukcję1. Jeśli wyrażenie1 ma wartość true,
lecz wyrażenie2 ma wartość false, wtedy, jeśli wyrażenie3 ma wartość true, wykonaj
instrukcję2. Jeśli wyrażenie1 ma wartość true, lecz wyrażenie2 i wyrażenie3 mają
wartość false, wtedy wykonaj instrukcję3. Na zakończenie, jeśli wyrażenie1 ma wartość
false, wykonaj instrukcję4. Jak widać, złożone instrukcje if mogą wprawiać w
zakłopotanie!
Przykład takiej złożonej instrukcji if zawiera listing 4.6.
Listing 4.6. Złożona, zagnieżdżona instrukcja if
0: // Listing 4.6 - a złożona zagnieżdżona
1: // instrukcja if
2: #include
3: int main()
4: {
5: // Poproś o dwie liczby.
6: // Przypisz je zmiennym bigNumber i littleNumber
7: // Jeśli bigNumber jest większe niż littleNumber,
8: // sprawdz, czy się dzielą bez reszty.
9: // Jeśli tak, sprawdz, czy są to te same liczby.
10:
11: using namespace std;
12:
13: int firstNumber, secondNumber;
14: cout << "Wpisz dwie liczby.\nPierwsza: ";
15: cin >> firstNumber;
16: cout << "\nDruga: ";
17: cin >> secondNumber;
18: cout << "\n\n";
19:
20: if (firstNumber >= secondNumber)
21: {
22: if ((firstNumber%secondNumber) == 0) // dziela sie bez
reszty?
23: {
24: if (firstNumber == secondNumber)
25: cout << "One sa takie same!\n";
26: else
27: cout << "One dziela sie bez reszty!\n";
28: }
29: else
30: cout << "One nie dziela sie bez reszty!\n";
31: }
32: else
33: cout << "Hej! Druga liczba jest wieksza!\n";
34: return 0;
35: }
Wynik
Wpisz dwie liczby.
Pierwsza: 10
Druga: 2
One dziela sie bez reszty!
Analiza
Program prosi o wpisanie dwóch liczb, jednej po drugiej. Następnie są one porównywane.
Pierwsza instrukcja if, w linii 20., sprawdza, czy pierwsza liczba jest większa lub równa drugiej.
Jeśli nie, wykonywana jest klauzula else w linii 32.
Jeśli pierwsza instrukcja if jest prawdziwa, wykonywany jest blok kodu zaczynający się w linii
21., po czym w linii 22. przeprowadzany jest kolejny test w instrukcji if. W tym przypadku
sprawdzamy, czy reszta z dzielenia pierwszej liczby przez drugą wynosi zero, to jest czy obie
liczby są przez siebie podzielne. Jeśli tak, liczby te mogą być takie same lub mogą być podzielne
przez siebie. Instrukcja if w linii 24. sprawdza, czy te liczby są równe i w obu przypadkach
wyświetla odpowiedni komunikat.
Jeśli warunek instrukcji if w linii 22. nie zostanie spełniony, wtedy wykonywana jest instrukcja
else w linii 29.
Użycie nawiasów klamrowych w
zagnieżdżonych instrukcjach if
Choć dozwolone jest pomijanie nawiasów klamrowych w instrukcjach if zawierających tylko
pojedyncze instrukcje, i choć dozwolone jest zagnieżdżanie instrukcji if:
if (x > y) // gdy x jest większe od y
if (x < z) // oraz gdy x jest mniejsze od z
x = y; // wtedy przypisz zmiennej x wartość zmiennej y
może to powodować zbyt dużo problemów ze zrozumieniem struktury kodu w przypadku, gdy
piszesz duże zagnieżdżone instrukcje. Pamiętaj, białe spacje i wcięcia są ułatwieniem dla
programisty, lecz nie stanowią żadnej różnicy dla kompilatora. Aatwo jest się pomylić i błędnie
wstawić instrukcję else do niewłaściwej instrukcji if. Problem ten ilustruje listing 4.7.
Listing 4.7. Przykład: nawiasy klamrowe ułatwiają zorientowanie się, które instrukcje else należą
do których instrukcji if.
0: // Listing 4.7  demonstruje, dlaczego nawiasy klamrowe
1: // mają duże znaczenie w zagnieżdżonych instrukcjach if
2: #include
3: int main()
4: {
5: int x;
6: std::cout << "Wpisz liczbe mniejsza niz 10 lub wieksza niz
100: ";
7: std::cin >> x;
8: std::cout << "\n";
9:
10: if (x >= 10)
11: if (x > 100)
12: std::cout << "Wieksza niz 100, Dzieki!\n";
13: else // nie tego else chcieliśmy!
14: std::cout << "Mniejsza niz 10, Dzieki!\n";
15:
16: return 0;
17: }
Wynik
Wpisz liczbe mniejsza niz 10 lub wieksza niz 100: 20
Mniejsza niz 10, Dzieki!
Analiza
Programista miał zamiar poprosić o liczbę mniejszą niż 10 lub większą od 100, sprawdzić czy
wartość jest poprawna, po czym wypisać podziękowanie.
Jeśli instrukcja if w linii 10. jest prawdziwa, zostaje wykonana następna instrukcja (w linii 11.).
W tym przypadku linia 11. jest wykonywana, gdy wprowadzona liczba jest większa niż 10. Linia
11. także zawiera instrukcję if. Ta instrukcja jest prawdziwa, gdy wprowadzona liczba jest
większa od 100. Jeśli liczba jest większa niż 100, wtedy wykonywana jest instrukcja w linii 12.
Jeśli wprowadzona liczba jest mniejsza od 10, wtedy instrukcja if w linii 10. daje wynik false i
program przechodzi do następnej linii po instrukcji if, czyli w tym przypadku do linii 16. Jeśli
wpiszesz liczbę mniejszą niż 10, otrzymasz wynik:
Wpisz liczbe mniejsza niz 10 lub wieksza niz 100: 9
Klauzula else w linii 13. miała być dołączona do instrukcji if w linii 10., i w związku z tym
została odpowiednio wcięta. Jednak w rzeczywistości ta instrukcja else jest dołączona do
instrukcji if w linii 11., co powoduje, że w programie występuje subtelny błąd.
Błąd jest subtelny, gdyż kompilator go nie zauważy i nie zgłosi. Jest to w pełni poprawny program
języka C++, lecz nie wykonuje tego, do czego został stworzony. Na dodatek, w większości testów
przeprowadzanych przez programistę będzie działał poprawnie. Dopóki wprowadzane będą liczby
większe od 100, program będzie działał poprawnie.
Listing 4.8 przedstawia rozwiązanie tego problemu  wstawienie koniecznych nawiasów
klamrowych.
Listing 4.8. Przykład właściwego użycia nawiasów klamrowych w instrukcji if
0: // Listing 4.8 - demonstruje właściwe użycie nawiasów
1: // klamrowych w zagnieżdżonych instrukcjach if
2: #include
3: int main()
4: {
5: int x;
6: std::cout << "Wpisz liczbe mniejsza niz 10 lub wieksza niz
100: ";
7: std::cin >> x;
8: std::cout << "\n";
9:
10: if (x >= 10)
11: {
12: if (x > 100)
13: std::cout << "Wieksza niz 100, Dzieki!\n";
14: }
15: else // poprawione!
16: std::cout << "Mniejsza niz 10, Dzieki!\n";
17: return 0;
18: }
Wynik
Wpisz liczbe mniejsza niz 10 lub wieksza niz 100: 9
Mniejsza niz 10, Dzieki!
Analiza
Nawiasy klamrowe w liniach 11. i 14. powodują, że cały zawarty między nimi kod jest traktowany
jak pojedyncza instrukcja, dzięki czemu instrukcja else w linii 15. odnosi się teraz do instrukcji
if w linii 10., czyli tak, jak zamierzono.
UWAGA Programy przedstawione w tej książce zostały napisane w celu zilustrowania
omawianych zagadnień. Są więc z założenia uproszczone i nie zawierają żadnych
mechanizmów kontroli błędów wpisywanych przez użytkownika danych. W profesjonalnym
kodzie należy przewidzieć każdy błąd i odpowiednio na niego zareagować.
Operatory logiczne
Często zdarza się, że chcemy zadać więcej niż jedno relacyjne pytanie na raz.  Czy jest prawdą że
x jest większe od y i czy jest jednocześnie prawdą, że y jest większe od z? Aby móc podjąć
działanie, program musi mieć możliwość sprawdzenia, czy oba te warunki są prawdziwe  lub
czy przynajmniej któryś z nich jest prawdziwy.
Wyobrazmy sobie skomplikowany system alarmowy, działający zgodnie z następującą zasadą:
 gdy zabrzmi alarm przy drzwiach I jest już po szóstej po południu I NIE ma świąt LUB jest
weekend, wtedy zadzwoń po policję . Do tego rodzaju obliczeń stosowane są trzy operatory
logiczne języka C++. Zostały one przedstawione w tabeli 4.2.
Tabela 4.2. Operatory logiczne
Operator Symbol Przykład
&& wyrażenie1 && wyrażenie2
I (AND)
|| wyrażenie1 || wyrażenie2
LUB (OR)
! !wyrażenie
NIE (NOT)
Logiczne I
Instrukcja logicznego I (AND) oblicza dwa wyrażenia, jeżeli oba mają wartość true, wartością
całego wyrażenia I także jest true. Jeśli prawdą jest, że jesteś głodny I prawdą jest, że masz
pieniądze, WTEDY możesz kupić obiad. Zatem
if ( (x == 5) && (y == 5) )
będzie prawdziwe, gdy zarówno x, jak i y ma wartość 5, zaś będzie nieprawdziwe, gdy któraś z
tych zmiennych będzie miała wartość różną od 5. Zapamiętaj, że aby całe wyrażenie było
prawdziwe, prawdziwe muszą być oba wyrażenia.
Zauważ, że logiczne I to podwójny symbol, &&. Pojedynczy symbol, &, jest zupełnie innym
operatorem, który opiszemy w rozdziale 21.,  Co dalej.
Logiczne LUB
Instrukcja logicznego LUB (OR) oblicza dwa wyrażenia, gdy któreś z nich ma wartość true, wtedy
wartością całego wyrażenia LUB także jest true. Jeśli prawdą jest, że masz gotówkę LUB prawdą
jest że, masz kartę kredytową, WTEDY możesz zapłacić rachunek. Nie potrzebujesz jednocześnie
gotówki i karty kredytowej, choć posiadanie obu jednocześnie nie przeszkadza. Zatem
if ( (x == 5) || (y == 5) )
będzie prawdziwe, gdy x lub y ma wartość 5, lub gdy obie zmienne mają wartość 5.
Zauważ, że logiczne LUB to podwójny symbol ||. Pojedynczy symbol | jest zupełnie innym
operatorem, który opiszemy w rozdziale 21.,  Co dalej.
Logiczne NIE
Instrukcja logicznego NIE (NOT) ma wartość true, gdy sprawdzane wyrażenie ma wartość false.
Jeżeli sprawdzane wyrażenie ma wartość true, operator logiczny NIE zwraca wartość false.
Zatem
if ( !(x == 5) )
jest prawdziwe tylko wtedy, gdy x jest różne od 5. Identycznie działa zapis:
if (x != 5)
Skrócone obliczanie wyrażeń logicznych
Gdy kompilator oblicza instrukcję I, na przykład taką, jak:
if ( (x == 5) && (y == 5) )
wtedy najpierw sprawdza prawdziwość pierwszego wyrażenia (x == 5). Gdy jest ono
nieprawdziwe, POMIJA sprawdzanie prawdziwości drugiego wyrażenia (y == 5), gdyż
instrukcja I wymaga, aby oba wyrażenia były prawdziwe.
Gdy kompilator oblicza instrukcję LUB, na przykład taką, jak:
if ( (x == 5) || (y == 5) )
wtedy w przypadku prawdziwości pierwszego wyrażenia (x == 5), nigdy NIE JEST sprawdzane
drugie wyrażenie (y == 5), gdyż w instrukcji LUB wystarczy prawdziwość któregokolwiek z
wyrażeń.
Kolejność operatorów logicznych
Operatory logiczne, podobnie jak operatory relacji, są w języku C++ wyrażeniami, więc zwracają
wartości; w tym przypadku wartość true lub false. Tak jak wszystkie wyrażenia, posiadają
priorytet (patrz dodatek C), określający kolejność ich obliczania. Ma on znaczenie podczas
wyznaczania wartości instrukcji
if ( x > 5 && y > 5 || z > 5)
Być może programista chciał, by to wyrażenie miało wartość true, gdy zarówno x, jak i y są
większe od 5 lub gdy z jest większe od 5. Z drugiej strony, programista mógł chcieć, by to
wyrażenie było prawdziwe tylko wtedy, gdy x jest większe od 5 i gdy y lub z jest większe od 5.
Jeśli x ma wartość 3, zaś y i z mają wartość 10, wtedy prawdziwa jest pierwsza interpretacja (z
jest większe od 5, więc x i y są ignorowane). Jednak w drugiej interpretacji otrzymujemy wartość
false (x nie jest większe od 5, więc nie ma znaczenia, co jest po prawej stronie symbolu &&,
gdyż obie jego strony muszą być prawdziwe).
Choć o kolejności obliczeń decydują priorytety operatorów, jednak do zmiany ich kolejności i
jasnego wyrażenia naszych zamiarów możemy użyć nawiasów:
if ( (x > 5) && (y > 5 || z > 5) )
Używając poprzednio opisanych wartości otrzymujemy dla tego wyrażenia wartość false.
Ponieważ x nie jest większe od 5, lewa strona instrukcji I jest nieprawdziwa, więc całe wyrażenie
jest traktowane jako nieprawdziwe. Pamiętaj, że instrukcja I wymaga, by obie strony były
prawdziwe.
UWAGA Dobrym pomysłem jest używanie dodatkowych nawiasów  pomagają one lepiej
oznaczyć operatory, które chcesz pogrupować. Pamiętaj, że twoim celem jest pisanie
programów, które nie tylko działają, ale są także łatwe do odczytania i zrozumienia.
Kilka słów na temat prawdy i fałszu
W języku C++ wartość zero jest traktowana jako logiczna wartość false, zaś wszystkie inne
wartości są traktowane jako logiczna wartość true. Ponieważ wyrażenie zawsze posiada jakąś
wartość, wielu programistów wykorzystuje ją w swoich instrukcjach if. Instrukcja taka jak
if(x) // jeśli x ma wartość true (różną od zera)
x = 0;
może być odczytywana jako  jeśli x ma wartość różną od zera, ustaw x na 0 . Jest to efektowna
sztuczka; zamiast tego lepiej będzie, gdy napiszesz:
if (x != 0) // jeśli x ma wartość różną od zera
x = 0;
Obie instrukcje są dozwolone, ale druga z nich lepiej wyraża intencje programisty. Do dobrych
obyczajów programistów należy pozostawienie pierwszej z form dla prawdziwych testów
logicznych (a nie dla sprawdzania czy wartość jest różna od zera).
Te dwie instrukcje także są równoważne:
if (!x) // jeśli x ma wartość false (równą zeru)
if (x == 0) // jeśli x ma wartość zero
Druga z nich jest nieco łatwiejsza do zrozumienia i wyrazniej sugeruje, że sprawdzamy
matematyczną wartość zmiennej x, a nie jej stan logiczny.
TAK NIE
Aby lepiej wyrazić kolejność obliczeń, Nie używaj if(x) jako synonimu dla if(x !=
umieszczaj nawiasy wokół wyrażeń logicznych.
0); druga z tych form jest bardziej czytelna.
Aby uniknąć błędów i lepiej wyrazić
Nie używaj if(!x) jako synonimu dla if(x
przynależność instrukcji else, używaj
== 0); druga z tych form jest bardziej czytelna.
nawiasów klamrowych w zagnieżdżonych
instrukcjach if.
Operator warunkowy (trójelementowy)
Operator warunkowy (?:) jest w języku C++ jedynym operatorem trójelementowym, tj.
operatorem korzystającym z trzech wyrażeń.
Operator warunkowy składa się z trzech wyrażeń i zwraca wartość:
(wyrażenie1) ? (wyrażenie2) : (wyrażenie3)
Tę linię odczytuje się jako:  jeśli wyrażenie1 jest prawdziwe, zwróć wartość wyrażenia2; w
przeciwnym razie zwróć wartość wyrażenia3 . Zwracana wartość jest zwykle przypisywana
zmiennej.
Listing 4.9 przedstawia instrukcję if przepisaną z użyciem operatora warunkowego.
Listing 4.9. Przykład użycia operatora warunkowego
0: // Listing 4.9 - demonstruje operator warunkowy
1: //
2: #include
3: int main()
4: {
5: using namespace std;
6:
7: int x, y, z;
8: cout << "Wpisz dwie liczby.\n";
9: cout << "Pierwsza: ";
10: cin >> x;
11: cout << "\nDruga: ";
12: cin >> y;
13: cout << "\n";
14:
15: if (x > y)
16: z = x;
17: else
18: z = y;
19:
20: cout << "z: " << z;
21: cout << "\n";
22:
23: z = (x > y) ? x : y;
24:
25: cout << "z: " << z;
26: cout << "\n";
27: return 0;
28: }
Wynik
Wpisz dwie liczby.
Pierwsza: 5
Druga: 8
z: 8
z: 8
Analiza
Tworzone są trzy zmienne całkowite: x, y oraz z. Wartości dwóch pierwszych są nadawane przez
użytkownika. Instrukcja if w linii 15. sprawdza, która wartość jest większa i przypisuje ją
zmiennej z. Ta wartość jest wypisywana w linii 20.
Operator warunkowy w linii 23. przeprowadza ten sam test i przypisuje zmiennej z większą z
wartości. Można go odczytać jako: jeśli x jest większe od y, zwróć wartość x; w przeciwnym razie
zwróć wartość y . Zwracana wartość jest przypisywana zmiennej z, zaś jej wartość jest
wypisywana w linii 25. Jak widać, instrukcja warunkowa stanowi krótszy odpowiednik instrukcji
if...else.


Wyszukiwarka

Podobne podstrony:
oiur r04 ver
r04
r04 02 (6)
r04 01 (2)

więcej podobnych podstron