Czym są zmienne w C++?
Zmienne stanowią fundament każdego języka programowania, w tym C++. Można je porównać do pojemników, w których przechowujemy dane podczas działania programu. Każda zmienna w C++ ma określony typ, nazwę oraz wartość. Typ zmiennej określa rodzaj danych, jakie może ona przechowywać, a także ilość pamięci, jaką zajmuje w systemie.
Podstawowa składnia deklaracji zmiennej w C++ wygląda następująco:
typ_zmiennej nazwa_zmiennej = wartość_początkowa;
Na przykład:
int liczba = 10;
double pi = 3.14159;
char znak = 'A';
Podstawowe typy zmiennych w C++
C++ oferuje szereg wbudowanych typów danych, które można podzielić na kilka głównych kategorii:
Kategoria | Typy | Zastosowanie |
---|---|---|
Całkowitoliczbowe | int, short, long, long long | Liczby całkowite (bez części ułamkowej) |
Zmiennoprzecinkowe | float, double, long double | Liczby rzeczywiste (z częścią ułamkową) |
Znakowe | char, wchar_t, char16_t, char32_t | Pojedyncze znaki |
Logiczne | bool | Wartości logiczne (prawda/fałsz) |
Void | void | Brak typu (używany głównie dla funkcji) |
Typy całkowitoliczbowe
Typy całkowitoliczbowe służą do przechowywania liczb całkowitych (bez części ułamkowej). W C++ mamy do dyspozycji następujące typy całkowitoliczbowe:
1. int
Podstawowy typ całkowitoliczbowy, najczęściej używany w praktyce programistycznej. Typowo zajmuje 4 bajty pamięci (32 bity), co pozwala na przechowywanie wartości w zakresie od \(-2^{31}\) do \(2^{31}-1\), czyli od -2,147,483,648 do 2,147,483,647.
int liczba = 42;
int ujemna_liczba = -100;
2. short
Zajmuje mniej pamięci niż int (zwykle 2 bajty), co ogranicza zakres wartości do \(-2^{15}\) do \(2^{15}-1\), czyli od -32,768 do 32,767. Przydatny, gdy chcemy oszczędzać pamięć, a wiemy, że wartości będą niewielkie.
short mala_liczba = 1000;
3. long
Na większości systemów 32-bitowych ma taki sam rozmiar jak int (4 bajty), ale na systemach 64-bitowych może zajmować 8 bajtów, co zwiększa zakres wartości.
long duza_liczba = 1000000L; // L na końcu oznacza literal typu long
4. long long
Wprowadzony w standardzie C++11, gwarantuje co najmniej 8 bajtów pamięci, co daje zakres od \(-2^{63}\) do \(2^{63}-1\), czyli od -9,223,372,036,854,775,808 do 9,223,372,036,854,775,807.
long long bardzo_duza_liczba = 9000000000000000000LL; // LL oznacza literal typu long long
Modyfikatory typów całkowitoliczbowych
Każdy z powyższych typów może być dodatkowo zmodyfikowany przez słowa kluczowe:
- signed – pozwala na przechowywanie wartości ujemnych i dodatnich (domyślne zachowanie)
- unsigned – pozwala na przechowywanie tylko wartości nieujemnych, ale podwaja górny zakres
Na przykład:
unsigned int tylko_dodatnie = 4000000000; // wartość poza zakresem zwykłego int
signed short z_minusem = -200;
Poniższa tabela przedstawia typowe zakresy dla różnych typów całkowitoliczbowych:
Typ | Typowy rozmiar | Minimalny zakres | Maksymalny zakres |
---|---|---|---|
short | 2 bajty | -32,768 | 32,767 |
unsigned short | 2 bajty | 0 | 65,535 |
int | 4 bajty | -2,147,483,648 | 2,147,483,647 |
unsigned int | 4 bajty | 0 | 4,294,967,295 |
long | 4 bajty (32-bit) 8 bajtów (64-bit) |
-2,147,483,648 lub mniej | 2,147,483,647 lub więcej |
long long | 8 bajtów | -9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 |
Typy zmiennoprzecinkowe
Typy zmiennoprzecinkowe (rzeczywiste) służą do przechowywania liczb z częścią ułamkową. W C++ mamy trzy podstawowe typy zmiennoprzecinkowe:
1. float
Typ o pojedynczej precyzji, zajmujący 4 bajty pamięci. Zapewnia precyzję około 7 cyfr dziesiętnych. Zakres wartości wynosi w przybliżeniu od \(1.2 \times 10^{-38}\) do \(3.4 \times 10^{38}\).
float pi_przyblizenie = 3.14159f; // f na końcu oznacza literal typu float
2. double
Typ o podwójnej precyzji, zajmujący 8 bajtów pamięci. Zapewnia precyzję około 15 cyfr dziesiętnych. Zakres wartości wynosi w przybliżeniu od \(2.3 \times 10^{-308}\) do \(1.7 \times 10^{308}\). Jest to najczęściej używany typ zmiennoprzecinkowy ze względu na dobry kompromis między precyzją a wydajnością.
double pi_dokladniej = 3.141592653589793;
3. long double
Typ o rozszerzonej precyzji, zajmujący zwykle 10 lub 16 bajtów pamięci (zależnie od kompilatora i systemu). Zapewnia jeszcze większą precyzję niż double, ale kosztem wydajności.
long double pi_bardzo_dokladnie = 3.1415926535897932384626433832795L; // L oznacza literal typu long double
Poniższy wykres przedstawia porównanie precyzji typów zmiennoprzecinkowych:
Typy znakowe
Typy znakowe służą do przechowywania pojedynczych znaków. W C++ mamy następujące typy znakowe:
1. char
Podstawowy typ znakowy, zajmujący 1 bajt pamięci. Może przechowywać znaki ASCII oraz wartości liczbowe od -128 do 127 (dla signed char) lub od 0 do 255 (dla unsigned char).
char litera = 'A';
char cyfra = '7';
char znak_specjalny = '@';
Warto pamiętać, że w C++ typ char może być traktowany zarówno jako typ znakowy, jak i jako mały typ całkowitoliczbowy:
char litera = 'A';
int kod_ascii = litera; // kod_ascii będzie miał wartość 65 (kod ASCII dla 'A')
2. wchar_t, char16_t, char32_t
Te typy zostały wprowadzone do obsługi znaków Unicode i innych rozszerzonych zestawów znaków:
- wchar_t – szeroki znak, zwykle 2 lub 4 bajty (zależnie od systemu)
- char16_t – 2-bajtowy znak (UTF-16)
- char32_t – 4-bajtowy znak (UTF-32)
wchar_t szeroki_znak = L'ł'; // L oznacza literal typu wchar_t
char16_t znak_utf16 = u'ę'; // u oznacza literal typu char16_t
char32_t znak_utf32 = U'🙂'; // U oznacza literal typu char32_t
Typ logiczny (boolean)
Typ bool
służy do przechowywania wartości logicznych: prawda (true
) lub fałsz (false
). Zajmuje zwykle 1 bajt pamięci, choć teoretycznie potrzebuje tylko 1 bitu.
bool prawda = true;
bool falsz = false;
bool wynik = (10 > 5); // wynik będzie miał wartość true
bool inny_wynik = (3 == 7); // inny_wynik będzie miał wartość false
Typ bool
jest szczególnie przydatny w instrukcjach warunkowych:
bool czy_pelnoletni = (wiek >= 18);
if (czy_pelnoletni) {
cout << "Możesz wejść na stronę" << endl;
} else {
cout << "Dostęp zabroniony" << endl;
}
Typ void
Typ void
oznacza "brak typu" i jest używany głównie w trzech kontekstach:
1. Funkcje bez wartości zwracanej
void powitaj() {
cout << "Witaj świecie!" << endl;
// Funkcja nic nie zwraca
}
2. Funkcje bez parametrów
int pobierz_liczbe(void) {
int x;
cin >> x;
return x;
}
3. Wskaźniki ogólnego przeznaczenia
void* wskaznik;
// Wskaźnik void* może przechowywać adres dowolnego typu danych
// ale wymaga jawnego rzutowania przed użyciem
Typy pochodne
Oprócz typów podstawowych, C++ oferuje również typy pochodne, które są tworzone na bazie typów podstawowych:
1. Tablice
Tablice przechowują wiele wartości tego samego typu w ciągłym obszarze pamięci.
int liczby[5] = {1, 2, 3, 4, 5};
char napis[10] = "Hello"; // Tablica znaków
2. Wskaźniki
Wskaźniki przechowują adresy pamięci innych zmiennych lub obiektów.
int liczba = 42;
int* wskaznik = &liczba; // wskaznik przechowuje adres zmiennej liczba
cout << *wskaznik; // Wyświetli 42 (wartość pod adresem przechowywanym przez wskaznik)
3. Referencje
Referencje są aliasami (innymi nazwami) dla istniejących zmiennych.
int liczba = 42;
int& referencja = liczba; // referencja odnosi się do zmiennej liczba
referencja = 100; // Zmienia wartość zmiennej liczba na 100
Typy zdefiniowane przez użytkownika
C++ pozwala na tworzenie własnych typów danych za pomocą:
1. Struktury (struct)
struct Osoba {
string imie;
string nazwisko;
int wiek;
};
Osoba jan = {"Jan", "Kowalski", 30};
2. Klasy (class)
class Punkt {
private:
double x, y;
public:
Punkt(double x_val, double y_val) : x(x_val), y(y_val) {}
double odleglosc() {
return sqrt(x*x + y*y);
}
};
Punkt p(3.0, 4.0);
3. Unie (union)
union Wartosc {
int i;
float f;
char c;
};
Wartosc w;
w.i = 10; // Teraz w.i ma wartość 10, ale w.f i w.c mają nieokreślone wartości
4. Wyliczenia (enum)
enum Kolor {CZERWONY, ZIELONY, NIEBIESKI};
Kolor wybrany = ZIELONY;
5. Wyliczenia z zakresem (enum class) - C++11
enum class Status {OK, BLAD, OSTRZEZENIE};
Status wynik = Status::OK;
Aliasy typów
C++ umożliwia tworzenie aliasów (alternatywnych nazw) dla istniejących typów:
1. Słowo kluczowe typedef
typedef unsigned long ulong;
ulong duza_liczba = 1000000UL;
2. Słowo kluczowe using (C++11)
using liczba_calkowita = int;
liczba_calkowita x = 42;
Automatyczne wnioskowanie typu (C++11)
Od C++11 można używać słowa kluczowego auto
, aby kompilator sam wywnioskował typ zmiennej na podstawie przypisanej wartości:
auto liczba = 42; // int
auto pi = 3.14159; // double
auto znak = 'A'; // char
auto tekst = "Hello"; // const char*
Jest to szczególnie przydatne przy złożonych typach:
std::vector liczby = {1, 2, 3, 4, 5};
auto iterator = liczby.begin(); // std::vector::iterator
Zmienne globalne i lokalne
W C++ zmienne mogą mieć różny zakres widoczności i czas życia:
1. Zmienne lokalne
Zmienne zadeklarowane wewnątrz funkcji lub bloku kodu są widoczne tylko w tym bloku i istnieją tylko podczas jego wykonywania:
void funkcja() {
int x = 10; // zmienna lokalna
// x jest widoczna tylko wewnątrz tej funkcji
}
// Tutaj x nie jest już dostępna
2. Zmienne globalne
Zmienne zadeklarowane poza wszystkimi funkcjami są widoczne w całym programie i istnieją przez cały czas jego działania:
int globalna = 100; // zmienna globalna
void funkcja() {
cout << globalna; // Można używać zmiennej globalnej
globalna = 200; // Można modyfikować zmienną globalną
}
Należy jednak pamiętać, że nadużywanie zmiennych globalnych może prowadzić do trudnych do wykrycia błędów i utrudniać utrzymanie kodu.
3. Zmienne statyczne
Zmienne statyczne zachowują swoją wartość między wywołaniami funkcji:
void licznik() {
static int liczba_wywolan = 0; // Inicjalizowana tylko raz
liczba_wywolan++;
cout << "Funkcja została wywołana " << liczba_wywolan << " razy" << endl;
}
Stałe w C++
Stałe to zmienne, których wartości nie można zmodyfikować po inicjalizacji:
1. Słowo kluczowe const
const double PI = 3.14159265359;
const int MAX_UZYTKOWNIKOW = 100;
2. Stałe w czasie kompilacji (C++11)
constexpr int KWADRAT(int x) {
return x * x;
}
constexpr int wynik = KWADRAT(5); // Obliczane podczas kompilacji
Konwersje typów
W C++ można konwertować wartości między różnymi typami danych:
1. Konwersje niejawne
Kompilator automatycznie konwertuje niektóre typy:
int i = 42;
double d = i; // Niejawna konwersja z int na double (bezpieczna)
double pi = 3.14159;
int zaokraglone = pi; // Niejawna konwersja z double na int (potencjalna utrata danych)
2. Konwersje jawne (rzutowanie)
C++ oferuje kilka sposobów jawnej konwersji typów:
Styl C (stary):
double pi = 3.14159;
int zaokraglone = (int)pi; // Rzutowanie w stylu C
Funkcje rzutowania (nowoczesny C++):
double pi = 3.14159;
int zaokraglone = static_cast(pi); // Preferowany sposób w C++
Inne operatory rzutowania w C++:
dynamic_cast
- bezpieczne rzutowanie w hierarchii klasconst_cast
- usuwanie kwalifikatorów const/volatilereinterpret_cast
- niskopoziomowe konwersje (niebezpieczne)
Podsumowanie
Typy zmiennych w C++ stanowią fundament języka, pozwalając na precyzyjne określenie, jakie dane będą przechowywane i jak będą przetwarzane. Zrozumienie typów danych i ich właściwości jest kluczowe dla tworzenia efektywnego, bezpiecznego i poprawnego kodu.
Wybór odpowiedniego typu zmiennej powinien uwzględniać:
- Zakres wartości, jakie zmienna będzie przechowywać
- Wymaganą precyzję (dla typów zmiennoprzecinkowych)
- Zużycie pamięci
- Wydajność operacji na danym typie
- Czytelność i intencje kodu
Nowoczesny C++ oferuje wiele narzędzi ułatwiających pracę z typami, takich jak auto
, using
, czy constexpr
, które warto wykorzystywać dla zwiększenia czytelności i bezpieczeństwa kodu.