Programowanie - C++

C++ – Cześć 8 kursu C/C++

8. Operacje logiczne

O ile w przypadku operacji artymetycznych wynikiem mogła być dowolna liczba (oczywiście z określonego zakresu), to wynikiem operacji logicznej jest jeden z dwóch możliwych stanów – prawda lub fałsz . W języku C za fałsz uznaje się liczbę zero, natomiast wszystkie pozostałe są uznawane za prawdę . Wynikiem takiego traktowania stanów logicznych jest możliwość używania kompaktowych wersji porównań logicznych, co zobaczymy w następnej części tego punktu.

8.1. Porównania

W tym podpunkcie przedstawię je tylko, natomiast przykłady ich wykorzystania zostaną zaprezentowane w następnym podpunkcie. W języku C mamy następujące operatory porównania:

C

Pascal

Opis

>

>

większe niż

<

<

mniejsze niż

>=

>=

większe lub równe

<=

<=

mniejsze lub równe

==

=

równe (zwróć uwagę na podwójny znak równości)

!=

<>

nie równe

8.2. Instrukcja if

Instrukcja ta jest istotnym elementem każdego programu, ponieważ pozwala ona na modyfikację sposobu, w jaki działa program w zależności od wartości danych. W języku C, podobnie jak w Pascalu, ma ona następującą składnię:

if(wyrażenie) wyrażenie1 else wyrażenie2

Jeśli wyrażenie w nawiasie ma wartość logiczną prawda to zostanie wykonane wyrażenie1, w przeciwnym wypadku zostanie wykonane wyrażenie2. Przykładowo:

if( a > 10 ) printf(„Zmienna a jest większa od dziesięciu !”); else printf(„Zmienna a jest mniejsza lub równa dziesięć !”);

Zauważ, że zarówno wyrażenie po if , jak i wyrażenie po else jest zakończone średnikiem. Uwagę tą kieruję szczególnie do osób znających Pascala, w którym średnik stawia dopiero na samym końcu. Oczywiście, tak jak w Pascalu, części „else” możesz w ogóle nie używać, jeśli nie jest Ci to akurat potrzebne. Czyli możesz napisać tak:

if( a > 10 ) printf(„Zmienna a jest większa od dziesięciu !”);

Jeśli chcesz wykonać kilka instrukcji jeśli spełniony jest pewien warunek to musisz je zawrzeć w bloku ograniczonym znakami { i } . Czyli wyglądałoby to następująco:

if( a > 10 ) {

printf(„Zmienna a jest wieksza od dziesięciu !
„);

printf(„Jest bowiem równa %d.”, a);

} else {

printf(„Zmienna a jest mniejsza lub równa dziesięć !
„);

if(a != 5) printf(„Jednak nie jest równa pieć !”);

}

Oczywiście to, jak sformatujesz ten tekst (np. możesz znak rozpoczynający blok wpisań w nowej linii) zależy tylko od Ciebie. Ja jednak preferuję taki sposób, według mnie jest to bardziej czytelne.

Pozostała do omówienia jeszcze jedna rzecz dotycząca instrukcji if , a związana z traktowaniem przez język C wartości logicznych. Zamiast:

if ( a != 0 ) printf(„a jest rozne od zera”);

możemy napisać:

if( a ) printf(„a jest rozne od zera”);

i będzie to działało w identyczny sposób. Jak myślisz dlaczego ? Jeśli przeczytałeś uważnie wstęp do operacji logicznych to nie powinieneś mieć większych problemów z odpowiedzią na to pytanie. W pierwszym przypadku mamy do czynienia z porównaniem wartości zmiennej a do zera. Przykładowo, jeśli zmienna a jest równa dziesięć to warunek „a != 0” zwróci prawdę do instrukcji if i zostanie wyświetlony na ekranie tekst. Natomiast co z drugim przypadkiem ? Nie mamy tu do czynienia z żadnym porównaniem, do instrukcji if jest od razu przekazywana wartość zmiennej a, czyli w naszym przypadku dziesięć. Zauważ, nie prawda , nie fałsz , ale liczba dziesięć ! I co się stanie teraz ? Po prostu na ekranie pojawi się tekst. Pamiętasz jak język C traktuje wartości logiczne ? Stanowi fałsz odpowiada liczba zero, natomiast stanowi prawda każda inna wartość. Czyli także liczba dziesięć ! Tak więc liczba ta zostanie potraktowana jako stan prawda i w wyniku tego zostanie wykonana odpowiednia instrukcja (blok instrukcji) – w naszym przypadku zostanie wywołana funkcja printf .

