Przejdź do głównej zawartości

Wprowadzenie do zmiennych

W tej lekcji powiemy o tym, jak przechowywać różne wartości w trakcie działania programu, czyli jak korzystać ze zmiennych.

Motywacja

Żeby zrozumieć do czego są one przydatne, napiszmy program, który podnosi pewną liczbę do potęgi trzeciej, a następnie ją wyświetla:

main.cpp | Potęga trzecia
#include <iostream>

int main()
{
std::cout << 212 * 212 * 212;
}
Wynik
9528128

Jeśli teraz będziemy chcieli podnieść do trzeciej potęgi inną liczbę, będziemy musieli zmieniać trzy miejsca w kodzie. Jest to uciążliwe.

Rozwiązanie

Żeby nie zmieniać za każdym razem tylu rzeczy, załóżmy na chwilę, że liczba, którą podnosimy do potęgi nazywa się x. Jak wtedy będzie wyglądał kod?

#include <iostream>
int main()
{
std::cout << x * x * x;
}

Powyższy program na tym etapie, nie przejdzie etapu kompilacji, ponieważ kod źródłowy jeszcze nie jest w pełni poprawny. Żeby użyć x w obliczeniu, musimy napierw stworzyć zmienną o tej nazwie:

#include <iostream>
int main()
{
int x = 212;
std::cout << x * x * x;
}

Powyższy program skompiluje się i zadziała poprawnie.

Zmienna

Zmienna to pojemnik na dane określonego typu. Wartość zmiennej może się zmienić, ale jej typ nie.

Tworzenie zmiennych

W wyżej przedstawionym programie zmienną stworzyliśmy w ten sposób:

int x = 212;

Oto schemat tego zapisu:

Schemat tworzenia zmiennej (z inicjalizacją)

Ten niezwykle istotny zapis składa się z następujących elementów:

ElementOpis
inttyp zmiennej
xnazwa zmiennej
= 212inicjalizacja (przypisanie początkowej wartości)
;średnik, który kończy instrukcję

Typ zmiennej

Typ zmiennej mówi o tym, co może dana zmienna przechowywać. Tak jak wspominałem wcześniej, zmienna jest pojemnikiem przechowującym pewne rzeczy, określonego typu.

int to skrót od angielskiego słowa integer, który oznacza liczbę całkowitą, czyli taką bez części ułamkowej.

Oprócz użytego wyżej int dostępnych jest jeszcze wiele innych typów. Na tym etapie postaraj się zapamiętać następujące typy:

TypOpis
intliczba całkowita
floatliczba rzeczywista (z częścią ułamkową)
charpojedynczy znak
boolwartość logiczna, czyli prawda (true) albo fałsz (false)
uwaga

Wyżej wymienione typy zmiennych zawsze piszemy małą literą. Ma to znaczenie.

Przykłady tworzenia zmiennych:

// Bez inicjalizacji
// Zmienna będzie posiadać przypadkową wartość
int x;

// Tworzymy zmienną i przypisujemy jej wartość 30
int y = 30;

Nazwa zmiennej

Nazwa może być dowolna, z pewnymi istotnymi ograniczeniami:

  • ❌ nie może posiadać spacji (zabronione: ❌ abc def)
  • ❌ nie może zawierać większości specjalnych symboli
  • ✔ może składać się z:
    • ✔ znaków a-z oraz A-Z
    • ✔ cyfr, ale nie na początku (zabronione: ❌ 932abc)
    • ✔ podkreślnika _
Dodatkowe uwagi na temat podkreślnika

Podkreślniki są dozwolne w nazwach, jednak są dwa schematy nazewnictwa, które są zarezerwowane przez C++:

  • Podkreślnik na początku i duża litera zaraz po (zabronione: ❌ _Speed)
  • Podwójny podkreślnik gdziekolwiek: (zabronione: ❌ __xyz, ❌ user__name)

Możesz utworzyć tyle zmiennych ile tylko chcesz, jednak muszą one różnić się nazwami, bo są ich unikalnymi identyfikatorami (z pewnymi wyjątkami, ale o tym kiedy indziej).

Wielkość liter ma znaczenie:

