Podsumowanie
Gratulacje, ukończyłeś pierwszy etap nauki 🎉. Tematy podstawowe wprowadziły Cię w świat programowania oraz zaznajomiły Cię z podstawowymi zagadnieniami i algorytmami. Jeżeli programowanie Cię zainteresowało, zachęcamy zagłębić się w tajniki C++, czytając tematy zaawansowane. Zanim to, uporządkujmy sobie jednak świeżo poznane pojęcia.
Słowniczek
Kompilator - program, który tłumaczy język C++ (zrozumiały dla ludzi), na język zrozumiały dla maszyn (np. komputera);
Biblioteka - plik / program, który tłumaczy kompilatorowi co ma zrobić, gdy natrafi na pewne obiekty, takie jak
std::cout,std::stringalbostd::vector. Jej nazwę podajemy między<...>, czyli zarównoiostream, jak i<iostream>, odnoszą się do tej samej biblioteki<iostream>;Przestrzeń nazw - “folder”, dzięki któremu C++ unika ryzyka konfliktu nazw (czyli dwóch różnych obiektów o tej samej nazwie). Możemy “wyrzucić na zewnątrz” rzeczy z “folderu” poprzez
using namespace nazwa_przestrzeni;Wypisywanie - umieszczanie tekstu na ekranie;
Wczytywanie - ustawianie wartości zmiennych (w czasie wykonania), na podstawie tego, co użytkownik wpisze po uruchomieniu programu;
Zmienna - komórka pamięci, która przechowuje wartość o pewnym typie. Jej działanie można porównać do pudełka;
Typ danych - określaja typ wartości oraz sposób jej przechowania w pamięci komputera;
Operator - znak specjalny, który wykonuje operacje (np.: dodaje, odejmuje, łączy warunki), lub pełni funkcje pomocniczą (np. oddziela wyrażenia);
Konstrukcja warunkowa - wykonuje określony kod, jeżeli warunek jest prawdziwy. Może również wykonać inny kod, w przeciwnym wypadku;
Pętla - wykonuje wielokrotnie ten sam kod, dopóki warunek jest spełniony;
Iteracja - (również obrót pętli) powtórzenie kodu pętli - np. jeśli pętla wykonała kod pięć razy, powiemy, że wykonała pięć iteracji lub pięć obrotów;
Iterowanie się po obiekcie - (rówież przechodzenie po obiekcie) uzyskiwanie kolejnych elementów obiektu, przechowywującego wiele wartości, np. tablica;
Iterator - zmienna wskazująca na jakiś element np. wektora. Iteratory są dostępne tylko na wybranych typach danych, nie ma ich na tablicach. Na razie, aby uzyskać element tablicy/wektora wystarczy odwołać się do indeksu, lecz niedługo poznasz struktury, w których nie będzie się dało tak zrobić - wtedy iteratory się nam przydadzą;
Tablica - struktura, który przechowywuje wiele wartości;
Funkcja - kod, który może zostać wygodnie wykonany z kilku różnych miejsc w kodzie, poprzez
nazwa(), oraz przyjmować różne parametry;Metoda - funkcja, która uruchamiana jest na obiekcie, za pomocą
obiekt.metoda(). Często wiąże się to z modyfikacją obiektu;Zwracanie wartości - (dotyczy funkcji i metody) obliczanie wartości przez funkcje i oddawanie/podstawianie jej w miejsce, gdzie funkcja została uruchomiona;
Wywoływanie funkcji/metody - inne określenie na uruchamianie funkcji/metody. Można używać zamiennie;
Wektor - usprawniona tablica. Zawiera szereg przydatnych metod. Nie ma związku z wektorami z lekcji fizyki;
Sortowanie - porządkowanie elementów, według pewnej reguły - najczęściej rosnąco lub malejąco;
Zaawansowane zagadnienia C++
Zanim rozpoczniesz czytanie zaawansowanych artykułów, poznajmy kilka nowych zagadnień i nową składnię języka - sposób, w jaki można pewne rzeczy zapisać.
Usprawnionione przechodzenie po pętli
Jeżeli mamy wektor, o rozmiarze $n$, możemy się po nim iterować za pomocą następującej składni.
for (typ zmienna : wektor) {
}
Wypiszmy w ten sposób elementy wektora.
vector<int> liczby = {5, 4, 3, 2, 1};
for (int liczba : liczby) {
cout << liczba << ' ';
}
W ten sposób zamiast indeksów, jak przy tradycyjnym przechodzeniu, będziemy uzyskiwać wartości.
Wskaźniki
Załóżmy, że mam zmienną a o typie int. Ma ona swoje położenie w pamięci komputera, które określa jej adres. Adres uzyskujemy za pomocą operatora &. C++ chciałby jednak wiedzieć, jaki typ ma wartość znajdująca się pod tym adresem. Do tego celu używamy gwiazdki *, np. adres liczby całkowitej to int*.
int liczba = 5;
int* adres_liczby = &liczba;
Jeżeli chcemy uzyskać wartość spod adresu, ponownie używamy gwiazdki. Można powiedzieć, że ładujemy adres, czyli uzyskujemy to pole w pamięci, które opisuje.
int liczba = 5;
int* adres_liczby = &liczba;
*adres_liczby += 5;
cout << liczba << endl;
Co tu się zadziało?
Wartość zmiennej
liczbato5(przyjmijmy, że jej adres to0x15);Wartość zmiennej
adres_liczbyto0x15;Ładujemy wartość zmiennej
adres_liczbyi zwiększamy ją o5;- W ten sposób zwiększyliśmy wartość, która znajdowała się pod adresem
0x15, czyli wartość zmiennejliczba;
- W ten sposób zwiększyliśmy wartość, która znajdowała się pod adresem
Wypisujemy wartość zmiennej
liczba, która wynosi10;
Zastosowanie wskaźników
Po co nam wskaźniki? Wyobraźmy sobie, że chcemy zrobić funkcje, która zwiększa wartość danej zmiennej o ile. Na pierwszy rzut oka wydawałoby się, że poniższa funkcja wykona to, co oczekiwaliśmy. Niestety, czeka nas rozczarowanie.
void zwieksz(int liczba, int ile)
{
liczba += o_ile;
}
Jeżeli wywołamy tę funkcję zwieksz(jakas_zmienna, 5), to wartość jakas_zmienna nie zostanie zwiększona o 5 - funkcja zwieksz skopiuje jej wartość do parametru i utworzy swoją własną, nową zmienną, o takiej samej wartości, jak jakas_zmienna. Następnie zwiększy ją o 5, jednak nie zmieni to wartości jakas_zmienna, a jedynie jej kopie, utworzoną na potrzeby funkcji zwieksz.
Rozwiązanie? Wskaźniki! Utwórzmy sobie funkcję, która przyjmuje adres zmiennej typu int. Dzięki temu zwiększy się wartość spod adresu parametru, czyli wartość zmiennej, którą podaliśmy (a nie jej kopii).
#include <iostream>
using namespace std;
void zwieksz(int* liczba, int ile)
{
*liczba += ile;
}
// Oto sposób, w jaki należy wywołać tę funkcję
int main()
{
int liczba = 5;
zwieksz(&liczba, 5);
cout << liczba << endl; // wpisze "10"
// zwieksz(liczba, 5);
// ^^ BŁĄD ^^
// Program oczekuje adresu do liczby całkowitej, a nie liczby całkowitej
}
Trzeba tylko uważać, aby nie napisać
liczba += ile. Wtedy bowiem zmieni się wartość parametru, czyli adresu, a nie tego, co się pod nim znajduje.
Wygodne wskaźniki - referencja
Jeżeli nie chcemy pisać gwiazdeczek, możemy utworzyć referencję. Referencja to nic innego jak zmienna, która odnosi się do dokładnie tej samej wartości, o tym samym położeniu w pamięci. Innymi słowy, dzięki referencji możemy mieć dwie zmienne, które są dokładnie tym samym, a zmiana jednej z nich modyfikuje drugą.
#include <iostream>
using namespace std;
int main()
{
int liczba = 5;
int& tez_liczba = liczba;
liczba++;
cout << tez_liczba << endl; // wypisze "6"
tez_liczba++;
cout << liczba << endl; // wypisze "7"
}
Zmienne liczba i tez_liczba są powiązane - odnoszą się do tego samego adresu w pamięci, a co za tym idzie, możemy zmieniać jedną wartość, a druga też się zmieni.
Referencja jest szczególnie przydatna w przypadku parametrów funkcji, kiedy przekazujemy funkcji np. vector, bez jego kopiowania, tak, aby funkcja mogła edytować jego wartości, a po wyjściu z niej, zmienna oryginalna też była zmieniona.
#include <iostream>
#include <vector>
using namespace std;
void zwieksz_kazdy_element_wektora_o_1(vector<int>& wektor)
{
for (int i = 0; i < wektor.size(); i++) {
wektor[i]++;
}
}
int main()
{
vector<int> fajny_wektor = {2, 6, 1, 3, 2, 7};
zwieksz_kazdy_element_wektora_o_1(fajny_wektor);
for (int element : fajny_wektor) {
cout << element << ' ';
}
cout << endl;
// wypisze "3 7 2 4 3 8"
}

