Struktura programu w C++
Najlepszym sposobem nauki programowania jest nauka poprzez pisanie/analizowanie programów. Naukę rozpoczniemy od klasyka - programu "Hello, World!", który wyświetla ten napis na ekranie komputera.
/* Program P1 - Hello World!
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
cout << "Hello, World!" << endl; //wypisuje ciąg znaków Hello, World! na ekran
return 0;
}
Linie 1-2:
/* Program P1 - Hello World!
* Wykonał Paweł Malinowski */
/* i */ - oznacza komentarz wieloliniowy. Wszystko co jest zapisane pomiędzy /* i */ jest traktowane jako komentarz i nie ma żadnego wpływu na zachowanie się programu. Programiści używają komentarzy w celu ułatwienia sobie pracy, poprzez komentowanie co w danym bloku kodu wykonują, jakie deklarują zmienne, itp. W tym przypadku komentarz dotyczy informacji o nazwie programu i jego autorze.
Linia 3:
Linia pusta
Linie takie nie mają żadnego wpływu na działanie programu. Używane są w celu poprawy czytelności kodu.
Linia 4:
Linie zaczynające się od znaku # są dyrektywami interpretowanymi przez preprocesor. Linie te są interpretowane zanim nastąpi kompilacja programu. W tym przypadku dyrektywa #include <iostream> przekazuje do preprocesora informację o dołączeniu do programu nagłówka biblioteki iostream, dzięki temu możemy wykonywać standardowe operacje wejścia/wyjścia, takie jak wypisanie na ekranie (Hello, World!).
Linia 6:
using namespace std;
Dyrektywa using udostępnia lokalnie całą zawartość standardowej przestrzeni nazw std. W standardowej przestrzeni nazw znajduje się obiekt cout, który wykorzystujemy w tym programie do wyświetlenia łąńcucha znaków "Hello, World!" na ekran. Więcej informacji o przestrzeniach nazw znajduje się w rozdziale Zasięg/przestrzenie nazw.
Linia 8:
int main( )
Linia ta inicjuje deklarację funkcji głównej (main). Funkcja to inaczej zestaw instrukcji, który posiada swoją nazwę - w tym przypadku main. Na początku każdej funkcji wpisujem typ danych, który funkcja zwraca, następnie podajemy jej nazwę, a w nawiasach podajemy argumenty funkcji (opcjonalnie). Więcej informacji o typach danych znajduje się w rozdziale Zmienne i typy danych. Więcej o funkcjach znajduje się w rozdziale Funkcje.
Linie 9 i 13:
{ , }
Nawias otwierający { wskazuje początek definicji funkcji głównej, nawias zamykający } oznacza koniec definicji funkcji. Wszystko pomiędzy tymi nawiasami to ciało funkcji, gdzie zdefiniowane jest, co się wydarzy po wywołaniu funkcji.
Linia 10:
cout << "Hello, World!" << endl; //wypisuje ciąg znaków Hello, World! na ekran
Ta linia jest instrukcją języka C++. Każda instrukcja jest to część kodu, która daje zamierzony efekt. Instrukcje wykonywane są w takim samym porządku jak są zapisane w kodzie programu. Obiekt cout character output z biblioteki iostream wskazuje urządzenie wyjścia (monitor komputera), na który wysyła łańcuch znaków "Hello, World!". << oznacza wysłanie danych do strumienia wyjściowego. Symbole wskazują kierunek przepływu informacji. endl (end line) - jest to manipulator, którego zadaniem jest zakończenie obecnej linii i przejście do nowej linii. Znaki // - oznaczają komentarz jednoliniowy.
Linia 12:
return 0;
Każda funkcja, gdzie przed nazwą występuje typ danych np. int, float, char, string, itp. z wyjątkiem void musi zwrócić po zakończeniu swojego działania dane z takim typem jak przy deklaracji funkcji. Funkcja main deklarowana była jako int main(), dlatego musi zwrócić liczbę całkowitę int - return 0.
Każda instrukcja w C++ kończy się znakiem ;. Średnik oznacza koniec każdej instrukcji. Dzięki niemu kompilator wie, gdzie instrukcja się zaczyna i gdzie kończy. Jednym z najczęściej popełnianych błędów na początku nauki programowania w C++ jest brak średnika na koncu każdej instrukcji.
Ten sam program można również napisać bez używania wcięć w kodzie, umieszczania instrukcji w osobnych liniach. Działanie programu jest identyczne, natomiast czytelność kodu źródłowego jest bardzo zła.
/* Program P1 - Hello World!* Wykonał Paweł Malinowski */#include <iostream>
using namespace std;int main(){cout << "Hello, World!" << endl; //wypisuje ciąg znaków Hello, World! na ekran
return 0;}
Zadania do wykonania
- Napisz program wypisujący w oddzielnych liniach Twoje imię, nazwisko, rok urodzenia, miejsce urodzenia, ulubiony kolor.
- Napisz program, który wyświetli na ekranie 3 razy "Bóg Honor Ojczyzna".
- W jaki sposób możemy dołączyć zewnętrzną bibliotekę do naszego programu?
- Jak możemy na ekran wypisać dowolny napis?
Podstawowe typy danych
Programowanie w C++ nie tylko ograniczone jest do wypisywania na ekran ciągów znaków, tak jak pokazał to program Hello, World!. Aby pisać bardziej funkcjonalne programy musimy poznać zmienne.
Co to jest zmienna?
Zmienna to konstrukcja programistyczna posiadająca trzy podstawowe atrybuty: symboliczną nazwę, miejsce przechowywania i wartość; pozwalająca w kodzie źródłowym odwoływać się przy pomocy nazwy do wartości lub miejsca przechowywania. Nazwa służy do identyfikowania zmiennej w związku z tym często nazywana jest identyfikatorem. Miejsce przechowywania przeważnie znajduje się w pamięci komputera i określane jest przez adres i długość danych. Wartość to zawartość miejsca przechowywania. Zmienna zazwyczaj posiada również czwarty atrybut: typ, określający rodzaj danych przechowywanych w zmiennej i co za tym idzie sposób reprezentacji wartości w miejscu przechowywania.
Miejsce przechowywania to wydzielony obszar pamięci o rozmiarze określonym przez typ danych. Aby można użyć zmiennych w programie, należy je najpierw zadeklarować.
Deklaracja zmiennej - to inaczej zarezerwowanie w pamięci miejsca o określonym rozmiarze (zależnym od typu danych i implementacji C++) i określonej nazwie. Np.
int a, x, y;
double b;
char c;
Każda zmienna deklarowana jest według następującej zasady. Najpierw podajemy typ danych, następnie unikatową nazwę z wyjątkiem zarezerwowanych słów kluczowych. Zmienne tego samego typu można również deklarować oddzielając je (,). Np. int a, x, y;
Zmienne można podczas deklaracji inicjalizować podając wartość zmiennej lub wyrażenie. Np.
int a = 1024;
double b(1.6180339887);
char c{'$'};
double d = b + a;
Znak = jest operatorem przypisania tzn. zmiennej po lewej stronie przypisuje wartość (wyrażenie) po prawej stronie. Drugi rodzaj inicjalizowania zmiennych to wykorzystanie nawiasów (), np. double b(.1.6180339887). Trzeci sposób inicjalizacji to wykorzystaniem nawiasów klamrowych {}, np. char c{'$'}.
Więcej o operatorach znajdziemy w rozdziale Operatory.
Prawidłowa nazwa zmiennej musi składać się z liter, cyfr i znaku podkreślenia (_). Spacje i inne znaki są wykluczone w budowaniu nazw zmiennych. Każda zmienna zawsze powinna zaczynać się od litery.
C++ rezerwuje listę słów kluczowych, których nie można wykorzystać podczas tworzenia nazw.
Słowa kluczowe:
alignas, alignof, and, and_eq, asm, auto, bitand, bitor, bool, break, case, catch, char, char16_t, char32_t, class, compl, const, constexpr, const_cast, continue, decltype, default, delete, do, double, dynamic_cast, else, enum, explicit, export, extern, false, float, for, friend, goto, if, inline, int, long, mutable, namespace, new, noexcept, not, not_eq, nullptr, operator, or, or_eq, private, protected, public, register, reinterpret_cast, return, short, signed, sizeof, static, static_assert, static_cast, struct, switch, template, this, thread_local, throw, true, try, typedef, typeid, typename, union, unsigned, using, virtual, void, volatile, wchar_t, while, xor, xor_eq
Każda implementacja C++ może zawierać dodatkowe zarezerwowane sława kluczowe.
Język C++ to język programowania typu "case sensitive". Oznacza to, że zmienna napisana dużymi literami jest różna od zmiennej o tej samej nazwie napisanej małymi literami. Np.
Zmienna RESULT nie jest tą samą zmienną co Result czy result. Są to trzy różne zmienne.
Aby wyświetlić wartość zmiennej x na ekranie wystarczy użyć instrukcji:
cout << x;
Wartości zmiennych przechowywane są w pamięci komputera jako ciąg zer i jedynek. Nasz program nie potrzebuje znać dokładnej lokalizacji w pamięci, gdzie zmienne są przechowywane (z wykorzystaniem wskaźników wiemy dokładnie w którym miejscu w pamięci znajduje się nasza zmienna). Program odwołuje się do nazwy zmiennej i to wystarczy. Program potrzebuje wiedzieć jakiego rodzaju dane zmienna przechowuje. To nie to samo przechowywać zmienne całkowite, znaki, czy duże liczby zmiennoprzecinkowe (rzeczywiste). Zmienne te interpretowane są w inny sposób i mogą zajmować różną ilość pamięci.
Podstawowe typy danych to typy bazowe bezpośrednio zaimplementowane w język C++ i są podzielone na:
- Typy znakowe - mogą reprezentować pojedynczy znak 'A', 'z'. Najbardziej podstawowym typem znakowym jest char, który potrzebuje do przechowywania danych 1 bajt - 8 bitów.
- Typy całkowite - mogą przechowywać wartości całkowite takie jak 23, 2048. Typy całkowite istnieją w różnych rozmiarach i mogą to być typy ze znakiem i bez znaku, w zależności czy wspierają wartości ujemne czy nie.
- Typy zmiennoprzecinkowe - reprezentują wartości rzeczywiste takie jak np. 1.618033, 3.141592 z różną dokładnością w zależności od jednego z trzech wybranych typów zmiennoprzecinkowych.
- Typ bool - typ ten może reprezentować tylko dwa stany: prawda lub fałsz.
Podstawowe typy danych
Rodzaj danych | Nazwa typu* | Rozmiar/precyzja |
---|---|---|
Typy znakowe | char | 1 bajt. 8 bitów. |
char16_t | Nie mniejszy niż typ char. Co najmniej 16 bitów. | |
char32_t | Nie mniejszy niż typ char16_t. Co najmniej 32 bity. | |
wchar_t | Może reprezentować największy wspierany zestaw znaków. | |
Typy całkowite (ze znakiem) | signed char | Taki sam rozmiar jak typu char. Co najmniej 8 bitów. |
signed short int | Nie mniejszy niż typ char. Co najmniej 16 bitów. | |
signed int | Nie mniejszy niż typ short. Co najmniej 16 bitów. | |
signed long int | Nie mniejszy niż typ int. Co najmniej 32 bity. | |
signed long long int | Nie mniejszy niż typ long. Co najmniej 64 bity. | |
Typy całkowite (bez znaku) | unsigned char | (taki sam rozmiar jak typy ze znakiem) |
unsigned short int | ||
unsigned int | ||
unsigned long int | ||
unsigned long long int | ||
Typy zmiennoprzecinkowe | float | |
double | Dokładność nie mniejsza niż float. | |
long double | Dokładność nie mniejsza niż double. | |
Typ logiczny | bool | |
Typ void | void |
* Nazwy wybranych typów całkowitych mogą zostać skrócone. Można pominąć signed oraz int tylko w miejscach gdzie nie jest pogrubiona czcionka. Np. signed short int można zapisać jako short.
W każdej grupie typy danych różnią się rozmiarem. Pierwszy typ w każdej grupie ma najmniejszy rozmiar, a ostatni największy. Każdy typ w danej grupie ma takie same własnosci.
W powyższej tabeli żaden typ danych z wyjątkiem typu char, który ma dokładnie jeden bajt, nie ma dokładnie podanych wartości. Zamiast tego jest np. co najmniej 16 bitów.
Oznacza to, że typy te nie mają standardowego rozmiaru dla każdego kompilatora czy architektury komputera. Każdy kompilator języka C++ może dowolnie ustawiać rozmiar zmiennych by najlepiej dopasować go do aktualnej architektury komputera, na którym będzie uruchomiony. Ta właściwość daje dużą elastyczność w optymalnym doborze rozmiaru zmiennych.
Rozmiar typu danych podawany był w bitach. Poniższa tabela przedstawia reprezentację bitową oraz wartość dziesiętną.
Rozmiar | Wartość | Uwagi |
---|---|---|
8-bitów | 256 | = 28 |
16-bitów | 65 536 | = 216 |
32-bity | 4 294 967 296 | = 232 |
64-bity | 18 446 744 073 709 551 616 | = 264 |
Przykład:
16-bitowa zmienna typu unsigned int może przechowywać wartości od 0 do 65535, natomiast ta sama zmienna ze znakiem signed przechowuje wartości od -32768 do 32767.
W związku z tym, iż rozmiary typów danych podane są tak jak w tabeli Podstawowe typy danych, to aby dokładnie sprawdzić ile bitów przypada na dany typ danych, jaka jest minimalna i maksymalna wartość dla danego typu, itp. należy skorzystać z klasy numeric_limits z biblioteki <limits>
//Wykorzystanie klasy numeric_limits
#include <iostream>
#include <limits>
int main ()
{
std::cout << std::boolalpha;
std::cout << "Minimalna wartość dla int: " << std::numeric_limits<int>::min() << '\n';
std::cout << "Maksymalna wartość dla int: " << std::numeric_limits<int>::max() << '\n';
std::cout << "Czy typ int jest ze znakiem?: " << std::numeric_limits<int>::is_signed << '\n';
std::cout << "Ilość bitów dla typu int: " << std::numeric_limits<int>::digits << '\n';
return 0;
}
Wynik działania programu (wartości mogą się różnić w zależności od implementacji języka C++ oraz architektury komputera):
Minimalna wartość dla int: -2147483648 Maksymalna wartość dla int: 2147483647 Czy typ int jest ze znakiem?: true Ilość bitów dla typu int: 31
Analiza programu
Linia 3:
Dołączamy za pomocą dyrektywy #include bibliotekę limits, aby można wykorzystać potrzebną nam klasę numeric_limits.
Linia 6:
std::cout << std::boolalpha;
Jeśli flaga boolalpha jest ustawiona tak jak w powyższym zapisie oznacza to, że zmienne typu bool będą zapisywane w postaci true lub false, a nie 1 lub 0. By powrócić do poprzednich ustawień flagi boolalpha należy wykonać instrukcję:
std::cout << std::noboolalpha;
Konstrukcja std::cout oznacza wykorzystanie obiektu cout z biblioteki standardowej std. :: - jest to operator zasięgu. Więcej na ten temat znajdziemy w rozdziale Zasięg/przestrzenie nazw.
Linie 7-10:
W tych liniach wykorzystywana jest klasa numeric_limits. min(), max(), is_signed, digits, has_infinity oznaczają kolejno wartość minimalną, wartość maksymalną, czy typ danych jest ze znakiem, ilość bitów liczona od 0.
Ten sam program można również zapisać w taki sposób:
//Wykorzystanie klasy numeric_limits
#include <iostream>
#include <limits>
using std::cout;
using std::boolalpha;
using std::numeric_limits;
int main () {
cout << boolalpha;
cout << "Minimalna wartość dla int: " << numeric_limits<int>::min() << '\n';
cout << "Maksymalna wartość dla int: " << numeric_limits<int>::max() << '\n';
cout << "Czy typ int jest ze znakiem?: " << numeric_limits<int>::is_signed << '\n';
cout << "Ilość bitów dla typu int: " << numeric_limits<int>::digits << '\n';
return 0;
}
Typy danych przedstawione powyżej (znakowe, całkowite, rzeczywiste i logiczne) znane są jako typy podstawowe.
C++ wspiera szeroką gamę typów bazujących na typach podstawowych i nazywa je typami złożonymi. Typy te stanowią siłę języka C++. Wybrane typy złożone przedstawione będą w kolejnych rozdziałach.
Stałe
Podczas tworzenia stałej musimy jej na początku nadać wartość. Stała jak sama nazwa wskazuje jest stała (niezmienna) przez czas życia programu. Stałą definiujemy w następujący sposób:
const [typ_stałej] nazwa_stałej = wartość; Np.
const float pi = 3.1415;
const double zlota_liczba = 1.6180339887
const int wzrost = 198;
- Napisz program, który deklaruje zmienną a jako int oraz zmienną b jako float. Zainicjalizuj zmienną a wartością 128. Do zmiennej b wpisz wartość 65.9876 z wykorzystaniem operatora przypisania. Wyświetl wartości zmiennych na ekranie.
- Napisz program, zadeklaruje zmienne a, b, c dowolnego typu oraz zainicjalizuje je przykładowymi wartościami z wykorzystaniem trzech typów inicjalizacji zmiennych. Wyświetl wartości tych zmiennych w osobnych liniach na ekranie.
- Co to jest zmienna?
- Co to jest deklaracja zmiennej?
- W jaki sposób można zainicjalizować zmienną (podaj wszystkie sposoby)?
- Co oznacza, że język C++ jest typu "case sensitive"?
- Jakie znasz podstawowe typy danych?
- Co oznaczają typy ze znakiem i bez znaku?
- Jak można sprawdzić ile bitów potrzeba dla typu long double?
Operatory
Jeżeli znamy już pojęcie zmiennych i stałych możemy z nimi pracować wykorzystując operatory.
Operator przypisania (=)
np.
x = 10;
Zmiennej x przypisana jest wartość 10. Operator przypisania działa od prawej do lewej strony czyli zmiennej po lewej stronie przypisana jest wartość lub wyrażenie po prawej stronie.
x = y;
Do zmiennej x przypisana jest teraz wartość zmiennej y. Należy rozważyć sytuację, że przypisujemy zmiennej x wartość zmiennej y, w momencie wykonania instrukcji przypisania. Dlatego jeśli wartość zmiennej y ulegnie zmianie, to wartość x będzie miała poprzednią wartość zmiennej y.
/* Operator przypisania
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
int a, b; // a:?, b:?
a = 10; // a:10, b:?
b = 4; // a:10, b:4
a = b; // a:4, b:4
b = 7; // a:4, b:7
cout << "a:";
cout << a;
cout << " b:";
cout << b;
return 0;
}
a:4 b:7
y = + (x = );
W tej instrukcji zmiennej y przypisana jest wartość wyrażenia 2 + (x = 5). Napotykamu tu kolejny operator przypisania x = 5. Powyższa instrukcja równoważna jest zapisowi:
x = ;
y = + x;
Wartością zmiennej y jest oczywiście liczba 7.
Poprawną instrukcją C++ jest również:
a = b = c =
W tej instrukcji wartość 64 przypisana jest do wszystkich 3 zmiennych a, b, c (od prawej do lewej).
Operatory arytmetyczne (+, -, *, /, %)
Operator | Opis |
---|---|
+ | dodawanie |
- | odejmowanie |
* | mnożenie |
/ | dzielenie |
% | modulo |
Operacje dodawania, odejmowania, mnożenia, dzielenia korespondują z działaniami matematycznymi. Natomiast ostatni operator % daje jako wynik resztę z dzielenia np.
x = 16 % 3 //daje wynik 1, ponieważ 16/3 = 5 z resztą 1
Złożone operatory przypisania (+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=)
Złożone operatory przypisania modyfikują aktualną wartość zmiennej wykorzystując na niej operatację
Instrukcja | Równoważna instrukcja |
---|---|
y += x; | y = y + x; |
x -= 5; | x = x - 5; |
y *= 3; | y = y * 3; |
x /= 12; | x = x / 12; |
/* Złożony operator przypisania
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
int a, b=3;
a = b;
a+=2; // zapis równoważny to a=a+2
cout << a;
return 0;
}
Operatory inkrementacji i dekrementacji
Niektóre instrukcje mogą być zapisane krócej za pomocą operatora ++ (inkrementacja) lub -- (dekrementacja). Jest to równoznaczne z zapisem +=1 lub -=1.
++x;
x += 1;
x = x + 1;
Powyższe instrukcje są równoznaczne i każda z nich zwiększa wartość zmiennej x o 1.
Cechą szczególną tych operatorów jest to, że mogą występować w dwóch odmianach w formie przedrostkowej (++x) lub przyrostkowej (x++). Jednakże te dwa zapisy mają różne znaczenie.
Przykład 1 | Przykład 2 |
---|---|
x = 3; y = ++x; // x = 4, y = 4 |
x = 3; y = x++; // x = 4, y = 3 |
Operatory porównania (==, !=, >, <, >=, <=)
Dwa wyrażenia mogą być ze sobą porównane z wykorzystaniem operatorów porównania
Operator | Opis |
---|---|
== | równy |
!= | różny |
< | mniejszy niż |
> | większy niż |
<= | mniejszy lub równy |
>= | większy lub równy |
(7 == 5) // wyrażenie fałszywe
(5 > 4) // wyrażenie prawdziwe
(3 != 2) // wyrażenie prawdziwe
(6 >= 6) // wyrażenie prawdziwe
(5 < 5) // wyrażenie fałszywe
Oczywiście porównywać można nie tylko wartości numeryczne, ale również wyrażenia, zmienne.Załóżmy, że a = 2, b = 3, c = 6
(a == 5) // wyrażenie fałszywe, ponieważ a nie jest równe 5
(a*b >= c) // wyrażenie prawdziwe, ponieważ wyrażenie (2*3 >= 6) jest prawdziwe
(b+4 > a*c) // wyrażenie fałszywe, ponieważ (3+4 > 2*6) jest fałszywe
((b=2) == a) // wyrażenie prawdziwe
UWAGA!
Bądź ostrożny. Operator przypisania (=) to nie to samo co operator porównania (==).
Operatory logiczne (!, &&, ||)
Operator ! oznacza negację. Ma on tylko jeden operand po swojej prawej stronie i odwraca wartość wyrażenia z true na false i odwrotnie.
!(5 == 5) // wyrażenie fałszywe, ponieważ wyrażenie po prawej stronie jest prawdziwe
!(6 <= 4) // wyrażenie prawdziwe, ponieważ wyrażenie (6 <= 4) jest fałszywe
!true // wyrażenie fałszywe
!false // wyrażenie prawdziwe
Operatory && i || są używane dla dwóch operandów.Operator && | ||
---|---|---|
a | b | a && b |
true | true | true |
true | false | false |
false | true | false |
false | false | false |
Operator || | ||
---|---|---|
a | b | a || b |
true | true | true |
true | false | true |
false | true | true |
false | false | false |
((5 == 5) && (3 > 6)) // wyrażenie fałszywe ( true && false )
((5 == 5) || (3 > 6)) // wyrażenie prawdziwe ( true || false )
Gdy używamy operatorów logicznych, C++ wykonuje tylko niezbędne operacje, ignorując resztę. Np.((5 == 5) || (3 > 6))
Kompilator C++ sprawdza wartość wyrażenia (5 == 5) i już nie musi sprawdzać wartości następnego wyrażenia, gdyż pierwsze daje true.
Operator | |
---|---|
&& | Jeśli wyrażenie po lewej stronie jest fałszywe, to całość daje wartość fałsz(wtedy wyrażenie po prawej stronie nie jest sprawdzane) |
|| | Jeśli wyrażenie po lewej stronie jest prawdziwe, to całość jest prawdziwa(wtedy wyrażenie po prawej stronie nie jest sprawdzane) |
Rozważmy następujący przykład
if ((i < 10) && (++i < n))
Widzimy, że operand po prawej stronie (++i < n) inkrementuje wartość zmiennej i, ale tylko wtedy, gdy po lewej stronie jest warunek prawdziwy. W przeciwnym wypadku operand po prawej stronie nigdy nie zostanie wykonany.
Trójargumentowy operator warunkowy (?)
Operator ten sprawdza warunek i zwraca jedną wartość, gdy jest prawdziwy, a inną, gdy jest fałszywy.
warunek ? wynik1 : wynik2
Jeżeli warunek jest prawdziwy wykona się instrukcja wynik1, w przeciwnym wypadku wykona się instrukcja wynik2.
7==5 ? 4 : 3 // wynik jest równy 3, ponieważ 7 jest różne od 5.
7==5+2 ? 4 : 3 // wynik jest równy 4, ponieważ 7 jest równe 5 + 2.
5>3 ? a : b // wynik jest równy a, ponieważ 5 jest większe od 3.
Przykład
/* Trójargumentowy operator warunkowy
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
int a,b,c;
a=2;
b=7;
c = (a>b) ? a : b;
cout << c << '\n';
return 0;
}
Operatory rzutowania
Operatory rzutowania pozwalają zamienić wartość z jednego typu na inny.
Przykład
int i;
float f = 3.14;
i = (int) f;
Kod ten konwertuje liczbę zmiennoprzecinkową 3.14 na wartość całkowitą 3. Reszta z tej liczby jest tracona poprzez konwersję. Drugi rodzaj rzutowania zapisujemy następująco:
i = int (f);
Operator sizeof
Operator ten zawiera jeden parametr, który może być typem danych lub zmienną i zwraca wielkość tego typu w bajtach.
x = sizeof(char);
x jest równe 1 bajt, gdyż typ char ma rozmiar 1 bajta.
Priorytety operatorów
Pojedyncza instrukcja może mieć kilka operatorów jednocześnie.
x = 5 + 7 % 2;
W C++ powyższa instrukja daje wartość 6, ponieważ operator modulo (%) ma wyższy priorytet od operatora dodawania (+). Dlatego, aby zmienić priorytety operatorów używa się nawiasów ().
x = 5 + (7 % 2); // x = 6
x = (5 + 7) % 2; // x = 0
- Napisz program, który sprawdza wartość wyrażenia (a * b) < 15, gdzie a = 5 i b = 4. W przypadku, gdy wartość wyrażenia jest prawdziwa wypisz na ekranie wartość a, w przeciwnym wypadku wypisz wartość b. (użyj trójargumentowego operatora warunkowego).
- Napisz program, który oblicza resztę z dzielenia (a * b)/(a + b), gdzie a = 5 i b = 4.
- Napisz program, który wypisuje wartość całkowitą zmiennej float a = 15.42 przy użyciu operatora rzutowania.
- Co to jest operator modulo (%)?
- Co to jest złożony operator przypisania, podaj przykład?
- Jak zapisujemy operator porównania?
- Napisz tabelę prawdy dla operatora &&.
- Napisz tabelę prawdy dla operatora ||.
- Co to jest operator rzutowania? Podaj przykład.
- Co to jest trójargumentowy operator warunkowy? Podaj przykład.
- Jak sprawdzić ile dana zmienna ma zarezerwowanych bajtów w pamięci komputera?
Strumień wejścia/wyjścia
C++ używa warstwy abstrakcji zwanej strumieniami by wykonywać operacje wejścia/wyjścia na ekran monitora, pobierać dane z klawiatury, wykonywać operacje na plikach. Programista nie musi znać dokładnej budowy strumieni. Wystarczy wiedzieć jak taki strumień zastosować i z jakich funkcji skorzystać. Wszystko co potrzebujemy wiedzieć o strumieniach to strumień jest wejściem lub wyjściem ciągu znaków dostarczanych sekwencyjnie (jeden po drugim).
Strumień | Opis |
---|---|
cin | Standardowy strumień wejścia |
cout | Standardowy strumień wyjścia |
cerr | Standardowy strumień błędów (wyjście) |
clog | Standardowy strumień logów (wyjście) |
Strumień wyjścia (cout)
W większości środowisk standardowym wyjściem jest monitor komputera. Do formatowania operacji wyjścia poprzez obiekt cout używa się tzw. operatora wstawiania (przekierowania strumienia) <<.
cout << "Hello World"; // wypisuje na ekranie Hello World
cout << 120; // wypisuje na ekranie liczbę 120
cout << 'A'; // wypisuje na ekranie znak A
cout << x; // wypisuje na ekranie wartość x
Zwróć uwagę, że ciąg znaków "Hello World" został umieszczony w cudzysłowiu ("), ponieważ ciągi znaków umieszcza się pomiędzy znakami " ". Natomiast pojedynczy znak umieszczamy pomiędzy apostrofami (').
cout << "Witaj"; // wypisuje na ekranie napis Witaj
cout << Witaj; // wypisuje na ekranie wartość zmiennej Witaj
W jednej instrukcji można wielokrotnie wykorzystać przekierowanie strumienia (<<).cout << "To " << " jest " << "prosta instrukcja C++";
W pojedynczej istrukcji możemy wysłać do strumienia wyjściowego połączenie łańcucha z wartościami zmiennych.cout << "Mam " << wiek << " lat, a mój kod pocztowy to " << kod;
Zakładając, że zmienna wiek przechowuje wartość 30, a zmienna kod 32-345, to w wyniku wykonania powyższej instrukcji otrzymamy:
Mam 30 lat, a mój kod pocztowy to 32-345 Cout automatycznie nie przechodzi do następnej linii. Przykład:
cout << "To jest pierwsze zdanie.";
cout << "To jest drugie zdanie.";
W wyniku wykonania się tych dwóch instrukcji na ekranie zobaczymy:
To jest pierwsze zdanie.To jest drugie zdanie. Aby przejść do nowej linii należy zastosować znak nowej linii (\n).
cout << "To jest pierwsze zdanie.\n";
cout << "To jest drugie zdanie.\nTo jest trzecie zdanie";
W wyniku działania tych instrukcji na ekranie zobaczymy:
To jest pierwsze zdanie.
To jest drugie zdanie.
To jest trzecie zdanie. Można również zastosować manipulator endl.
cout << "To jest pierwsze zdanie." << endl;
cout << "To jest drugie zdanie." << endl << "To jest trzecie zdanie";
Wynik jest dokładnie taki jak poprzednio.
Strumień wejścia (cin)
W większości środowisk standardowym wejściem jest klawiatura. Do wprowadzania danych do strumienia wejściowego poprzez klawiaturę wykorzystuje się obiekt cin. Do przekierowania strumienia do np. zmiennej służy operator przekierowania strumienia (>>).
int wiek;
cin >> wiek;
W pierwszej linii zadeklarowana jest zmienna wiek typu całkowitego. W kolejnej linii program oczekuje wprowadzenia informacji o wieku i zapisuje ją w zmiennej wiek.
Napiszmy program Powitanie, który wczytuje Twoje imię i nazwisko z klawiatury, a następnie wyświetla spersonalizowane powitanie.
/* Program - Powitanie
* Wykonał Paweł Malinowski */
#include <iostream>
#include <string>
using namespace std;
string imie, nazwisko;
int main() {
cout << "Podaj swoje imię: ";
cin >> imie;
cout << "Podaj swoje nazwisko: ";
cin >> nazwisko;
cout << "Witaj " << imie << " " << nazwisko << "! Życzę miłego dnia:)";
return 0;
}
Wynikiem działania programu Powitanie jest:
Podaj swoje imię: Paweł Podaj swoje nazwisko: Malinowski Witaj Paweł Malinowski! Życzę miłego dnia:)
Kolorem zielonym oznaczono dane wprowadzone przez użytkownika. W każdym programie analizie podlegają tylko nowe rzeczy. Dlatego warto rozpocząć wykład od początku.
Analiza programu: Powitanie
Za pomocą instrukcji #include dołączana jest biblioteka string obsługująca łańcuchy (ciągi znaków). Nastepnie deklarowane są dwie zmienne globalne: imie oraz nazwisko typu string. Funkcja główna wypisuje na ekranie prośbę o podanie imienia. Instrukcja cin >> imie; wczytuje z klawiatury imię użytkownika i zapisuje je do zmiennej imie. cin jest to skrót od Console Input. To samo program wykonuje dla drugiej zmiennej nazwisko. Podane z klawiatury nazwisko zapisywane jest w zmiennej nazwisko. Następnie za pomocą instrukcji cout wypisywany jest łańcuch znaków oraz zmiennych.
Program Przeliczanie temperatury oczekuje podania przez użytkownika temperatury w stopniach Celcjusza, a jako wynik wypisuje temperaturę w stopniach Fahrenheita i Kelvina.
/* Program - Przeliczanie temperatury
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
float celsjusz, fahrenheit, kelvin;
int main()
{
cout << "Proszę podać temperaturę (°C): ";
cin >> celsjusz;
fahrenheit = (celsjusz * 1.8) + 32;
kelvin = celsjusz + 273.15;
cout << "Temperatura w stopniach Fahrenheita wynosi: " << fahrenheit << endl;
cout << "Temperatura w Kelvinach wynosi: " << kelvin;
return 0;
}
Wynik działania programu Przeliczanie
Proszę podać temperaturę (°C): 100
Temperatura w stopniach Fahrenheita wynosi: 212
Temperatura w Kelvinach wynosi: 373.15
Analiza programu: Przeliczanie temperatury
W programie deklarowane są zmienne typu float o nazwach celsjusz, fahrenheit, kelvin. Następnie program pyta użytkownika o podanie temperatury w stopniach Celsjusza. Gdy użytkownik wprowadzi z klawiatury podaną wartość, program obliczy i wypisze temperatury w stopniach Fahrenheita oraz Kelvina.
Napiszmy program Średnia arytmetyczna, który pyta o trzy liczby całkowite i wylicza średnią arytmetyczną z podanych liczb.
/* Program - Średnia arytmetyczna
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
int a,b,c;
float srednia;
cout << "Prosze wprowadzic kolejno trzy liczby calkowite:" << endl;
cout << "Podaj pierwsza liczbe: ";
cin >> a;
cout << "Podaj druga liczbe: ";
cin >> b;
cout << "Podaj trzecia liczbe: ";
cin >> c;
srednia = (float) (a + b + c)/3;
cout << "Srednia arytmetyczna z podanych liczb wynosi: " << srednia;
return 0;
}
Prosze wprowadzic kolejno trzy liczby ca│kowite: Podaj pierwsza liczbe: 2 Podaj druga liczbe: 8 Podaj trzecia liczbe: 3 Srednia arytmetyczna z podanych liczb wynosi: 4.33333
Analiza programu: Średnia arytmetyczna
W programie deklarowane są trzy zmienne typu całkowitego oraz jedna typu float. Następnie program prosi o podanie wartości trzech liczb całkowitych i zapisuje je do zmiennych a,b,c. W kolejnym kroku oblicza średnią arytmetyczną i wypisuje jej wynik na ekranie.
Zwróćmy uwagę na linię 19 programu.
srednia = (float) (a + b + c)/3;
W linii zastosowano tzw. rzutowanie typów oznaczone jako (float). Chodzi o to, że gdyby nie było tego zapisu to nastąpiłoby dzielenie całkowite, a wynik nie byłby dokładną wartością.
Przykład: Proszę usunąć zapis (float) z kodu programu i wykonać program dla następujących liczb: 3, 3, 8.
Średnia arytmetyczna z tych liczb wynosi: 4.666. Natomiast program obliczy to jako 4. Dlatego musimy zastosować rzutowanie typów.
- Napisz program, który pyta o podanie odległości w milach morskich i zamienia ją na metry (1 mila morska to 1852 metry).
- Napisz program, który pyta użytkownika o wiek w latach i wypisuje wiek w miesiącach.
- Napisz program, który pyta użytkownika o wzrost w metrach i wagę w kilogramach i wypisuje wskaźnik BMI. (BMI = masa/wzrost2).
- Co to jest strumień wyjściowy?
- Co to jest strumień wejściowy?
- Jakiego obiektu używamy do wyprowadzenia danych na ekran monitora?
- Jakiego obiektu używamy do wprowadzania danych z klawiatury?
- Co oznaczają tzw. operatory przekierowania strumienia << lub >> ?
Instrukcje / sterowanie przepływem
Instrukcja warunkowa if
Instrukcja warunkowa służy do podejmowania decyzji w programie. Dzięki tej konstrukcji językowej, programy stają się bardziej złożone (rozbudowane). Instrukcja if działa następująco. Jeżeli warunek jest prawdziwy to zostaje wykonana instrukcja lub blok instrukcji. Jeżeli warunek jest fałszywy to nie zostanie wykonana żadna instrukcja.
Składnia instrukcji warunkowej if
if (warunek) instrukcja1;
Przykład:
if (a > 10) cout << "Zmienna a jest większa od 10";
if (b == 64)
{
a = 0;
b = 0;
}
Istnieje jeszcze druga odmiana instrukcji warunkowej:
if (warunek) instrukcja1;
else instrukcja2;
Przykład:
if (wiek >=18) cout << "Jesteś pełnoletni.";
else cout << "Jesteś niepełnoletni.";
/* Program - Instrukcja warunkowa
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
int a,b,c;
a = 15;
b = 7;
if (2 * b > a) cout << "2 * " << b << " jest większe od " << a;
else cout << "2 * " << b << " jest mniejsze od " << a;
return 0;
}
2 * 7 jest mniejsze od 15
Kolejna odmiana instrukcji warunkowej if:
if (warunek1) instrukcja1;
else if (warunek2) instrukcja2;
else instrukcja3;
/* Program - Złożona instrukcja warunkowa
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
int wzrost;
cout << "Podaj swój wzrost (cm):";
cin >> wzrost;
if (wzrost > 180)
{
cout << "Możesz zostać koszykarzem. \n";
cout << "==========================\n";
if (wzrost <= 190) cout << "Mógłbyś być rozgrywającym\n";
else if (wzrost <= 205) cout << "Mógłbyś grać na pozycjach rzucającego obrońcy, skrzydłowego lub silnego skrzydłowego\n";
else cout << "Możesz być centrem.";
}
else
cout << "Prawdopodobnie nie zostaniesz koszykarzem.";
return 0;
}
Podaj swój wzrost (cm): 178
Prawdopodobnie nie zostaniesz koszykarzem.
Podaj swój wzrost (cm): 185
Możesz zostać koszykarzem.
==========================
Mógłbyś być rozgrywającym.
Podaj swój wzrost (cm): 198
Możesz zostać koszykarzem.
==========================
Mógłbyś grać na pozycjach rzucającego obrońcy, skrzydłowego lub silnego skrzydłowego.
Podaj swój wzrost (cm): 214
Możesz zostać koszykarzem.
==========================
Możesz być centrem.
Instrukcja wyboru switch
Składnia instrukcji switch:
switch(wyrażenie-całkowite)
{
case etykieta1: instrukcja(e)
case etykieta2: instrukcja(e)
case etykieta3: instrukcja(e)
...
default: instrukcja(e)
}
/* Program - Instrukcja wyboru switch
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
int ile_jezykow;
cout << "Ile znasz języków: ";
cin >> ile_jezykow;
if (ile_jezykow > 0)
{
switch(ile_jezykow)
{
case 1: cout << "Jesteś bohaterem. Znasz swój ojczysty język.";
break;
case 2: cout << "Oprócz języka ojczystego znasz dodatkowo język obcy.";
break;
case 3: cout << "Możesz pochwalić się znajomością dwóch języków obcych.";
break;
default: cout << "Brawo. Jesteś prawdziwym poliglotą.";
}
}
return 0;
}
Ile znasz języków: 1
Jesteś bohaterem. Znasz swój ojczysty język.
Ile znasz języków: 2
Oprócz języka ojczystego znasz dodatkowo język obcy.
Ile znasz języków: 3
Możesz pochwalić się znajomością dwóch języków obcych.
Ile znasz języków: 5
Brawo. Jesteś prawdziwym poliglotą.
Pętle
Pętla for
Składnia pętli for:
for (inicjalizacja; warunek; aktualizacja)
{
instrukcje;
}
/* Program - P«tla for
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
int liczba;
cout << "Podaj liczbę całkowitą (0 - 100): ";
cin >> liczba;
for (int i = 0; i < liczba; i++)
{
cout << "To jest liczba: " << i + 1 << endl;
}
return 0;
}
Podaj liczbę całkowitą (0 - 100): 10
To jest liczba: 1
To jest liczba: 2
To jest liczba: 3
To jest liczba: 4
To jest liczba: 5
To jest liczba: 6
To jest liczba: 7
To jest liczba: 8
To jest liczba: 9
To jest liczba: 10
Pętla while
Składnia pętli while:
while (warunek)
{
instrukcje;
}
/* Program - Pętla for
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
int liczba, i = 0;
cout << "Podaj liczbę całkowitą (0 - 100): ";
cin >> liczba;
while (i < liczba)
{
cout << "To jest liczba: " << i + 1 << endl;
i++;
}
return 0;
}
Podaj liczbę całkowitą (0 - 100): 10
To jest liczba: 1
To jest liczba: 2
To jest liczba: 3
To jest liczba: 4
To jest liczba: 5
To jest liczba: 6
To jest liczba: 7
To jest liczba: 8
To jest liczba: 9
To jest liczba: 10
Pętla do ... while
Składnia pętli do ... while:
do
{
instrukcje;
}
while (warunek);
/* Program - Pętla do while
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
int liczba, i = 0;
cout << "Podaj liczbę całkowitą (0 - 100): ";
cin >> liczba;
do
{
cout << "To jest liczba: " << i + 1 << endl;
i++;
} while(i < liczba);
return 0;
}
Podaj liczbę całkowitą (0 - 100): 10
To jest liczba: 1
To jest liczba: 2
To jest liczba: 3
To jest liczba: 4
To jest liczba: 5
To jest liczba: 6
To jest liczba: 7
To jest liczba: 8
To jest liczba: 9
To jest liczba: 10
Instrukcja break
Instrukcja break umożliwia programowi pominięcie części kodu. Instrukcja ta jest stosowana w instrukcjach wyboru (switch) oraz w pętlach. Kompilator po napotkaniu instrukcji break; opuszcza dany blok kodu zawarty w nawiasach {}.
Przykład:
Instrukcja continue
Instrukcja continue umożliwia ominięcie fragmentu kodu. Instrukcja ta stosowana jest w pętlach. Gdy kompilator napotka instrukcję continue przerywa wykonywane instrukcje i przechodzi do następnej iteracji pętli.
Przykład:
- Napisz program, który zapyta Cię o wiek. Jeśli jesteś pełnoletni na ekranie pojawi się napis - Witaj, jesteś pełnoletni. Jeśli nie masz 18 lat, program wypisze na ekranie - Niestety jeszcze nie jesteś pełnoletni.
- Napisz prosty program do logowania. Jeśli jako login podasz - Zenon, a jako hasło - G56y, to zostaniesz zalogowany i wyświetli się napis - Witamy w systemie. Jeśli wprowadzisz błędne dane logowania - program wyświetli napis - Niestety wprowadziłeś błędny login lub hasło.
- Napisz program, który zapyta cię ile masz dzieci. Na każde dziecko przypada 500zł. W zależności od ilości dzieci, program pokaże ile powinieneś otrzymać z programu 500+. Zastosuj instrukcję switch. Założenie: maksymalna ilość dzieci w programie - 5.
- Napisz program, który wypisze liczby od 10 do 20 za pomocą pętli for, while i do-while.
- *Napisz program, który wypisze liczby od 20 do 0 co dwie (20,18,16 ...) za pomocą pętli for, while, do-while.
- Napisz program, który wypisze liczby od 1 do 100. W środku pętli umieść warunek, że jeśli iterator będzie równy 23, opuść pętlę za pomocą instrukcji break.
- Napisz program, który wypisuje liczby od 1 do 20. Jeśli napotka liczbę 13 to opuść wykonanie pętli za pomocą instrukcji continue.
- Podaj składnię instrukcji warunkowej wraz z jej schematem blokowym.
- Podaj na przykładzie składnię instrukcji wyboru.
- Wymień jakie znasz rodzaje pętli, czym one się różnią, podaj schematy blokowe każdej z nich.
- Omów działanie instrukcji break, podaj schemat blokowy.
- Omów działanie instrukcji continue, podaj schemat blokowy.
Pliki tekstowe
Zapis do pliku tekstowego
W celu wykonania operacji zapisu danych do pliku należy wykonać następujące czynności:
- utworzyć obiekt klasy ofstream do obsługi strumienia wyjściowego,
- skojarzyć ten obiekt z plikiem,
- używać tego obiektu w taki sam sposób jak obiektu cout - jedyną różnicą jest to, że dane wyjściowe są wysyłane do pliku, a nie na ekran.
W pierwszej kolejności dołączamy bibliotekę fstream, następnie tworzymy obiekt klasy ofstream - output file stream np.
ofstream fout;
W drugim kroku musimy skojarzyć ten obiekt z plikiem. Służy do tego metoda open().
fout.open("data.txt");
Te dwie instrukcje możemy zastąpić jedną:
ofstream fout("data.txt");
Od tego momentu możemy używać obiektu fout tak samo jak obiektu cout. Jeśli chcemy zapisać w pliku następujący łańcuch: "Informacje zapisane w pliku", to wystarczy użyć następującej instrukcji:
fout << "Informacje zapisane w pliku";
Możemy tak zrobić ponieważ klasą bazową klasy ofstream jest klasa ostream, włącznie z metodami i manipulatorami formatującymi.
Poniżej przykład programu zapisującego powitanie do pliku data.txt.
/* Program - ofstream - zapis
* Wykonał Paweł Malinowski */
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string imie;
ofstream fout("data.txt"); //otwarcie pliku
cout << "Zapis danych do pliku rozpoczęty\n"; //zapis do pliku
cout << "Podaj swoje imię:";
cin >> imie;
fout << "Witaj, " << imie << endl;
fout.close(); //zamknięcie pliku
return 0;
}
Widzimy, że obiekt musimy otworzyć oraz zamknąć, aby zwolnić zasoby. Obiekt fout wykorzystany był dokładnie tak jak do tej pory korzystaliśmy z obiektu cout.
Poniższy program odczytuje zawartość pliku data.txt z wykorzystaniem obiektu klasy ifstream - input file stream, np.
ifstream fin;
Dalej musimy skojarzyć obiekt z plikiem data.txt, wykonując poniższą instrukcję:
fin.open("data.txt");
Te dwie instrukcje możemy zastąpić jedną:
ifstream fin("data.txt");
/* Program - ofstream - odczyt
* Wykonał Paweł Malinowski */
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string imie;
ifstream fin("data.txt"); //otwarcie pliku
cout << "To jest zawartość pliku data.txt\n";
char ch;
while(fin.get(ch)) //odczytaj znak
cout << ch; //wypisz go na ekranie
fin.close(); //zamknięcie pliku
return 0;
}
Odczyt danych z pliku data.txt odbywa się znak po znaku.
Tryby otwarcia pliku
Tryb otwarcia pliku określa sposób, w jaki dany plik ma być używany: do odczytu, zapisu, plik binarny, itp. Do tej pory nie podawaliśmy drugiego argumentu w metodzie open czy podczas inicjalizacji obiektu strumienia plikowego z nazwą pliku.
Stała | Znaczenie |
---|---|
ios::in | Otwórz plik do odczytu. |
ios::out | Otwórz plik do zapisu. |
ios::ate | Po otwarciu pliku ustaw się na jego końcu. |
ios::app | Dołącz na koniec pliku. |
ios::trunc | Zredukuj rozmiar pliku do zera, jeśli istnieje. |
ios::binary | Plik binarny. |
W metodzie open klasy ifstream domyślną wartością drugiego argumentu (tryb otwarcia pliku) jest ios::in (otwórz plik do odczytu), a w przypadku klasy ofstream domyślną wartością jest ios::out | ios::trunc (otwórz plik do zapisu i zredukuj rozmiar pliku do zera).
Dla obiektu klasy ofstream oznacza to, iż jeśli plik już istnieje, to nastąpi zredukowanie jego rozmiaru do zera - czyli usunięcie, a następnie zapisanie danych od początku pliku.
Aby można było dopisać dane na końcu pliku (wielokrotne otwieranie pliku w trybie do zapisu) należy użyć następującego trybu otwarcia pliku:
ios::out | ios::app
Pliki binarne
/* Program - ofstream - odczyt
* Wykonał Paweł Malinowski */
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
char napis[30];
ofstream fout("data.dat", ios::out | ios::app | ios::binary); //otwarcie pliku binarnego
cout << "Wpisz tekst, który chcesz zapisać w pliku binarnym\n";
cin.get(napis,30);
fout.write(napis, sizeof napis);
fout.close(); //zamknięcie pliku
return 0;
}
/* Program - ofstream - odczyt
* Wykonał Paweł Malinowski */
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
char napis[30];
ifstream fin("data.dat", ios::in | ios::binary); //otwarcie pliku binarnego
while(fin.read(napis, sizeof napis))
cout << napis;
fin.close(); //zamknięcie pliku
return 0;
}
Poniżej przykładowy plik binarny.
Przykład wykorzystania klasy fstream do zapisu i odczytu danych. Wykorzystanie metody open() na rzecz obiektu klasy fstream o nazwie plik.
/* Program - fstream - zapis
* Wykonał Paweł Malinowski */
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
fstream plik;
string imie, nazwisko, miejsce_urodzenia, wojewodztwo;
cout << "Podaj imie: ";
cin >> imie;
cout << "Podaj nazwisko: ";
cin >> nazwisko;
cout << "Podaj miejsce urodzenia: ";
cin >> miejsce_urodzenia;
cout << "Podaj z jakiego jesteś województwa: ";
cin >> wojewodztwo;
plik.open("/Users/pawelmalinowski/Documents/C++/q/dane.txt", ios::out | ios::app);
plik << "Imię:\t\t\t" << imie << endl;
plik << "Nazwisko:\t\t" << nazwisko << endl;
plik << "Miejsce urodzenia:\t" << miejsce_urodzenia << endl;\
plik << "Wojewodztwo:\t\t" << wojewodztwo << endl;
return 0;
}
Imię: Paweł Nazwisko: Malinowski Miejsce urodzenia: Prudnik Województwo: opolskie
Odczyt z pliku tekstowego
/* Program - fstream - odczyt
* Wykonał Paweł Malinowski */
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int main()
{
fstream plik;
string imie, nazwisko, miejsce_urodzenia, wojewodztwo;
plik.open("/Users/pawelmalinowski/Documents/C++/q/dane.txt", ios::in);
if (plik.good() == true)
{
string linia;
int licznik = 1;
while(getline(plik, linia))
{
switch(licznik)
{
case 1: imie = linia; break;
case 2: nazwisko = linia; break;
case 3: miejsce_urodzenia = linia; break;
case 4: wojewodztwo = linia; break;
}
licznik++;
}
cout << imie << endl;
cout << nazwisko << endl;
cout << miejsce_urodzenia << endl;
cout << wojewodztwo << endl;
}
else
{
cout << "Plik nie istnieje!";
exit(0);
}
return 0;
}
Imię: Paweł Nazwisko: Malinowski Miejsce urodzenia: Prudnik Województwo: opolskie
- Napisz program, który zapyta cię o następujące informacje: imię, nazwisko, płeć, wykształcenie, zawód. Zapisz te informacje w pliku dane.txt.
- Napisz program, który odczyta z pliku dane.txt informacje o twoim imieniu, nazwisku, płci, wykształceniu oraz zawodzie i wyświetli je na ekranie.
- Napisz program, który zapisuje dowolny ciąg znaków podany z klawiatury do pliku w trybie binarnym.
- Napisz program, który odczytuje te dane z pliku binarnego.
- Co to jest klasa fstream?
- Co to jest klasa ifstream i ofstream?
- Jak zapisać dane do pliku?
- Jak odczytać dane z pliku?
- Jakie znasz tryby otwarcia pliku?
- Jak można otworzyć plik (binarny) w trybie do zapisu?
- Jak można otworzyć plik (binarny) w trybie do odczytu?
Funkcje
Funkcje to inaczej podprogramy. Koncepcja funkcji umożliwia napisanie jednej funkcji i wywołanie jej w programie setki razy. Dzięki temu oszczędzamy czas, porządkujemy kod, a jeśli chcemy zmienić ciało funkcji robimy to w jednym miejscu.
Aby użyć funkcji w C++ należy:
- podać definicję funkcji,
- podać prototyp funkcji,
- wywołać funkcję.
/* Program - funkcja
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
void funkcja(); //prototyp funkcji
int main()
{
funkcja(); //wywołanie funkcji
funkcja(); //kolejne wywołanie funkcji
return 0;
}
//definicja funkcji
void funkcja()
{
using namespace std;
cout << "Funkcja wykonała się.\n";
}
W powyższym przykładzie widzimy wszystkie trzy elementy tzn. definicja funkcji, prototyp funkcji oraz wywołanie funkcji.
Definicja funkcji - to inaczej ciało funkcji
Funkcje można podzielić na dwa typy:
- Niezwracające wartości (procedury - typ void)
- Zwracające wartość (funkcje)
Składnia funkcji niezwracającej żadnej wartości:
void nazwa_funkcji(listaParametrów)
{
instrukcja/e
}
listaParametrów określa liczbę i typy danych parametrów przekazywanych funkcji.
Przykład:
void witaj(string imie)
{
cout << "Witaj " << imie;
}
Wywołanie tej funkcji w programie może wyglądać tak:
witaj("Paweł");
Składnia funkcji zwracającej wartość:
typ_danych nazwa_funkcji(listaParametrów)
{
instrukcja/e
return wartość;
}
Przykład:
int suma(int a, int b)
{
return a + b;
}
Prototyp funkcji - to nazwa funkcji z zestawem argumentów poprzedzonych typem danych.
Składnia prototypu:
typ_danych nazwa_funkcji(typ_danych argument1, typ_danych argument2,...);
Przykład:
int suma(int a, int b);
Prototyp opisuje interfejs funkcji na potrzeby kompilatora, czyli mówi kompilatorowi, jaki jest typ wartości zwracanej przez funkcję, a także ile jest argumentów i jakie są ich typy.
Prototyp funkcji umieszczamy przed funkcją main(), aby funkcja główna wiedziała jakich funkcji może sie spodziewać, jaka jest ich budowa. Natomiast ciało funkcji - definicja umieszczana jest za funkcją główną main().
Definicja funkcji - mówi nam jak funkcja jest zbudowana (jakiego typu), jakie przyjmuje argumenty oraz jak wygląda ciało funkcji.
Wywołanie funkcji - jest to instrukcja wywołująca po nazwie funkcję wraz z argumentami. Dzięki wywołaniu możemy zobaczyć efekt działania funkcji.
Przykłady funkcji:
Przykład 1:
Funkcja, której zadaniem będzie przeliczanie temperatury ze stopni Celcjusza na Kelviny i stopnie Fahrenheita.
/* Program - Przeliczanie temperatury - funkcja
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
void temperatura(float c); // prototyp funkcji
float celsjusz;
int main()
{
cout << "Proszę podać temperaturę (°C): ";
cin >> celsjusz;
temperatura(celsjusz); // wywołanie funkcji
return 0;
}
void temperatura(float c) // definicja funkcji
{
float fahrenheit, kelvin;
fahrenheit = (celsjusz * 1.8) + 32;
kelvin = celsjusz + 273.15;
cout << "Temperatura w stopniach Fahrenheita wynosi: " << fahrenheit << endl;
cout << "Temperatura w Kelvinach wynosi: " << kelvin;
}
Przykład 2:
Funkcja, której zadaniem będzie obliczenie średniej arytmetycznej trzech podanych liczb.
/* Program - Średnia arytmetyczna - funkcja
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int a, b, c;
float srednia(int x, int y, int z); // prototyp funkcji
int main()
{
cout << "Prosze wprowadzic kolejno trzy liczby calkowite:" << endl;
cout << "Podaj pierwsza liczbe: ";
cin >> a;
cout << "Podaj druga liczbe: ";
cin >> b;
cout << "Podaj trzecia liczbe: ";
cin >> c;
cout << "Srednia arytmetyczna z podanych liczb wynosi: " << srednia(a, b, c); // wywołanie funkcji
return 0;
}
float srednia(int x, int y, int z) // definicja funkcji
{
return (float) (x + y + z)/3;
}
Przykład 3:
Funkcja, której zadaniem będzie zrealizowanie petli for za pomocą funkcji.
/* Program - Pętla for - funkcja
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
void petla_for(int x); // prototyp funkcji
int main()
{
int liczba;
cout << "Podaj liczbę całkowitą (0 - 100): ";
cin >> liczba;
petla_for(liczba); // wywołanie funkcji
return 0;
}
void petla_for(int x) // definicja funkcji
{
for (int i = 0; i < x; i++)
{
cout << "To jest liczba: " << i + 1 << endl;
}
}
Przykład 4:
Funkcja, której zadaniem będzie zrealizowanie petli while za pomocą funkcji.
/* Program - Pętla for
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
void petla_while(int x); // prototyp funkcji
int main()
{
int liczba;
cout << "Podaj liczbę całkowitą (0 - 100): ";
cin >> liczba;
petla_while(liczba); // wywołanie funkcji
return 0;
}
void petla_while(int x) // definicja funkcji
{
int i = 0;
while (i < x)
{
using namespace std;
cout << "To jest liczba: " << i + 1 << endl;
i++;
}
}
Przykład 5:
Funkcja, której zadaniem będzie zrealizowanie petli do while za pomocą funkcji.
/* Program - Pętla do while - funkcja
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
void petla_do_while(int x); // prototyp funkcji
int main()
{
int liczba;
cout << "Podaj liczbę całkowitą (0 - 100): ";
cin >> liczba;
petla_do_while(liczba); // wywołanie funkcji
return 0;
}
void petla_do_while(int x) // definicja funkcji
{
using namespace std;
int i = 0;
do
{
cout << "To jest liczba: " << i + 1 << endl;
i++;
} while(i < x);
}
Przykład 6:
Funkcja, której zadaniem będzie obliczenie wskaźnika BMI.
/* Program - BMI - funkcja
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
float wzrost, waga;
float BMI(float wzr, float wag); // prototyp funkcji
int main()
{
int liczba;
cout << "Podaj swój wzrost:";
cin >> wzrost;
cout << "Podaj swóją wagę:";
cin >> waga;
cout << "Twój wskaźnik BMI wynosi: " << BMI(wzrost, waga); // wywołanie funkcji
return 0;
}
float BMI(float wzr, float wag) // definicja funkcji
{
return wag/(wzr*wzr);
}
Przekazywanie parametrów przez wartość lub przez referencje
Wszystkie powyższe funkcje zawarte w tym rozdziale przekazywały argumenty przez wartość. Oznacza to, że do funkcji została przesłana kopia wartości parametru. Oryginalna wartość parametru pozostaje bez zmiany.
W tej części zostanie przedstawiony sposób przekazywania parametrów do funkcji poprzez tzw. referencje. Oznacza to, że do funkcji zostanie przesłana oryginalna wartość parametru, który może zostać zmieniony w trakcie działania funkcji.
/* Program - zamiana - przekazywanie parametrów przez referencję
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
void zamien(int & a, int & b); //a i b to aliasy zmiennych przekazywanych do funkcji
int main()
{
int z1 = 123;
int z2 = 321;
cout << "Wartość zmiennej z1 wynosi: " << z1 << endl;
cout << "Wartość zmiennej z2 wynosi: " << z2 << endl;
cout << "Wywołanie funkcji zamien!" << endl;
zamien(z1, z2);
cout << "Zmienna z1 ma teraz wartość: " << z1 << endl;
cout << "Zmienna z2 ma teraz wartość: " << z2 << endl;
return 0;
}
void zamien(int & a, int & b)
{
int pomocnicza;
pomocnicza = a;
a = b;
b = pomocnicza;
}
Przykład ten pokazuje, że funkcja zamień pracowała na oryginalnych wartościach i zamieniła pierwotne wartości zmiennych z1 oraz z2.
Przeciążanie funkcji
Przeciążanie funkcji - inaczej polimorfizm (wielopostaciowość) pozwala używać wielu funkcji o takiej samej nazwie. Korzystając z przeciążania funkcji (polimorfizmu) możemy zdefiniować całą rodzinę funkcji realizujących te same zadania, ale pracujących na różnych zestawach parametrów.
/* Program - przeciążanie nazw funkcji
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
float pole(float r); //pole koła
int pole(int a); //pole kwadratu
int pole(int a, int b); //pole prostokąta
int main()
{
float promien;
int a, b;
cout << "Podaj promien koła: ";
cin >> promien;
cout << "Pole koła o promieniu " << promien << " wynosi: " << pole(promien) << endl;
cout << "Podaj długość boku kwadratu: ";
cin >> a;
cout << "Pole kwadratu o boku " << a << " wynosi: " << pole(a) << endl;
cout << "Podaj długość pierwszego boku prostokąta: ";
cin >> a;
cout << "Podaj długość drugiego boku prostokąta: ";
cin >> b;
cout << "Pole prostokąta o bokach " << a << " i " << b << " wynosi: " << pole(a,b);
return 0;
}
float pole(float r)
{
return 3.14 * r * r;
}
int pole(int a)
{
return a * a;
}
int pole(int a, int b)
{
return a * b;
}
Rekurencja
Rekurencja to inaczej wywoływanie funkcji wewnętrz samej siebie.
Przykład:
Algorytm obliczania silni w sposób rekurencyjny
/* Program - obliczanie silni rekurencyjnie
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int silnia(int n);
int main()
{
return 0;
}
int silnia(int n)
{
if(n < 2)
return 1;
return n * silnia(n - 1);
}
Przykład:
Wyznacz sumę kolejnych liczb naturalnych z wykorzystaniem algorytmu rekurencyjnego.
/* Program - obliczanie kolejnych liczb naturalnych - rekurencyjnie
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int suma(int n);
int main()
{
return 0;
}
int suma(int n)
{
if(n < 1)
return 0;
return n + suma(n - 1);
}
- Napisz program, który obliczy średnią geometryczną trzech wczytanych liczb za pomocą funkcji.
- Napisz program, który wyświetli na ekranie pierwszych 10 znaków ciągu Fibonacciego.
- Napisz program, który obliczy wartość funkcji f(x) = 2x2 - 8x. Parametr przekaż do funkcji poprzez referencję.
- Co to jest funkcja?
- Co to jest prototyp, definicja i wywołanie funkcji?
- Jakie znasz typy funkcji?
- Co oznacza, że przekazujemy do funkcji argument/y?
- Jak przesyłamy do funkcji parametry przez wartość?
- Jak przesyłamy do funkcji parametry przez referencję?
Złożone typy danych
Tablice
Tablica - to struktura danych, która może przechowywać wiele wartości tego samego typu. Gdyby tablice nie istniały to musielibyśmy deklarować dziesiątki czy setki oddzielnych zmiennych w celu realizacji jakiegoś złożonego zadania. Ale na szczęście tablice istnieją i deklarujemy tylko jedną zmienną tablicową określonego typu, podając jednocześnie ilość elementów tablicy. Aby utworzyć tablicę, należy podać trzy elementy:
- typ wartości elementów tablicy,
- nazwę tablicy,
- liczbę elementów tablicy.
int miesiace[12];
Zmienna typu tablicowego o nazwie miesiace zawiera 12 szufladek na zmienne typu int. Aby dostać się do wartości poszczególnych szufladek używa się następującego zapisu:
- miesiace[0] - pierwsza szufladka
- miesiace[1] - druga szufladka
- ................................
- miesiace[11] - dwunasta szufladka
Tablicę można również zainicjalizować:
string miesiace[12] = {"styczeń", "luty", "marzec", "kwiecień", "maj", "czerwiec", "lipiec", "sierpień", "wrzesień", "październik", "listopad", "grudzień"};
Tablica jest typem złożonym, ponieważ zbudowana jest na bazie innego typu.
Ciąg arytmetyczny.
Przykład:
Napisz program, który oblicza n-ty wyraz ciągu arytmetycznego oraz oblicza sumę n-początkowych wyrazów tego ciągu.
/* Program - tablice
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
void ciag_a(int p, int r);
int main()
{
int p,r;
cout << "Podaj pierwszy wyraz ciągu: ";
cin >> p;
cout << "Podaj różnicę ciągu: ";
cin >> r;
ciag_a(p,r);
return 0;
}
void ciag_a(int p, int r)
{
int tab_a[3][100] = {}; //deklaracja tablicy wyzerowanie wartości wszystkich komórek
tab_a[0][0] = 1;
tab_a[1][0] = p;
tab_a[2][0] = p;
for (int i = 1; i < 100; i++)
{
tab_a[0][i] = i + 1;
tab_a[1][i] = tab_a[1][i - 1] + r;
tab_a[2][i] = i * (p + tab_a[1][i]) / 2;
}
for (int i = 0; i < 100; i++)
{
cout << tab_a[0][i] << "\t" << tab_a[1][i] << "\t" << tab_a[2][i] << endl;
}
}
Podaj pierwszy wyraz ciągu: 2
Podaj różnicę ciągu: 3
1 2 2
2 5 3
3 8 10
4 11 19
5 14 32
6 17 47
7 20 66
8 23 87
9 26 112
10 29 139
11 32 170
12 35 203
13 38 240
14 41 279
15 44 322
16 47 367
17 50 416
18 53 467
19 56 522
20 59 579
21 62 640
22 65 703
23 68 770
24 71 839
25 74 912
26 77 987
27 80 1066
28 83 1147
29 86 1232
30 89 1319
31 92 1410
32 95 1503
33 98 1600
34 101 1699
35 104 1802
36 107 1907
37 110 2016
38 113 2127
39 116 2242
40 119 2359
41 122 2480
42 125 2603
43 128 2730
44 131 2859
45 134 2992
46 137 3127
47 140 3266
48 143 3407
49 146 3552
50 149 3699
51 152 3850
52 155 4003
53 158 4160
54 161 4319
55 164 4482
56 167 4647
57 170 4816
58 173 4987
59 176 5162
60 179 5339
61 182 5520
62 185 5703
63 188 5890
64 191 6079
65 194 6272
66 197 6467
67 200 6666
68 203 6867
69 206 7072
70 209 7279
71 212 7490
72 215 7703
73 218 7920
74 221 8139
75 224 8362
76 227 8587
77 230 8816
78 233 9047
79 236 9282
80 239 9519
81 242 9760
82 245 10003
83 248 10250
84 251 10499
85 254 10752
86 257 11007
87 260 11266
88 263 11527
89 266 11792
90 269 12059
91 272 12330
92 275 12603
93 278 12880
94 281 13159
95 284 13442
96 287 13727
97 290 14016
98 293 14307
99 296 14602
100 299 14899
Process returned 0 (0x0) execution time : 19.851 s
Press ENTER to continue.
Ciąg geometryczny.
Przykład:
Napisz program, który oblicza n-ty wyraz ciągu geometrycznego oraz oblicza sumę n-początkowych wyrazów tego ciągu.
/* Program - tablice
* Wykonał Paweł Malinowski */
#include <iostream>
#include <cmath>
using namespace std;
void ciag_g(int p, float q);
int main()
{
int p;
float q;
cout << "Podaj pierwszy wyraz ciągu: ";
cin >> p;
cout << "Podaj iloraz ciągu geometrycznego: ";
cin >> q;
ciag_g(p,q);
return 0;
}
void ciag_g(int p, float q)
{
float tab_g[3][20] = {}; //deklaracja tablicy wyzerowanie wartości wszystkich komórek
tab_g[0][0] = 1;
tab_g[1][0] = p;
tab_g[2][0] = p;
for (int i = 1; i < 20; i++)
{
tab_g[0][i] = i + 1;
tab_g[1][i] = tab_g[1][i - 1] * q;
tab_g[2][i] = p * (1 - pow(q,i+1)) / (1 - q);
}
for (int i = 0; i < 20; i++)
{
cout << tab_g[0][i] << "\t" << tab_g[1][i] << "\t\t" << tab_g[2][i] << endl;
}
}
Podaj pierwszy wyraz ciągu: 3
Podaj iloraz ciągu geometrycznego: 2
1 3 3
2 6 9
3 12 21
4 24 45
5 48 93
6 96 189
7 192 381
8 384 765
9 768 1533
10 1536 3069
11 3072 6141
12 6144 12285
13 12288 24573
14 24576 49149
15 49152 98301
16 98304 196605
17 196608 393213
18 393216 786429
19 786432 1.57286e+06
20 1.57286e+06 3.14572e+06
Process returned 0 (0x0) execution time : 2.662 s
Press ENTER to continue.
Ciąg Fibonacciego.
Przykład:
Napisz program, który oblicza n-ty wyraz ciągu Fibonacciego.
/* Program - ciąg Fibonnaciego - iteracyjnie
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
void ciag_f();
int main()
{
ciag_f();
return 0;
}
void ciag_f()
{
long tab_f[100] = {}; //deklaracja tablicy wyzerowanie wartości wszystkich komórek
tab_f[0] = 1;
tab_f[1] = 1;
for (int i = 2; i < 100; i++)
{
tab_f[i] = tab_f[i - 1] + tab_f[i - 2];
}
for (int i = 0; i < 93; i++)
{
cout << i + 1 << "\t" << tab_f[i] << endl;
}
}
1 1
2 1
3 2
4 3
5 5
6 8
7 13
8 21
9 34
10 55
11 89
12 144
13 233
14 377
15 610
16 987
17 1597
18 2584
19 4181
20 6765
21 10946
22 17711
23 28657
24 46368
25 75025
26 121393
27 196418
28 317811
29 514229
30 832040
31 1346269
32 2178309
33 3524578
34 5702887
35 9227465
36 14930352
37 24157817
38 39088169
39 63245986
40 102334155
41 165580141
42 267914296
43 433494437
44 701408733
45 1134903170
46 1836311903
47 2971215073
48 4807526976
49 7778742049
50 12586269025
51 20365011074
52 32951280099
53 53316291173
54 86267571272
55 139583862445
56 225851433717
57 365435296162
58 591286729879
59 956722026041
60 1548008755920
61 2504730781961
62 4052739537881
63 6557470319842
64 10610209857723
65 17167680177565
66 27777890035288
67 44945570212853
68 72723460248141
69 117669030460994
70 190392490709135
71 308061521170129
72 498454011879264
73 806515533049393
74 1304969544928657
75 2111485077978050
76 3416454622906707
77 5527939700884757
78 8944394323791464
79 14472334024676221
80 23416728348467685
81 37889062373143906
82 61305790721611591
83 99194853094755497
84 160500643816367088
85 259695496911122585
86 420196140727489673
87 679891637638612258
88 1100087778366101931
89 1779979416004714189
90 2880067194370816120
91 4660046610375530309
92 7540113804746346429
93 -6246583658587674878
Process returned 0 (0x0) execution time : 0.016 s
Press ENTER to continue.
Przykład:
Wyznacz n-ty wyraz ciągu Fibbonaciego rekurencyjnie.
/* Program - ciąg Fibbonaciego - rekurencyjnie
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
long long fib(int n);
int main()
{
int n = 40;
cout << fib(n);
return 0;
}
long long fib(int n)
{
if(n < 3)
return 1;
return fib(n - 2) + fib(n - 1);
}
Liczby pseudolosowe.
rand() % ile_liczb + liczba_początkowa
Przykład:
Chcemy wygenerować liczby z zakresu (7 - 46)
Obliczanie zakresu:
ile_liczb = koniec_zakresu - początek_zakresu + 1
ile_liczb = 46 - 7 + 1
ile_liczb = 40
rand() % 40 + 7
Aby włączyć generator liczb pseudolosowych należy wpisać następującą instrukcję:
srand(time(NULL));Aby tego dokonać należy dołączyć biblioteki cstdlib (srand, rand) oraz time.h (time)
/* Program - tablice
* Wykonał Paweł Malinowski */
#include <iostream>
#include <cstdlib>
#include <time.h>
using namespace std;
int main()
{
int tab[100] = {};
srand(time(NULL));
for (int i = 0; i < 100; i++)
{
tab[i] = rand() % 100 + 1;
}
for (int i = 0; i < 100; i++)
{
cout << i + 1 << "\t" << tab[i] << endl;
}
return 0;
}
1 55
2 24
3 91
4 69
5 6
6 99
7 28
8 89
9 100
10 3
11 31
12 39
13 96
14 65
15 56
16 63
17 11
18 99
19 67
20 8
21 18
22 65
23 34
24 77
25 77
26 4
27 87
28 75
29 27
30 18
31 53
32 48
33 88
34 26
35 59
36 64
37 92
38 2
39 13
40 90
41 79
42 37
43 85
44 61
45 21
46 43
47 12
48 30
49 99
50 100
51 8
52 3
53 50
54 78
55 92
56 46
57 32
58 23
59 48
60 59
61 47
62 98
63 91
64 7
65 43
66 2
67 54
68 15
69 73
70 60
71 22
72 9
73 36
74 61
75 72
76 16
77 87
78 68
79 80
80 16
81 78
82 28
83 95
84 25
85 95
86 79
87 3
88 82
89 77
90 67
91 77
92 34
93 50
94 41
95 73
96 70
97 32
98 38
99 75
100 89
Process returned 0 (0x0) execution time : 0.042 s
Press ENTER to continue.
Sortowanie bąbelkowe
Zasada działania sortowania bąbelkowego
Sortowanie bąbelkowe polega na porównywaniu par liczb ze sobą (zaznaczone na niebiesko). Jeżeli porównanie liczb jest fałszywe (na czerwono) to następuje zamiana liczb ze sobą. W przeciwnym przypadku liczby pozostają na swoim miejscu. Algorytm wykorzystuje dwie pętle for zewnątrzną oraz wewnętrzną oraz funkcję swap, która zamienia liczby ze sobą. Jeżeli algorytm przejdzie przez wszystkie iteracje tych pętli, oznacza to, że zbiór jest posortowany.
/* Program - sortowanie bąbelkowe
* Wykonał Paweł Malinowski */
#include <iostream>
#include <cstdlib>
using namespace std;
void sortowanie_babelkowe(int tab[],int n)
{
for(int i = 0; i < n; i++)
for(int j = 1; j < n - i; j++)
if(tab[j - 1] > tab[j])
swap(tab[j - 1], tab[j]);
}
int main()
{
int *tab;
tab = new int [100];
srand(time(NULL));
for (int i = 0; i < 100; i++)
{
tab[i] = rand() % 101;
}
cout << "Tablica liczb pseudolosowych" << endl;
for(int i = 0; i < 100; i++)
cout << tab[i] << " ";
sortowanie_babelkowe(tab, 100);
cout << endl << endl;
cout << "Tablica posortowana metodą bąbelkową:" << endl;
for(int i = 0; i < 100; i++)
cout << tab[i] << " ";
return 0;
}
Tablica liczb pseudolosowych
70 94 44 75 92 2 68 87 23 15 47 40 91 33 10 40 18 54 23 40 61 43 86 63 95 89 9 93 80 62 37 40 11 9 34 60 49 34 62 98 44 97 13 80 16 19 62 0 70 34 60 64 65 41 37 71 35 40 100 14 32 13 51 26 34 8 30 70 27 25 76 85 32 6 9 31 70 52 78 92 72 94 10 84 95 43 5 63 77 9 40 71 100 96 67 51 92 98 80 60
Tablica posortowana metodą bąbelkową:
0 2 5 6 8 9 9 9 9 10 10 11 13 13 14 15 16 18 19 23 23 25 26 27 30 31 32 32 33 34 34 34 34 35 37 37 40 40 40 40 40 40 41 43 43 44 44 47 49 51 51 52 54 60 60 60 61 62 62 62 63 63 64 65 67 68 70 70 70 70 71 71 72 75 76 77 78 80 80 80 84 85 86 87 89 91 92 92 92 93 94 94 95 95 96 97 98 98 100 100
Process returned 0 (0x0) execution time : 0.017 s
Press ENTER to continue.
Sortowanie szybkie - Quicksort
/* Program - sortowanie szybkie - quicksort
* Wykonał Paweł Malinowski */
#include <iostream>
#include <cstdlib>
using namespace std;
void quick_sort(int *tab, int lewy, int prawy)
{
if(prawy <= lewy) return;
int i = lewy - 1, j = prawy + 1,
pivot = tab[(lewy+prawy)/2];
while(1)
{
while(pivot>tab[++i]);
while(pivot<tab[--j]);
if( i <= j)
swap(tab[i],tab[j]);
else
break;
}
if(j > lewy)
quick_sort(tab, lewy, j);
if(i < prawy)
quick_sort(tab, i, prawy);
}
int main()
{
int *tab;
tab = new int [100];
srand(time(NULL));
for (int i = 0; i < 100; i++)
{
tab[i] = rand() % 101;
}
cout << "Tablica liczb pseudolosowych" << endl;
for(int i = 0; i < 100; i++)
cout << tab[i] << " ";
quick_sort(tab,0, 99);
cout << endl << endl;
cout << "Tablica posortowana metodą quicksort:" << endl;
for(int i = 0; i < 100; i++)
cout << tab[i] << " ";
return 0;
}
Tablica liczb pseudolosowych
32 100 5 76 31 81 58 71 68 47 39 47 18 31 36 84 2 90 60 44 57 13 72 75 57 76 33 4 64 57 29 79 55 7 68 77 67 7 58 25 9 90 8 61 48 79 19 94 7 42 16 33 13 49 79 74 62 30 19 30 85 48 15 25 75 4 18 61 27 17 49 12 3 44 23 21 26 50 89 19 21 96 44 91 76 93 31 97 64 65 59 26 75 59 21 20 22 2 14 49
Tablica posortowana metodą quicksort:
2 2 3 4 4 5 7 7 7 8 9 12 13 13 14 15 16 17 18 18 19 19 19 20 21 21 21 22 23 25 25 26 26 27 29 30 30 31 31 31 32 33 33 36 39 42 44 44 44 47 47 48 48 49 49 49 50 55 57 57 57 58 58 59 59 60 61 61 62 64 64 65 67 68 68 71 72 74 75 75 75 76 76 76 77 79 79 79 81 84 85 89 90 90 91 93 94 96 97 100
Process returned 0 (0x0) execution time : 0.015 s
Press ENTER to continue.
Struktury
Poznaliśmy już tablice, które przechowują dużą ilość danych tego samego typu. Struktura to taki typ danych, która może przechowywać dane różnego typu. Jeśli chciałbyś napisać większy program przechowujący dane np. w bazie danych to operowanie na tablicach byłoby uciążliwe. Dlatego wymyślono wygodniejszy sposób realizacji tego typu zadań poprzez zastosowanie nowego typu danych - struktury. W ten sposób możemy zaprojektować na przykład tablicę struktur, którą będziemy wykorzystywać w naszym programie.
Przykład: Deklaracja struktury
struct samochod
{
string marka;
string model;
float pojemnosc;
float przyspieszenie;
};
Każda struktura, typ wyliczeniowy i klasa w języku C++ po nawiasie klamrowym zamykającym (}) zawsze musi mieć średnik (;).
Przykład:/* Program - struktura
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
struct koszykarz
{
string imie;
string nazwisko;
int wzrost;
float waga;
string klub;
};
int main()
{
koszykarz MJ = { "Michael", "Jordan", 198, 98, "Chicago Bulls" };
cout << "Kto jest najlepszym koszykarzem wszechczasów?\n";
cout << MJ.imie << " " << MJ.nazwisko << " reprezentujący klub " << MJ.klub << endl;
return 0;
}
Unie
Unia - to złożony typ danych podobny trochę do struktury, gdyż w skład unii może wchodzić wiele zmiennych różnego typu. Unię odróżnia to, że w danym momencie możemy korzystać tylko z jednej zmiennej. Ilość bitów przeznaczona na unię określona jest wielkością największego elementu w unii.
Unie stosujemy wtedy, gdy nie mamy pewności jakiego typu element będzie nam potrzebny w danym momencie. Podobnie jak ze strukturami można utworzyć tablicę unii. Unie można również wykorzystywać w strukturach czy klasach.
Typy wyliczeniowe
Typ wyliczeniowy ze słowem kluczowym enum, to mechanizm za pomocą którego możemy tworzyć nowe typy danych. Składnia polecenia enum jest zbliżona do składni struktur.
enum position
{
"Point quard", "Shooting quard", "Small forward", "Power forward", "Center"
};
Wskaźniki
Wskaźniki - to zmienne przechowujące adres innej zmiennej. Zanim przejdziemy do wskaźników, adres zmiennej możemy uzyskać przez tzw. operator adresu (&) - znak ampersand.
int gruszki;
Aby odwołać się do adresu zmiennej gruszki w programie wystarczy wpisać:
&gruszki;
Przykład:
/* Program - adresy zmiennych
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
int truskawki = 12;
string samochod = "Subaru";
cout << "Wartość zmiennej truskawki wynosi " << truskawki << endl;
cout << "Wartość zmiennej samochod = " << samochod << endl;
cout << "Wielkość zmiennej truskawki wynosi " << sizeof(truskawki) << endl;
cout << "Wielkość zmiennej samochod wynosi " << sizeof(samochod) << endl;
cout << "Adres zmiennej truskawki to " << &truskawki << endl;
cout << "Adres zmiennej samochod to " << &samochod << endl;
return 0;
}
Wartość zmiennej truskawki wynosi 12
Wartość zmiennej samochod = Subaru
Wielkość zmiennej truskawki wynosi 4
Wielkość zmiennej samochod wynosi 24
Adres zmiennej truskawki to 0x7ffeecd36a30
Adres zmiennej samochod to 0x7ffeecd36a18
Wskaźniki jak sama nazwa mówi wskazują na obszar w pamięci komputera innej zmiennej. Wskaźnik nie pokazuje wartości zmiennej, ale miejsce gdzie dana zmienna przechowywana jest w pamięci.
/* Program - wskaźniki
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
int truskawki = 12;
int *w_truskawki;
w_truskawki = &truskawki; // przypisanie wskaźnikowi adresu zmiennej truskawki
// pokazanie wartości zmiennej truskawki na dwa sposoby
cout << "Pokazanie wartości zmiennej truskawki na dwa sposoby" << endl;
cout << "Wartość zmiennej truskawki wynosi (truskawki) " << truskawki << endl;
cout << "Wartość zmiennej truskawki wynosi (*w_truskawki) " << *w_truskawki << endl << endl;
// pokazanie adresu zmiennej truskawki na dwa sposoby
cout << "Pokazanie adresu zmiennej truskawki na dwa sposoby" << endl;
cout << "Adres zmiennej truskawki to (&truskawki) " << &truskawki << endl;
cout << "Adres zmiennej truskwaki to (w_truskawki) " << w_truskawki << endl << endl;
// wykorzystanie wskaźnika do zmiany wartości zmiennej truksawki
cout << "Za pomocą wskaźnika można zmienić wartość zmiennej truskawki:" << endl;
*w_truskawki += 1;
cout << "Wartość zmiennej truskawki wynosi teraz " << truskawki;
return 0;
}
Pokazanie wartości zmiennej truskawki na dwa sposoby:
Wartość zmiennej truskawki wynosi (truskawki) 12
Wartość zmiennej truskawki wynosi (*w_truskawki) 12
Pokazanie adresu zmiennej truskawki na dwa sposoby:
Adres zmiennej truskawki to (&truskawki) 0x7ffee21b9a18
Adres zmiennej truskwaki to (w_truskawki) 0x7ffee21b9a18
Za pomocą wskaźnika można zmienić wartość zmiennej truskawki:
Wartość zmiennej truskawki wynosi teraz 13
Zapamiętaj!.
Zmienna truskawki i wskaźnik *w_truskawki są równoważne i pokazują wartość zmiennej truskawki.
&truskawki i w_truskawki są równoważne i pokazują adres zmiennej truskawki.
Użycie operatora new do alokowania pamięci
/* Program - wskaźniki - operator new
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
int *wsk = new int;
*wsk = 23;
int w = 33;
cout << "Wartość " << *wsk << endl;
cout << "Adres " << wsk << endl;
cout << "Wartość " << w << endl;
cout << "Adres " << &w << endl;
return 0;
}
Wartość 23
Adres 0x7f986cc00690
Wartość 33
Adres 0x7ffee91d1a6c
W programie został zadeklarowany wskaźnik na typ int alokowany operatorem new.
Zmienne przechowywane są w pamięci zwanej stosem (stack), natomiast obiekty danych alokowane za pomocą operatora new przechowywane są w pamięci zwanej stertą (heap) albo w puli wolnej pamięci (free store). Dlatego adresy widoczne na listingu powyżej nie znajdują się koło siebie.
Zwalnianie pamięci za pomocą operatora delete. Operator delete umożliwia zwolnienie pamięci zaalokowanej operatorem new. Jest to ważna zasada w dobrym wykorzystaniu pamięci.
Przykład:
/* Program - wskaźniki - operator new
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
int *wsk = new int;
*wsk = 23;
cout << "Wartość " << *wsk << endl;
cout << "Adres " << wsk << endl;
delete wsk;
cout << "Wartość " << *wsk << endl;
cout << "Adres " << wsk << endl;
return 0;
}
Wartość 23
Adres 0x7f8e05c00690
Wartość 23
Adres 0x7f8e05c00690
Pomimo, że operator delete zwolnił pamięć przydzieloną operatorem new, to wskazywana wartość oraz adres nie uległy zmianie. Oznacza to, że wskaźnik dalej wskazuje na to samo miejsce w pamięci, ale pamięć ta nie należy już do programu.
Użycie operatora new do dynamicznego tworzenia tablic
/* Program - wskaźniki - dynamiczne tworzenie tablicy
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
int main()
{
int rozmiar;
cout << "Podaj rozmiar tablicy: ";
cin >> rozmiar;
int *tab = new int[rozmiar];
for (int i = 0; i < rozmiar; i++)
{
tab[i] = i + 1;
cout << tab[i] << endl;
}
delete [] tab;
return 0;
}
Podaj rozmiar tablicy: 10
1
2
3
4
5
6
7
8
9
10
Użycie operatora new do tworzenia struktur dynamicznych
/* Program - wskaźniki - dynamiczne tworzenie struktury
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
struct koszykarz
{
string imie;
string nazwisko;
string klub;
int wzrost;
int waga;
};
int main()
{
koszykarz *MJ = new koszykarz;
cout << "Kto jest najlepszym koszykarzem wszechczasów?\n";
cout << "Podaj imię: ";
getline(cin,MJ->imie);
cout << "Podaj nazwisko: ";
getline(cin,MJ->nazwisko);
cout << "Klub sportowy: ";
getline(cin,MJ->klub);
cout << "Podaj wzrost: ";
cin >> MJ->wzrost;
cout << "Podaj wagę: ";
cin >> MJ->waga;
cout << endl << MJ->imie << " " << MJ->nazwisko << " wzrost: " << MJ->wzrost << ", waga: " << MJ->waga << " reprezentujący klub " << MJ->klub << endl;
delete MJ;
return 0;
}
Kto jest najlepszym koszykarzem wszechczasów?
Podaj imię: Michael
Podaj nazwisko: Jordan
Klub sportowy: Chicago Bulls
Podaj wzrost: 198
Podaj wagę: 98
Michael Jordan wzrost: 198, waga: 98 reprezentujący klub Chicago Bulls
Zasięg zmiennych / przestrzenie nazw
Zasięg zmiennych
Pisząc programy staramy się nadawać unikatowe nazwy wszystkim zmiennym. Każda zmienna widoczna jest w ramach pewnego zasięgu. Zasięg ten wyznaczony jest poprzez blok kodu zawarty w nawiasach klamrowych {,}. Istnieją zmienne o zasięgu globalnym tzn. widoczne w całym programie oraz przez cały okres działania programu. Deklaruje się je po dołączeniu plików nagłówkowych, a przed funkcją główną main(). Natomiast zmienne lokalne widoczne są tylko w tym bloku kodu, w którym zostały zadeklarowane.
Przykład:
/* Program - zasięg zmiennych
* Wykonał Paweł Malinowski */
#include <iostream>
using namespace std;
// Deklaracja zmiennej globalnej i jej inicjalizacja
int x = 90;
int main()
{
// Wypisanie zmiennej globalnej
cout << "Wartość zmiennej x wynosi: " << x << endl;
for (int i = 0; i < 2; i++)
{
int j = 156;
// Wypisanie zmiennej globalnej
cout << "Wartość zmiennej x wynosi: " << x << endl;
// Wypisanie zmiennej lokalnej
cout << "Wartość zmiennej j wynosi: " << j << endl;
}
// Wypisanie zmiennej globalnej
cout << "Wartość zmiennej x wynosi: " << x << endl;
// Wypisanie zmiennej lokalnej
cout << "Wartość zmiennej j wynosi: " << j << endl; //error: use of undeclared identifier 'j'
return 0;
}
Można zauważyć, że zmienne globalne widoczne są w każdym bloku kodu. Natomiast wyświetlenie zmiennej lokalnej poza blokiem kodu, w którym została zadeklarowana nie może zostać zrealizowane. Kompilator zgłasza błąd: error: use of undeclared identifier 'j'
Przestrzenie nazw
Do tej pory w większości programów stosowaliśmy zapis using namespace std;. Zapis ten oznacza, że korzystamy ze wszystkich metod przestrzeni nazw std, na przykład: cout, cin, endl, itd. Dobrą praktyką przy pisaniu programów jest wskazanie dokładnie których metod, obiektów będziemy używać w naszym programie, np. using std::cout i/lub using std::cin.
Tworzenie włanej przestrzeni nazw
namespace moja_nazwa
{
int liczba;
}
/* Program - zasięg zmiennych
* Wykonał Paweł Malinowski */
#include <iostream>
namespace pole
{
double prostokat(int a, int b)
{
return(a * b);
}
}
int main()
{
using std::cout;
using std::cin;
int x, y;
cout << "Podaj pierwszy bok prostokąta:";
cin >> x;
cout << "Podaj drugi bok prostokąta:";
cin >> y;
cout << "Pole prostokata wynosi: " << pole::prostokat(x,y);
return 0;
}
- Napisz program, który obliczy pole i obwód kwadratu dla x = 15 i wypisz je na ekranie.
- Napisz program, który obliczy pole i obwód koła dla r = 4 i wypisz je na ekranie.
- Napisz program, który obliczy pole i obwód trójkąta dla a = 3, b = 4, c = 5 i wypisz je na ekranie.
- Napisz program, który obliczy pole powierzchni i objętość kuli o promieniu 3.
- Napisz program, który obliczy pole powierzchni i objętość prostopadłościanu (podstawa 3, 5) wysokość 8.
- Napisz program, który obliczy resztę z dzielenia (2x2 - 2x) / (2x - 1) dla x = 4.
- Napisz program, który pyta o podanie odległości w milach morskich i zamienia ją na metry (1 mila morska to 1852 metry).
- Napisz program, który pyta użytkownika o wzrost w metrach i wagę w kilogramach i wypisuje wskaźnik BMI. (BMI = masa/wzrost2).
- Napisz program, który zapyta Cię o wiek. Jeśli jesteś pełnoletni na ekranie pojawi się napis - Witaj, jesteś pełnoletni. Jeśli nie masz 18 lat, program wypisze na ekranie - Niestety jeszcze nie jesteś pełnoletni.
- Napisz program do logowania. Jeśli jako login podasz - admin, a jako hasło - Admin, to zostaniesz zalogowany i wyświetli się napis - Witamy w systemie. Jeśli wprowadzisz błędne dane logowania - program wyświetli napis - Niestety wprowadziłeś błędny login lub hasło.
- Napisz program, który zapyta Cię ile masz dzieci. Na każde dziecko przypada 500zł. W zależności od ilości dzieci, program pokaże ile powinieneś otrzymać z programu 500+. Zastosuj instrukcję switch. Założenie: maksymalna ilość dzieci - 5.
- Napisz program, który zapyta użytkownika o odległość w latach świetlnych i zwróci odległość w jednostkach astronomicznych. Rok świetlny to 63240 jednostek astronomicznych.
- Napisz program, który wypisze liczby od 10 do 20 za pomocą pętli for, while i do-while.
- Napisz program, który wypisze liczby od 20 do 0 co dwie (20,18,16 ...) za pomocą pętli for, while, do-while.
- Napisz program, który wypisze liczby od 1 do 100. W środku pętli umieść warunek, że jeśli iterator będzie równy 23, opuść pętlę za pomocą instrukcji break.
- Napisz program, który wypisuje liczby od 1 do 20. Jeśli napotka liczbę 13 to opuść wykonanie pętli za pomocą instrukcji continue.
- Napisz program, który zapyta użytkownika o długość geograficzną w stopniach, minutach i sekundach, a następnie wyświetli tą długość w formacie dziesiętnym.
- Napisz program, który zapyta cię o następujące informacje: imię, nazwisko, płeć, wykształcenie, zawód. Zapisz te informacje w pliku dane.txt.
- Napisz program, który odczyta z pliku dane.txt informacje o twoim imieniu, nazwisku, płci, wykształceniu oraz zawodzie i wyświetli je na ekranie.
- Napisz program, który zapisuje dowolny ciąg znaków podany z klawiatury do pliku w trybie binarnym.
- Napisz program, który odczytuje te dane z pliku binarnego.
- Napisz program, który obliczy średnią geometryczną trzech wczytanych liczb za pomocą funkcji.
- Napisz program, który wyświetli na ekranie pierwszych 10 elementów ciągu Fibonacciego.
- Napisz program, który obliczy wartość funkcji f(x) = 2x2 - 8x. Parametr przekaż do funkcji poprzez referencję.
- Napisz program, który obliczy średnią ważoną dla następujących liczb: 2, 4, 8, 1, 12 o następujących wagach 1, 3, 3, 2, 1.
- Napisz program, który obliczy średnią harmoniczną dla następujących liczb 23, 19, 48, 15.
- Napisz program, który poprosi użytkownika o podanie liczby sekund, a wynik pokaże w dniach, godzinach, minutach i sekundach.
- Napisz program, który poprosi użytkownika o podanie populacji światowej oraz populacji Polski. Program powinien wyświetlić procent jaki populacja Polski stanowi w populacji świata.