Na zakończenie tego punktu zamieściłem jeszcze przykład często popełnianego błędu (który na dodatek bardzo trudno jest zlokalizować), związanego z właśnie takim traktowaniem stanów logicznych przez język C:

if( a = 0 ) printf(„a jest równe zero”);

else printf(„a jest różne od zera”);

Jak myślisz, co zostanie wyświetlone na ekranie, jeśli powiem Ci, że zmienna a jest równa zero ? Jeśli odpowiesz, że będzie to „a jest równe zero” to niestety nie będziesz miał racji. Możesz zapytać: „Ale dlaczego ? Przecież mamy porównanie a do zera i ponieważ a jest równe zero, to powinien wyświetlić się pierwszy napis.”. Miałbyś rację, jeśli naprawdę byłoby tam porównanie. Jednak przyjrzyj się uważnie – tam nie ma porównania ! Porównanie w języku C to podwójny znak równości, natomiast pojedynczy (tak jak jest w tym przypadku) oznacza przypisanie. Tak więc najpierw zostanie tu przypisana wartość zero do zmiennej a, a następnie (tak jak w poprzednim przykładzie) wartość tej zmiennej zostanie przekazana do instrukcji if , która potraktuje ją jako fałsz (bo zero właśnie to oznacza) i w efekcie wywoła funkcję printf występującą po else .

8.3. Podstawowe operacje logiczne

W podpunkcie tym przedstawię cztery podstawowe operacje logiczne – OR, AND, NOT i XOR. Jeśli wiesz na jakiej zasadzie one działają to możesz przejść do następnego podpunktu. Zero w tabeli odpowiada stanowi fałsz , natomiast jedynka odpowiada stanowi prawda .

Operacja OR (lub)

Wejście

Wyjście

0

0

0

1

0

1

0

1

1

1

1

1

Wynikiem operacji OR jest zero, gdy oba argumenty są równe zero, lub jedynka w przeciwnym wypadku.

Operacja AND (i)

Wejście

Wyjście

0

0

0

1

0

0

0

1

0

1

1

1

Wynikiem operacji AND jest jedynka, gdy oba argumenty są równe jeden, lub zero w przeciwnym wypadku.

Operacja XOR

Wejście

Wyjście

0

0

0

1

0

1

0

1

1

1

1

0

Wynikiem operacji XOR jest jedynka, gdy tylko jeden z argumentów jest równy jeden, lub zero w przeciwnym wypadku.

Operacja NOT

Wejście

Wyjście

0

1

1

0

Wynikiem operacji NOT jest jedynka, gdy argument był równy zero, lub zero, gdy argument był równy jeden.

8.4. Operacje logiczne w języku C

Przedstawione w poprzednim punkcie operacje mają w języku C dwa aspekty – logiczny i arytmetyczny (operacje na bitach). Co prawda drugi z nich należałoby przedstawić już wcześniej, przy okazji omawiania operacji arytmetycznych, jednak zrobię to dopiero w tym punkcie z uwagi na podobieństwo. Najpierw jednak skupmy się na pierwszym aspekcie. Oto jak operacje logiczne zapisujemy w języku C:

Operacja

C

Pascal

OR

||

or

AND

&&

and

NOT

!

not

Ponieważ o wiele łatwiej jest uczyć się na przykładach, podam teraz program, który zilustruje wykorzystanie poznanych operacji logicznych.

#include <stdio.h>

void main(void)

