Programowanie w C++ – zmienne, instrukcje warunkowe, strumienie wejścia i wyjścia

Witaj po raz kolejny. To już druga część kursu. Jeżeli nie zapoznałeś się jeszcze z pierwszą – zapraszam Cię do przeczytania artykułu o programowaniu w C++. Dowiesz się z niego między innymi kilku informacji o mnie, czyli kim jestem i dlaczego tworzę ten kurs dla Ciebie, oraz jak zainstalować środowisko programistyczne, które umożliwi Ci pisanie programów w C++.

W tej części kursu zajmiemy się trzema zagadnieniami należącymi do najbardziej podstawowych. Mowa tutaj o deklaracji zmiennych, strumieniach wejścia i wyjścia oraz instrukcjach warunkowych. Bez nich wykonywanie nawet najprostszych czynności byłoby niemożliwe.

Zatem do dzieła!

Typy zmiennych w języku programowania C++

Z definicji zmienna to konstrukcja programistyczna, która umożliwia odwoływanie się poprzez jej nazwę do wartości (dokładniej mówiąc: do miejsca jej przechowywania). Teoria teorią, a w praktyce wygląda to następująco:

Powyższa linijka kodu sprawi, że komputer (po poprawnej kompilacji i uruchomieniu programu) zarezerwuje sobie w komórce pamięci miejsce, które będzie przeznaczone do użytku tylko przez zmienną o nazwie “liczba”. Dodatkowo przypisze w to miejsce ustaloną przez Ciebie wartość liczbową, czyli 15.

W C++ mamy wiele typów danych. Na tym etapie nie musisz znać ich wszystkich, wystarczy zaledwie część. Oto one:

Rodzaje zmiennych C++
Co przechowuje?
boolwartość logiczną false (0) lub true (1)
charpojedynczy znak, np. literę “a”
intliczbę całkowitą
floatliczbę zmiennoprzecinkową, np. 12.83
doubleliczbę zmiennoprzecinkową o większej precyzji

Te pięć powyższych typów danych w zupełności wystarczy Ci przez większość czasu, gdy będziemy się przygotowywać do rozszerzonej matury z informatyki. Warto jednak wspomnieć o jeszcze jednym typie danych:

Rodzaje zmiennych C++
Co przechowuje?
stringciąg znaków, np. “Ala ma kota”.

Łańcuchy znaków to nieco specjalny przypadek, ponieważ jest to obiekt klasy string, a nie standardowa zmienna. Czym jest obiekt, a czym klasa – dowiesz się innym razem. Pojęcia te stosowane są w programowaniu obiektowym. Niestety na rozszerzonej maturze z informatyki umiejętność pisania programów obiektowo nie daje wielu korzyści. Zadania z części programistycznej kładą nacisk na algorytmikę, dlatego na tym my też będziemy się skupiać.

Typy zmiennych C++
Dzięki zmiennym programista może przechowywać informacje, takie jak liczby, tekst czy obiekty, oraz dokonywać operacji na tych danych w trakcie wykonywania programu. Zmienne umożliwiają dynamiczne zarządzanie danymi i są fundamentalnym elementem programowania.

W C++ wszystkie zmienne deklarujemy w ten sam sposób, czyli najpierw podajemy typ zmiennej, a następnie jej nazwę. Przykładowe deklaracje zmiennych:

W pierwszej linijce powyższego kodu widać mój komentarz. Korzystając z okazji, chciałbym o nich również wspomnieć. W C++ mamy dwa podstawowe rodzaje komentarzy: jednowierszowe i wielowierszowe. Ten, użyty przeze mnie to jak możesz się spodziewać – jednowierszowy.

Komentarze stosuje się wtedy, kiedy chcesz ująć jakąś informację w kodzie zarówno dla siebie, żebyś o czymś nie zapomniał, jak i dla innych osób, które mają dostęp (aby ułatwić im zrozumienie programu). Wszystko, co znajduje się w komentarzu, jest pomijane przez kompilator.