int x = 30;
float X = 12.34f;

W wyżej przedstawionym kodzie, zmienne x oraz X to dwie różne zmienne!

Dobra praktyka

Najlepiej korzystaj z tylko angielskich nazw, czyli np:

float average;

zamiast

float srednia;

Inicjalizacja (wartość początkowa)

Inicjalizacja jest opcjonalnym krokiem w tworzeniu zmiennych. Gdy ją kreujemy, możemy albo zostawić ją bez chcianej wartości:

int x;

lub przypisać jej wartość początkową:

int x = 30;

Uwaga, słowo to: "inicjalizacja" ✔, nie "inicjacja" ❌

Brak inicjalizacji

Niezainicjowana zmienna, wewnątrz funkcji (np. wewnątrz main) będzie miała początkowo nieprzewidywalną wartość, nie zostanie wyzerowana do 0.

Pozostawienie zmiennej bez wartości początkowej może spowodować problemy w dalszej części kodu. Czasami jednak możemy celowo ją pominąć, ale o tym więcej później.

Nigdy nie można czytać ze zmiennej, gdy jest ona w stanie niezainicjowanym!

Średnik na końcu

Tylko dla przypomnienia 😀

int name = 40;

Możliwości

W tej sekcji jedynie pokażę Ci kilka możliwości korzystania ze zmiennych, natomiast ich omówienie znajduje się w następnej lekcji o zmiennych.

Wczytywanie danych od użytkownika

Aby wczytać dane od użytkownika, możemy stworzyć niezainicjializowaną zmienną, a nastęnie powiedzieć C++owi, aby wsadził do niej informacje wpisane przez użytkownika.

#include <iostream>

int main()
{
int age; // aktualny wiek (zmienna niezainicjalizowana!)
std::cout << "Podaj ile masz lat: ";
std::cin >> age;
std::cout << "Za 10 lat będziesz mieć: " << age + 10 << " lat.\n";
}

Rozbijanie skomplikowanych równań

Możemy używać zmiennych do reprezentowania wartości pośrednich w złożonych równaniach. Pomaga to uczynić kod bardziej czytelnym i utrzymywalnym.

🗒️ main.cpp
#include <iostream>

int main()
{
float current_pos = 10; // w metrach
float target_pos = 20; // w metrach
float current_speed = 2.5f; // w metrach na sekundę
float time_remaining = 0.5f; // w sekundach

// Oblicz końcową pozycję po zakończeniu czasu
// Obliczamy końcową pozycję po zakończeniu czasu
float ending_pos = current_pos + current_speed * time_remaining;

// Oblicz jak daleko od celu się znaleźliśmy
// Obliczamy jak daleko od celu się znaleźliśmy
float error = target_pos - ending_pos;

// Oblicz prędkość potrzebną do wylądowania idealnie w celu
// Obliczamy prędkość potrzebną do wylądowania idealnie w celu
float required_speed = (target_pos - current_pos) / time_remaining;

// Oblicz ile dodatkowej prędkości potrzebowaliśmy, aby wylądować bezpośrednio na celu
// Obliczamy ile dodatkowej prędkości potrzebowaliśmy, aby wylądować bezpośrednio na celu
float extra_speed_needed = required_speed - current_speed;

std::cout << "Wylądowaliśmy " << error << " metrów od celu.\n";
std::cout << "Musielibyśmy lecieć " << extra_speed_needed << "m/s szybciej, aby wylądować bezpośrednio na celu.";
}
Result (console)
We landed 8.75 meters away from the target.
We needed to go 17.5m/s faster to land on the target.

Powtórzenie

Podsumowując, nauczyliśmy się:

Dodatkowe wiadomości

Brak inicjalizacji

Przykład
int main() {
int x; // brak inicjalizacji
}

Niezainicjalizowana zmienna (bez przypisanej początkowej wartości), wewnątrz bloku funkcji (np. wewnątrz main-a) będzie na początku posiadała przypadkową wartość, nie będzie wyzerowana. Zostawienie zmiennej bez wartości początkowej może powodować problemy w dalszej części kodu. Czasami jednak intencjonalnie możemy to pomijać, ale o tym kiedy indziej.