{

int a = 17;

// przykład użycia operacji logicznej OR

if( (a 10) ) {

printf(„Zmienna a jest mniejsza od pięciu _lub_ większa od dziesięciu.

„);

}

// przyklad użycia operacji logicznej AND

if( (a 10) && (a

Ponieważ początek programu nie wymaga chyba komentarza (jeśli wymaga to cofnij się, proszę, do poprzednich punktów), analizę naszego programu zaczniemy od linijki z pierwszym wystąpieniem instrukcji if .

W naszym przypadku chcemy wykonać jakieś działanie (wyświetlenie tekstu na ekranie), gdy zmienna a jest mniejsza od pięciu lub też większa od dziesięciu. Idealnie do tego celu nadaje się operacja logiczna OR , której używa się, gdy chcemy sprawdzić czy chociaż jeden z podanych warunków jest prawdziwy . Widzimy, że mamy tu dwa porównania – pierwsze (a < 5) , dla zmiennej a równej siedemnaście zwraca fałsz , jednak drugie (a > 10) , zwraca prawdę (bo 17 > 10). Operacja logiczna OR dla takich parametrów zwraca prawdę (zobacz w tabeli przedstawionej powyżej), tak więc zostanie wyświetlony na ekranie odpowiedni tekst. Zapamiętaj więc – jeśli chcesz sprawdzić, czy którykolwiek z warunków jest spełniony, użyj operacji OR.

W sytuacji, gdy wykonanie działania ma zależeć od spełnienia wszystkich warunków, używamy natomiast instrukcji logicznej AND . Pokazane jest to przy okazji następnej instrukcji if . W tym wypadku chcemy wykonać działanie tylko wtedy, gdy zmienna a jest większa od dziesięciu i mniejsza od dwudziestu (czyli zawiera się w określonym przedziale). Pierwszy warunek (a > 10) , dla zmiennej a równej siedemnaście zwraca prawdę , drugi (a < 20) także zwraca prawdę . Patrząc do tabeli widzimy, że w takim przypadku wynikiem operacji AND jest prawda , więc na ekranie zostanie wyświetlony tekst o tym informujący. Zapamiętaj więc – jeśli chcesz wykonanie działania uzależnić od spełnienia wszystkich warunków, użyj operacji AND.

Przejdźmy teraz do omówienia ostatniej, najprostszej operacji logicznej, a mianowicie NOT . Jest ona po prostu negacją (zaprzeczeniem) danego parametru – tzn. że dla parametru prawda zwróci fałsz, natomiast dla parametru fałsz zwróci wartość prawda. Pokazuje to wyraźnie trzecia z instrukcji if w naszym programie. Warunek (a < 10) jest sformułowany tak, że dla zmiennej a równej siedemnaście, zwróci fałsz , czyli normalnie tekst nie zostałby wyświetlony na ekranie. Jednak w naszym przypadku występuje jeszcze negacja, która „zamienia” fałsz na prawdę i w efekcie na ekranie pojawi się odpowiedni napis.

8.5. Operacje na bitach

Pozostało jeszcze do omówienia zastosowanie poznanych operacji logicznych do wykonywania działań na bitach. Do zrozumienia (i wykorzystania w swoich programach) podanych w tym punkcie informacji konieczna będzie znajomość podstaw dwójkowego systemu zapisu liczb. Jeśli nie wiesz co to takiego to sugeruję, żebyś pominął teraz ten punkt i powrócił do niego po zaglądnięciu do książki z matematyki (ja to miałem w 7 lub 8 klasie podstawówki, teraz to chyba będzie w gimnazjum). Najpierw przedstawię operatory języka C stosowane do operacji na bitach:

Operacja

C

Pascal

OR

|

or

AND

&

and

XOR

^

xor

NOT

~

not

Wszystkie przedstawione w tabeli operacje mają taką samą zasadę działania. Pierwsze trzy operują na dwóch argumentach, natomiast ostatnia tylko na jednym. Algorytm działania tych pierwszych wygląda tak:

1. Najpierw zamieniasz oba argumenty na postać binarną.

2. Teraz bierzesz zerowe bity obu argumentów i wykonujesz odpowiednią operację logiczną

3. To, co otrzymałeś zapisujesz w zerowym bicie wyniku.

4. Punkty dwa i trzy wykonujesz kolejno dla pierwszego, drugiego, itd. bitu argumentu.

Natomiast algorytm działania operacji NOT jest dużo prostszy – po prostu neguje ona wszystkie bity argumentu. Czyli w efekcie tam, gdzie były zera, teraz będą jedynki i odwrotnie.

Być może nie zrozumiałeś wszystkiego z powyższego opisu. Jednak nie martw się – wszystko się wyjaśni przy analizie przykładowego programu:

#include <stdio.h>

void main(void)

{

char a=12, b=9;

printf(„%d and %d = %d
„, a, b, a & b);

printf(„%d or %d = %d
„, a, b, a | b);

printf(„%d xor %d = %d
„, a, b, a ^ b);

printf(„not %d = %d
„, b, ~b);

}

Każde z wywołań funkcji printf prezentuje inny operator. Zacznijmy od operacji AND.

Jak widzisz wykonujemy operację AND na dwóch argumentach – zmiennej a równej dwanaście i zmiennej b równej dziewięć. Po zapisaniu tego w postaci dwójkowej wygląda to następująco:

1100 (12 w systemie dziesiętnym)

AND

1001 (9 w systemie dziesiętnym)

====

1000 (8 w systemie dziesiętnym)

Na podstawie algorytmu działania przedstawionego powyżej pokażę w jaki sposób otrzymaliśmy w efekcie liczbę osiem. Najpierw zamieniamy obie liczby na postać binarną. Dla lepszego zobrazowania zapisałem je jedna nad drugą. Bierzemy teraz zerowy (ten z prawej) bit pierwszej liczby (12) – jest on równy zero. Następnie bierzemy zerowy bit drugiej liczby (9) – jest on równy jeden. Wykonujemy operację AND na tych danych – w efekcie otrzymujemy zero (zobacz w tabeli dla operacji AND), którą to zapisujemy jako zerowy bit wyniku. Teraz to samo wykonujemy dla pierwszych bitów obu liczb. Tym razem oba są równe zero, więc w wyniku także otrzymujemy zero. Następnie wykonujemy operację dla bitów numer trzy obu liczb. Wynikiem działania dla argumentów równych jeden i zero jest ponownie zero. Dokonujemy tej samej operacji dla bitów numer cztery obu liczb – w efekcie wykonania operacji AND na obu argumentach równych jeden, otrzymujemy jedynkę. Wynikiem całej operacji jest więc liczba 1000 w systemie dwójkowych. Liczba ta w systemie dziesiętnym jest równa osiem i właśnie ona zostanie wyświetlona na ekranie.

Następną operacją jest operacja OR . Po zapisaniu jej podobnie jak poprzednio otrzymujemy:

1100 (12 w systemie dziesiętnym)

OR

1001 (9 w systemie dziesiętnym)

====

1101 (13 w systemie dziesiętnym)

Algorytm działania jest identyczny jak poprzednio, tylko zamiast operacji AND wykonujemy operację OR. Wynikiem tej operacji jest jedynka, gdy którykolwiek z argumentów jest jedynką, stąd też tylko dla bitu pierwszego otrzymaliśmy zero, a reszta bitów jest równa jeden.

Przedostatnią operacją jest XOR :

1100 (12 w systemie dziesiętnym)

XOR

1001 (9 w systemie dziesiętnym)

====

0101 (5 w systemie dziesiętnym)

I znowu wykonujemy identyczne operacje, zamieniając tylko operację na XOR. Dla przypomnienia – wynikiem tej operacji jest jedynka, gdy tylko jeden z argumentów jest równy jeden.

Ostatnią operacją jest operacja NOT . Jak zapewne zauważyłeś po uruchomieniu programu, wynikiem operacji NOT 9 jest liczba minus dziesięć, którą binarną reprezentacją jest 11110110. A oto jak ją otrzymaliśmy:

NOT

00001001 (9 w systemie dziesiętnym)

========

11110110 (-10 w systemie dziesiętnym)

Jest to najprostsza z operacji logicznych – ja widać odwraca po prostu wszystkie bity argumentu.