Na maturze z informatyki warto stosować komentarze przed każdym z podpunktów, które wykonujemy. Czyli np. pisząc funkcję (więcej o funkcjach w kolejnych częściach), która jest rozwiązaniem na podpunkt pierwszy wybranego zadania, warto umieścić komentarz np. ” // Odp. A”. Dzięki temu osoba, która może zajrzeć do naszego kodu (w tym przypadku egzaminator), będzie miała wszystko “podane na talerzu” 🙂

Komentarze wielowierszowe są stosowane, gdy chce się skomentować większą część kodu. Przykładowo:

W tym momencie wszystko umieszczone pomiędzy znakami “/* */” będzie traktowane jako komentarz, czyli kompilator to po prostu pominie.

Podczas rozwiązywania zadań maturalnych komentarze wielowierszowe pełnią bardzo ważną rolę – to dzięki nim możesz w łatwy sposób zweryfikować, dlaczego Twój program nie działa, tak jak powinien. Przez komentowanie kolejnych części kodu możesz bardzo szybko dojść do sedna problemu i trafić na linijkę, w której program się przysłowiowo “sypie”.

Odnosząc się do fragmentu kodu, w którym pokazywałem, jak można deklarować zmienne o różnych typach danych, wspomniałem tam o różnicy między cudzysłowem a apostrofem. Otóż jeżeli chcesz użyć łańcucha znaków, zawsze stosuj cudzysłów. Natomiast jeżeli zamierzasz wykorzystać konkretny znak, używaj apostrofu. To drobna różnica, jednak nie można o tym zapomnieć, by uniknąć niepotrzebnych błędów kompilacji.

ads banner

Strumienie wejścia i wyjścia w C++

Pod tą dziwną nazwą kryje się coś bardzo oczywistego. Dzięki bibliotece “iostream” możesz skorzystać z gotowych funkcji obsługi strumieni. W Code::Blocks biblioteka jest dodawana automatycznie i wygląda to tak:

Powyżej widzisz klasyczną metodę dodania biblioteki do programu. W ten sam sposób będziesz dodawać wiele innych bibliotek, które będą zawierać kolejne, bardzo przydatne funkcje.

Co prawda istnieją również biblioteki takie jak std::istream oraz std::ostream, gdzie pierwsza z nich odpowiada za wczytywanie danych (wejście), a ta druga za ich wypisywanie (wyjście). Jednak częściej wykorzystywana jest std::iostream ze względu na to, że łączy obie te funkcje, a więc cechuje się większą uniwersalnością.

Obsługa strumienia wejścia to nic innego, jak np. umożliwienie użytkownikowi wpisywania wartości do programu. Przykładowe użycie:

Wykonanie tej linijki spowoduje, że w konsoli pojawi się migający kursor – program będzie czekał na podanie przez użytkownika wartości. Po wpisaniu liczby i kliknięciu enter, program przejdzie do kolejnej części kodu. Strumień wejścia obsługiwany jest przez użytą funkcję “cin”. Zwróć proszę uwagę na kierunek znaków “>>” – początkujący programiści często o tym zapominają i dziwią się, dlaczego kompilator zwraca błąd, gdy piszą je na odwrót: “<<” 🙂

Obsługa strumienia wyjścia to analogicznie, wyświetlanie informacji na ekranie. Używa się do tego funkcji “cout”. Przykład:

Jeżeli zmienna liczba przechowuje wartość 15, efekt wywołania tej linijki kodu to wypisanie w konsoli: “Wartosc zmiennej to 15”. Ważne! Wszystkie teksty umieszczaj w cudzysłowie. Jeżeli chcesz wydobyć wartość zmiennej, to rób to bez cudzysłowów. Dla przykładu:

Linijka ta wypisze “Wartosc zmiennej to: liczba”, czyli nie osiągniesz planowanego rezultatu. Zwróć uwagę na sposób połączenia tekstu i zmiennej, czyli na łącznik “<<“. W ten sposób można łączyć wyświetlane teksty. Używa się tego, gdy chcesz (tak jak w tym przypadku) wyświetlić kawałek tekstu, a następnie wartość zmiennej.

Wcześniej opisane strumienie, czyli cin oraz cout, to tak zwane strumienie predefiniowane, czyli już wcześniej przygotowane do użytku.

Istnieje także strumień std::cerr (error stream), który służy do wypisywania błędów (skierowany jest na konsolę błędów stderr). Dzięki temu można łatwiej kontrolować pracę swojego programu i określanie, w których momentach występuje określony błąd, a więc co należy naprawić. Przykład użycia tego strumienia to:

Warto wiedzieć o kilku domyślnie ustawionych parametrach dotyczących tych strumieni. Jeśli chodzi o cout, w części kompilatorów jeśli zechcesz wyświetlić liczby zmiennoprzecinkowe, to ukazane zostanie do 6 miejsc po przecinku. O tym jak to zmienić, dowiesz się w dalszej części artykułu.

Z kolei jeśli chodzi o cin, to trzeba pamiętać o tym, że ten strumień ignoruje białe znaki (przykładowo spacja) znajdujące się przed ciągiem znaków, a jednocześnie za koniec frazy uznaje pierwszy biały znak po wpisywanym wyrazie. Czyli po wpisaniu do strumienia wejścia zdania “drzewo jest wysokie”, wczytane zostanie tylko “drzewo”.

Instrukcje warunkowe C++

Mówiąc o instrukcjach warunkowych, użyjesz dopiero co zdobytej wiedzy z zakresu deklarowania i używania zmiennych oraz obsługi strumieni wejścia i wyjścia. Jak sama nazwa wskazuje, instrukcja warunkowa to pewnego rodzaju sprawdzenie. Na przykład możesz sprawdzić, czy dana zmienna przechowuje wartość większą niż 10. W C++ do instrukcji warunkowych używa się funkcji if. Przykład użycia:

Wydaje mi się, że powyższy kod jest na tyle jasny, że nie ma potrzeby komentowania, co się wydarzy. Jeżeli jednak nie jesteś pewien – skopiuj kod do Code::Blocks i zobacz efekt!

Dodatkowo pamiętaj, że po użyciu instrukcji warunkowej if, nie musisz umieszczać klamer {} jeśli wykonywane jest tylko jedno polecenie tak jak powyżej. Jeśli jednak jest ich więcej, to konieczne jest ich umieszczenie pomiędzy klamrami (przykład ich użycia znajdziesz w kolejnych przykładach).

Dobrze, opisano jak coś sprawdzić, a co w sytuacji, gdy chcesz wykonać daną czynność, gdy zmienna NIE będzie spełniać sprawdzanego warunku? Teoretycznie, można to zrobić w ten sposób:

Jednak jest na to prostszy sposób, a mianowicie użycie klauzuli “else”. Funkcja ta wykonuje się za każdym razem, gdy sprawdzany przez nas warunek okazał się niespełniony. Użycie funkcji:

Jest to po prostu forma skrótu. My, programiści, bardzo lubimy skróty 🙂

Funkcja warunkowa
Instrukcja warunkowa if-else, pozwala na wykonanie różnych fragmentów kodu w zależności od spełnienia warunku. Jest to fundamentalna struktura kontrolna, która umożliwia programowi podjęcie decyzji w trakcie jego wykonywania.

Prócz powyższej formy instrukcji warunkowej, możliwe jest również użycie jej w ramach “warunek ? dzialanie1 : dzialanie2”. To tzw. operator trójargumentowy (warunkowy), wykorzystywany w C++. Pozwala na skrócenie objętości kodu, a dla wprawionej osoby okazuje się wygodniejszy. Przykład użycia prezentuje się następująco:

Mówiąc o instrukcjach warunkowych w C++, należy wspomnieć o spójnikach, jakich można używać do łączenia warunków (operatorach logicznych). Używa się ich, jeżeli chcesz np. aby spełniony został jeden ORAZ drugi warunek. Inny przykład, to jeżeli chcesz, aby wykonał się jeden LUB drugi warunek. Pamiętaj, że w niektórych przypadkach istotna jest ich kolejność (np. sprawdzając w warunku długość tablicy oraz konkretne jej elementy). W praktyce wygląda to następująco:

  • && – or – ORAZ
  • || – and – LUB

Proszę nie mylić spójnika LUB (określany również jako alternatywa nierozłączna) z ALBO (zwany alternatywą rozłączną)! Gdy używasz LUB to jeżeli więcej niż jeden warunek jest spełniony – wynik wyrażenia logicznego to prawda. W przypadku użycia spójnika ALBO, jeżeli więcej niż jeden warunek jest spełniony – wynikiem końcowym wyrażenia będzie fałsz. W C++ wygląda to następująco:

Ostatnia rzecz, o której dzisiaj chcę Wam powiedzieć to instrukcja wielokrotnego wyboru, czyli switch-case. Zacznę od przedstawienia przykładu użycia.

Powyżej zaprezentowane wyrażenie switch-case pobiera (w trzeciej linijce kodu) parametr, czyli to, co zostało podane w nawiasach. Jak widzisz, w tym przypadku jest to zmienna “liczba”. To oznacza, że funkcja switch będzie sprawdzać wartość tej zmiennej przez przypadki (case), które zostały podane.

Czyli, jeżeli zmienna ma wartość 1, to wykona się “case 1:”, jak 2 to “case 2:”, a jak nie będzie miała wartości ani 1 ani 2, to wykona się przypadek “default:”.

Bardzo ważne jest używanie instrukcji “break”. Będziesz ją stosować wielokrotnie, podczas nauki działań na pętlach. Instrukcja break powoduje przerwanie trwającej instrukcji sterującej (w tym przypadku instrukcja switch-case). Jeżeli dany case się wykonuje, to break oznacza, że wszystko, co miało się wykonać, już się wykonało, a program powinien przejść do kolejnych linijek kodu (za switch-case).

W praktyce, gdybyś nie napisał funkcji break, to kod wyglądałby następująco:

Gdy użytkownik podałby wartość 1, to wynikiem programu, który by się pojawił w konsoli, byłby napis:

Liczba ma wartosc 1 Liczba ma wartosc 2 Liczba nie ma wartosci 1 ani 2

Jak widzisz, wykonały się wszystkie trzy case. Na końcu każdego wywołania funkcji cout moglibyśmy dopisać “<< endl” i wówczas po każdym zdaniu pojawiłby się enter.

Obsługa wyjątków i błędów w C++ – dla ambitnych

Jest to niezwykle istotna kwestia, która może pomóc uchronić się przed nieprzewidzianymi sytuacjami, gdzie przykładowo wprowadzono nieprawidłowe dane. Błędy oraz wyjątki można obsłużyć za pomocą wyrażeń try-catch, która w momencie wykrycia odpowiedniego komunikatu o błędzie przerywa działanie kodu i zaczyna działać odpowiedni blok catch.

Dodatkowo można samodzielnie użyć wyrażenia throw, która służy do sygnalizacji programowi wystąpienia konkretnego wyjątku. Przykładowo “throw std::runtime_error(“Dzielenie przez zero jest niedozwolone”);”.

Natomiast schemat wyrażenia try-catch prezentuje się tak:

Najczęstsze błędy, które możesz obsłużyć w ramach try-catch to:

  • std::ios_base::failure – gdy wystąpi błąd wejścia-wyjścia, przykładowo problem z otwarciem pliku.
  • std::invalid_argument – funkcja może zwrócić ten komunikat, jeśli przekazane do niej argumenty są nieprawidłowe,
  • std::out_of_range – gdy wartość znajduje się poza zakresem dozwolonych wartości, funkcja zwraca ten wyjątek,
  • std::bad_alloc – problem z alokacją pamięci w funkcji,
  • std::runtime_error – próba wykonania operacji, która jest niemożliwa do zrealizowania przez nieprawidłowe dane lub warunki.

Strumienie wejścia i wyjścia – dla ambitnych

Przy poszerzaniu wiedzy na temat strumieni wejścia i wyjścia, można zapoznać się z wieloma funkcjami, jedną z bardziej istotnych jest metoda pozwalająca na pobieranie tekstu razem ze spacjami. Getline pozwala na wprowadzanie całej linii za pomocą cin razem z białymi znakami (standardowo pobierany tekst zakańczany jest na pierwszym białym znaku, czyli zazwyczaj spacji). Schemat funkcji getline prezentuje się następująco:

Po umieszczeniu tej linijki w kodzie, konsola pobierze od użytkownika tekst i zapisze go do zmiennej string o nazwie “zmienna_tekst”. Standardowo pobierany jest tekst aż do znaku nowej linii (czyli \n), możliwe jest ustalenie innego znaku końcowego, poprzez dodanie kolejnego argumentu do tej funkcji o typie char.

W celu zmiany parametrów strumieni wejścia i wyjścia można zmieniać ich flagi. W tym celu można skorzystać z funkcji setf(flaga, grupa), która nie tylko doda nową flagę, ale jednocześnie też wyzeruje inne flagi z danej grupy. Istnieje również metoda unsetf, której zadaniem jest wyłączenie flagi.

Konieczne może jednak być ograniczenie szerokości pola z pomocą setw(20), żeby flaga justowania mogła zadziałać prawidłowo. Przykład znajdziesz poniżej:

Jedne z najbardziej użytecznych flag znajdziesz poniżej.

W grupie adjustfield:

  • left – justowanie do lewej,
  • right – justowanie do prawej,
  • internal – justowanie do krawędzi ekranu.

W grupie basefield:

  • dec – wypisywanie i wczytywanie liczb w systemie dziesiętnym,
  • oct – w systemie ósemkowym,
  • hex – w systemie szesnastkowym.

Z kolei dzięki metodzie precision(liczba), można określić, ile liczb po przecinku ma być wyświetlanych. Jest to stała zmiana, póki ponownie nie zmieni się tego parametru za pomocą tej metody. Przykład:

Przy wykorzystaniu samego precision:

Jak widać, sama instrukcja precision wpływa na ogólną ilość wyświetlanych liczb (przed oraz po przecinku), natomiast wspólnie z fixed, chodzi o liczbę znaków tylko po przecinku.

Podsumowanie

Postarałem się wytłumaczyć wszystko możliwie najprostszymi słowami. Zmienne, strumienie wejścia i wyjścia oraz instrukcje warunkowe w C++ to absolutne podstawy, które umożliwią Ci dalszą naukę programowania i przygotowania do matury z informatyki. Może się to wydawać bardzo proste – jeżeli tak jest to naprawdę świetnie. Mimo wszystko bardzo proszę o wykonanie poniższych zadań domowych.

Pamiętaj, że zawsze możesz się umówić na indywidualne lub grupowe zajęcia w formie korepetycji z informatyki. Jest to o tyle fajne, że mogę udzielić odpowiedzi na każde z Twoich pytań. W razie czego – kontakt znajdziesz tutaj.