Chociaż może się wydawać, że posiadanie możliwości zrobienia takiego błędu w języku jest dziwne, należy pamiętać, że czasem wykorzystuje się to celowo. Otrzymywanie danych wejściowych od użytkownika jest jednym z przypadków kiedy warto zostawić zmienną w niezainicjowanym stanie.

Konwersja typu

Zmienna posiada określony typ, którego nie można dowolnie zmieniać. Wartości, które w niej spróbujemy zapisać muszą być zgodne z jej typem. Wiele typów zostanie jednak przekonwertowanych automatycznie. Możemy na przykład przypisać wartość całkowitą (int) do zmiennej typu float (liczba rzeczywista). Wywołuje to konwersję z int na float:

Przykład
float y = 30; // OK

Przejście w drugą stronę jest nieco bardziej problematyczne. Zmienna typu int nie może przechowywać części ułamkowej, więc gdy spróbujemy do niej taką wartość zapisać, zostanie ona skonwertowana, lecz nie wystąpi żadne zaokrąglenie, tylko po prostu ucięcie części ułamkowej.

C++ nie robi tego przez zaokrąglanie - zamiast tego, obcina po prostu część ułamkową liczby. Na przykład, 3.1415 obcina się do 3.

⚠ Niejawna konwersja
int y = 30.5f; // OK, konwersja do 30, ale tracimy część ułamkową

Kompilator analizując kod może wystosować ostrzeżenie, że następuje niejawna konwersja. Niejawna dlatego, że takiego zapisu moglibyśmy użyć nieświadomie i uzyskać nie tą wartość co chcemy.

uwaga

Staraj się dopasowywać typy, kiedy tylko możesz!

Niejawne konwersje, takie jak float do int, powodują utratę informacji! W najlepszym przypadku może to powodować złe wyniki, w najgorszym nawet katastrofy.

Rakieta Ariane 5 V88 katastrofalnie eksplodowała 37 sekund po starcie z powodu błędnej konwersji z float na int, powodując utratę precyzji, która zatrzymała komputer nawigacyjny.

Wprowadzenie do zmiennych

W tej lekcji powiemy o tym, jak przechowywać różne wartości w trakcie działania programu, czyli jak korzystać ze zmiennych.

Motywacja

Żeby zrozumieć do czego są one przydatne, napiszmy program, który podnosi pewną liczbę do potęgi trzeciej, a następnie ją wyświetla:

main.cpp | Potęga trzecia
#include <iostream>

int main()
{
std::cout << 212 * 212 * 212;
}
Wynik
9528128

Jeśli teraz będziemy chcieli podnieść do trzeciej potęgi inną liczbę, będziemy musieli zmieniać trzy miejsca w kodzie. Jest to uciążliwe.

Rozwiązanie

Żeby nie zmieniać za każdym razem tylu rzeczy, załóżmy na chwilę, że liczba, którą podnosimy do potęgi nazywa się x. Jak wtedy będzie wyglądał kod?

#include <iostream>
int main()
{
std::cout << x * x * x;
}

Powyższy program na tym etapie, nie przejdzie etapu kompilacji, ponieważ kod źródłowy jeszcze nie jest w pełni poprawny. Żeby użyć x w obliczeniu, musimy napierw stworzyć zmienną o tej nazwie:

#include <iostream>
int main()
{
int x = 212;
std::cout << x * x * x;
}

Powyższy program skompiluje się i zadziała poprawnie.

Zmienna

Zmienna to pojemnik na dane określonego typu. Wartość zmiennej może się zmienić, ale jej typ nie.

Tworzenie zmiennych

W wyżej przedstawionym programie zmienną stworzyliśmy w ten sposób:

int x = 212;

Oto schemat tego zapisu:

Schemat tworzenia zmiennej (z inicjalizacją)

Ten niezwykle istotny zapis składa się z następujących elementów:

ElementOpis
inttyp zmiennej
xnazwa zmiennej
= 212inicjalizacja (przypisanie początkowej wartości)
;średnik, który kończy instrukcję

Typ zmiennej

Typ zmiennej mówi o tym, co może dana zmienna przechowywać. Tak jak wspominałem wcześniej, zmienna jest pojemnikiem przechowującym pewne rzeczy, określonego typu.

int to skrót od angielskiego słowa integer, który oznacza liczbę całkowitą, czyli taką bez części ułamkowej.

Oprócz użytego wyżej int dostępnych jest jeszcze wiele innych typów. Na tym etapie postaraj się zapamiętać następujące typy:

TypOpis
intliczba całkowita
floatliczba rzeczywista (z częścią ułamkową)
charpojedynczy znak
boolwartość logiczna, czyli prawda (true) albo fałsz (false)
uwaga

Wyżej wymienione typy zmiennych zawsze piszemy małą literą. Ma to znaczenie.

Przykłady tworzenia zmiennych:

// Bez inicjalizacji
// Zmienna będzie posiadać przypadkową wartość
int x;

// Tworzymy zmienną i przypisujemy jej wartość 30
int y = 30;

Nazwa zmiennej

Nazwa może być dowolna, z pewnymi istotnymi ograniczeniami:

  • ❌ nie może posiadać spacji (zabronione: ❌ abc def)
  • ❌ nie może zawierać większości specjalnych symboli
  • ✔ może składać się z:
    • ✔ znaków a-z oraz A-Z
    • ✔ cyfr, ale nie na początku (zabronione: ❌ 932abc)
    • ✔ podkreślnika _
Dodatkowe uwagi na temat podkreślnika

Podkreślniki są dozwolne w nazwach, jednak są dwa schematy nazewnictwa, które są zarezerwowane przez C++:

  • Podkreślnik na początku i duża litera zaraz po (zabronione: ❌ _Speed)
  • Podwójny podkreślnik gdziekolwiek: (zabronione: ❌ __xyz, ❌ user__name)

Możesz utworzyć tyle zmiennych ile tylko chcesz, jednak muszą one różnić się nazwami, bo są ich unikalnymi identyfikatorami (z pewnymi wyjątkami, ale o tym kiedy indziej).

Wielkość liter ma znaczenie:

int x = 30;
float X = 12.34f;

W wyżej przedstawionym kodzie, zmienne x oraz X to dwie różne zmienne!

Dobra praktyka

Najlepiej korzystaj z tylko angielskich nazw, czyli np:

float average;

zamiast

float srednia;

Inicjalizacja (wartość początkowa)

Inicjalizacja jest opcjonalnym krokiem w tworzeniu zmiennych. Gdy ją kreujemy, możemy albo zostawić ją bez chcianej wartości:

int x;

lub przypisać jej wartość początkową:

int x = 30;

Uwaga, słowo to: "inicjalizacja" ✔, nie "inicjacja" ❌

Brak inicjalizacji

Niezainicjowana zmienna, wewnątrz funkcji (np. wewnątrz main) będzie miała początkowo nieprzewidywalną wartość, nie zostanie wyzerowana do 0.

Pozostawienie zmiennej bez wartości początkowej może spowodować problemy w dalszej części kodu. Czasami jednak możemy celowo ją pominąć, ale o tym więcej później.

Nigdy nie można czytać ze zmiennej, gdy jest ona w stanie niezainicjowanym!

Średnik na końcu

Tylko dla przypomnienia 😀

int name = 40;

Możliwości

W tej sekcji jedynie pokażę Ci kilka możliwości korzystania ze zmiennych, natomiast ich omówienie znajduje się w następnej lekcji o zmiennych.

Wczytywanie danych od użytkownika

Aby wczytać dane od użytkownika, możemy stworzyć niezainicjializowaną zmienną, a nastęnie powiedzieć C++owi, aby wsadził do niej informacje wpisane przez użytkownika.

#include <iostream>

int main()
{
int age; // aktualny wiek (zmienna niezainicjalizowana!)
std::cout << "Podaj ile masz lat: ";
std::cin >> age;
std::cout << "Za 10 lat będziesz mieć: " << age + 10 << " lat.\n";
}

Rozbijanie skomplikowanych równań

Możemy używać zmiennych do reprezentowania wartości pośrednich w złożonych równaniach. Pomaga to uczynić kod bardziej czytelnym i utrzymywalnym.

🗒️ main.cpp
#include <iostream>

int main()
{
float current_pos = 10; // w metrach
float target_pos = 20; // w metrach
float current_speed = 2.5f; // w metrach na sekundę
float time_remaining = 0.5f; // w sekundach

// Oblicz końcową pozycję po zakończeniu czasu
// Obliczamy końcową pozycję po zakończeniu czasu
float ending_pos = current_pos + current_speed * time_remaining;

// Oblicz jak daleko od celu się znaleźliśmy
// Obliczamy jak daleko od celu się znaleźliśmy
float error = target_pos - ending_pos;

// Oblicz prędkość potrzebną do wylądowania idealnie w celu
// Obliczamy prędkość potrzebną do wylądowania idealnie w celu
float required_speed = (target_pos - current_pos) / time_remaining;

// Oblicz ile dodatkowej prędkości potrzebowaliśmy, aby wylądować bezpośrednio na celu
// Obliczamy ile dodatkowej prędkości potrzebowaliśmy, aby wylądować bezpośrednio na celu
float extra_speed_needed = required_speed - current_speed;

std::cout << "Wylądowaliśmy " << error << " metrów od celu.\n";
std::cout << "Musielibyśmy lecieć " << extra_speed_needed << "m/s szybciej, aby wylądować bezpośrednio na celu.";
}
Result (console)
We landed 8.75 meters away from the target.
We needed to go 17.5m/s faster to land on the target.

Powtórzenie

Podsumowując, nauczyliśmy się:

Dodatkowe wiadomości

Brak inicjalizacji

Przykład
int main() {
int x; // brak inicjalizacji
}

Niezainicjalizowana zmienna (bez przypisanej początkowej wartości), wewnątrz bloku funkcji (np. wewnątrz main-a) będzie na początku posiadała przypadkową wartość, nie będzie wyzerowana. Zostawienie zmiennej bez wartości początkowej może powodować problemy w dalszej części kodu. Czasami jednak intencjonalnie możemy to pomijać, ale o tym kiedy indziej.

Chociaż może się wydawać, że posiadanie możliwości zrobienia takiego błędu w języku jest dziwne, należy pamiętać, że czasem wykorzystuje się to celowo. Otrzymywanie danych wejściowych od użytkownika jest jednym z przypadków kiedy warto zostawić zmienną w niezainicjowanym stanie.

Konwersja typu

Zmienna posiada określony typ, którego nie można dowolnie zmieniać. Wartości, które w niej spróbujemy zapisać muszą być zgodne z jej typem. Wiele typów zostanie jednak przekonwertowanych automatycznie. Możemy na przykład przypisać wartość całkowitą (int) do zmiennej typu float (liczba rzeczywista). Wywołuje to konwersję z int na float:

Przykład
float y = 30; // OK

Przejście w drugą stronę jest nieco bardziej problematyczne. Zmienna typu int nie może przechowywać części ułamkowej, więc gdy spróbujemy do niej taką wartość zapisać, zostanie ona skonwertowana, lecz nie wystąpi żadne zaokrąglenie, tylko po prostu ucięcie części ułamkowej.

C++ nie robi tego przez zaokrąglanie - zamiast tego, obcina po prostu część ułamkową liczby. Na przykład, 3.1415 obcina się do 3.

⚠ Niejawna konwersja
int y = 30.5f; // OK, konwersja do 30, ale tracimy część ułamkową

Kompilator analizując kod może wystosować ostrzeżenie, że następuje niejawna konwersja. Niejawna dlatego, że takiego zapisu moglibyśmy użyć nieświadomie i uzyskać nie tą wartość co chcemy.

uwaga

Staraj się dopasowywać typy, kiedy tylko możesz!

Niejawne konwersje, takie jak float do int, powodują utratę informacji! W najlepszym przypadku może to powodować złe wyniki, w najgorszym nawet katastrofy.

Rakieta Ariane 5 V88 katastrofalnie eksplodowała 37 sekund po starcie z powodu błędnej konwersji z float na int, powodując utratę precyzji, która zatrzymała komputer nawigacyjny.