Praca domowa

  • Napisz program, który poprosi użytkownika o podanie liczby komunikatem “Prosze wpisz liczbe i kliknij enter”. Po wpisaniu przez użytkownika liczby niech program sprawdzi, czy liczba jest z zakresu [0, 9]. Jeżeli tak: niech wyświetli “To jest cyfra!”. W przeciwnym przypadku niech wypisze “Podana przez Ciebie liczba to: “, i tutaj wartość wpisanej przez użytkownika liczby.
  • Napisz program obliczający średnią prędkość, z jaką poruszał się samochód na trasie. Aby to zrobić, pobierz od użytkownika dwie wartości: drogę, jaką samochód przebył oraz czas przejazdu. Następnie przy użyciu wzoru v = s/t oblicz wartość średniej prędkości.
    Uwaga! Pamiętaj, że podawane przez użytkownika zmienne oraz otrzymywany wynik nie muszą być liczbami całkowitymi! Uwzględnij to w swoim programie.
  • Napisz program, który poprosi użytkownika o podanie dowolnego jednego znaku. Przy użyciu instrukcji switch-case sprawdź, czy jest to któraś z pierwszych 6 liter alfabetu angielskiego. Jeżeli tak – wypisz tę literę. W przeciwnym wypadku wypisz “Litera zawarta jest w dalszej czesci alfabetu.” w ramach default i zakończ program.

Najczęściej zadawane pytania o zaawansowane strumienie wejścia i wyjścia w C++

Jak działa tryb binarny w strumieniach wejścia i wyjścia w C++?

Wystarczy użyć objaśnionej wcześniej funkcji setf do ustawienia flagi ios::binary. Dzięki temu zdołasz odczytywać oraz wysyłać do wyjścia dane binarne, co może się przydać w określonych sytuacjach, przykładowo gdy operuje się na różnego rodzaju plikach binarnych, czy w ramach komunikacji sieciowej.

Jak działa przeciążanie operatorów << i >> w C++?

Ogółem przeciążanie operatorów pozwala na naturalne używanie >>, <<, a także wszelkiego rodzaju innych znaków jak choćby + i – w odniesieniu do obiektów klas. Jest to konstrukcja stosowana w takich językach jak Python, C# czy właśnie C++.

Normalnie gdy wypisuje się jakąś zmienną, to strumień wyjścia wie, jak to zrobić, skoro zna typ wartości. Jednak co w przypadku klas, gdzie znajdują się rozmaite atrybuty (czyli zmienne)? Można ręcznie ustalić, co ma być wyświetlane, w momencie gdy wypisuje się obiekt konkretnej klasy.

Przykładowo gdyby zadeklarować sobie nowy typ Osoba, gdzie znajdują się zmienne takie jak Imie i Nazwisko można przeciążyć operator << w taki sposób, żeby po użyciu cout było wypisywane imię oraz nazwisko zapisane w tym obiekcie lub coś jeszcze innego, zależnie od Twojej decyzji.

Przeciążanie operatorów jest więc wygodnym rozwiązaniem, dzięki któremu możesz usprawnić używanie obiektów w ramach danego programu. Jest to polecane w przypadku długich kodów, gdzie pozwala to zaoszczędzić miejsce.

Co to są manipulatory strumieniowe i jak ich używać w C++?

Są to specjalne funkcje, dzięki którym zdołasz kontrolować formatowanie wyjścia strumienia. Pozwalają między innymi na zmianę szerokości wyjścia, wycentrowanie tekstu, czy zmianę wyświetlania liczb. Ich działanie może wydawać się podobne do opisanych wcześniej funkcji setf oraz unsetf, jednak nie są to manipulatory strumieniowe, bo zapewniają one tylko uruchamianie lub wyłączanie flag formatowania. Przykłady manipulatorów strumieniowych, o jakich warto wiedzieć to:

  • endl – czyści bufor i ustawia nową linię,
  • setprecision – zmiana precyzji zmiennoprzecinkowej,
  • setw – konfiguracja szerokości pola wyjścia,
  • flush – opróżnia bufor wyjściowy strumienia.
ads banner

Wpisy, które mogą Cię zainteresować: