Typy zmiennych

  Dział ten jest wprowadzeniem do znaczenia danych i tego co można z nimi zrobić. W języku C++ występuje dużo różnych rodzajów zmiennch, służących do przechowywania wartości różnego typu. Każda zmienna ma swój typ i istnieją zasady co do możliwości używania zmiennych określonego typu. Nadawanie nazwy i typu zmiennej wewnątrz modułu lub funkcji nazywamy deklaracją zmiennej. Po zdeklarowaniu zmiennej można jej używać, jednak nowo utworzona zmienna nie jest wypełniana żadnymi wartościami, dopóki nie przypiszemy jej żadnej konkretnej wartości, może ona zawierać wartości przypadkowe.
  Wypełnienie zmiennej może odbywać się na wiele sposobów, ale najczęstszą metodą jest instrukcja przypisania. Najprostsza metoda przypisania może wyglądać tak:
int a = 0;
W podanym przykładzie najpierw zadeklarowałem zmienną typu int nadałem jej nazwę a i przypisałem jej wartość 0. Od tej chwili, dopóki coś innego nie wpłynie na tą zmienną, ma ona wartość 0. Symbol " = " nazywany jest operatorem przypisania. Jest on jednym z całej klasy takich symboli używanych w języku C++ i zwanych operatorami, które określają relacje lub działania między dowoma elementami. Średnik (;) znajdujący się na końcu instrukcji, jest sygnałem dla kompilatora, że tu kończy się instrukcja i każda instrukcja w języku C++ musi być zakończona średnikiem.
  Język C++ pozwala tworzyć stałe nazwane, które są bardzo podobne do zmiennych, jednak w odróżnieniu od nich stałych nie można zmieniać w instrukcjach przypisania ani innych konstrukcjach języka C++. Po wypełnieniu stałe nazwane są zamknięte i nie można ich ponownie otwierać, chociaż w każdej chwili można odczytać ich wartość.
  Deklarowanie stałych nazwanych jest podobne do deklarowania zmiennych tzn. deklaruje się je w tym samym miejscu wewnątrz funkcji i kończy średnikiem, jednak nazwę typu poprzedza się słowem zastrzeżonym const, po którym następuje nazwa zmiennej z operatorami przypisania i wartością:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
const int a = 100;
int b;

b = a + 10;
}

W podanym przykładzie zadeklarowałem stałą nazwaną o nazwie a i wartości 100 i gdziekolwiek zostanie użyta ta nazwa w programie, kompilator podstawi pod nią wartość 100.
W dalszej części działu zostaną omówione różne typy zmiennych.

Menu



Typy całkowite

  Typy całkowite zawierają wartości liczbowe bez części dziesiętnej, np.: 100 jest liczbą całkowitą ale już 100,23 jest liczbą zmiennopozycyjną.
  C++ Builder definiuje trzy wielkości liczb całkowitych, które mogą być zarówno liczbami dodatnimi jak i ujemnymi. Tabela wymienia typy całkowite, ich zakresy i wielkości pamięci potrzebne do ich reprezentowania.

Nazwa

Zakres

Reprezentacja

  char

  -128 ... 127

  8 bitów

  signed char

  -128 ... 127

  8 bitów

  unsigned char

  0 ... 255

  8 bitów

  short int

  -32768 ... 32767

  16 bitów

  signed short int

  -32768 ... 32767

  16 bitów

  unsigned short int

  0 ... 65535

  16 bitów

  int

  -2147483648 ... 214783647

  32 bity

  signed int

  -2147483648 ... 214783647

  32 bity

  unsigned int

  0 ... 4294967296

  32 bity

  long int

  -2147483648 ... 214783647

  32 bity

  signed long int

  -2147483648 ... 214783647

  32 bity

  unsigned long int

   ... 4294967296

  32 bity


  Nasuwa się pytanie po co tyle zmiennych? Może po to, że czasami potrzebujemy użyć małych wartości, które mieszczą się na 8 bitach, lub większych 16 bitowych pozwala to oszczędzać pamięć. Jeżeli zamierzamy operować na małych wartościach liczbowych np. na 1 000 wartości liczbowych z których żadna nie osiągnie większej wartości niż 100 to typ char pomieści takie wartości i zajmie tylko 10 000 bajtów pamięci podczas gdy typ int zająłby 40 000 bajtów pamięci. Trzy z czterech bajtów pamięci byłyby marnowane ponieważ wyliczane wartości nigdy nie byłyby większe niż 100, a jak już zaznaczyłem ta liczba swobodnie mieści się na 8 bitach.
Jednak mniejsze nie znaczy szybciej ponieważ obliczenia wykonywane na liczbach całkowitych 8 i 16 bitowych są powolniejsze od obliczeń wykonywanych na liczbach całkowitych 32 bitowych. Dlaczego? Dlatego, że kompilator języka C++ generuje kod 32 bitowy przeznaczony dla procesorów 32 bitowych. Procesor 32 bitowy zawsze robi obliczenia na liczbach 32 bitowych, może wykonywać obliczenia z mniejszymi wartościami, ale tylko umieszczając je w 32 bitowych grupach i ignorując puste miejsca. Dodatkowe operacje polegające na wydzieleniu wartośći 8 bitowych z grup 32 bitowych powodują, że takie obliczenia są wolniejsze.

...powrót do menu.


Typy zmiennopozycyjne

  Liczba zmiennopozycyjna jest liczbą z częścią ułamkową i przecinkiem dziesiętnym (ale uwaga wewnątrz kodu źródłowego liczby zmiennopozycyjne nie są odzielane przecinkiem lecz kropką) oddzielającym część ułamkową od części dziesiętnej. C++ Builder zawiera kilka różnych typów danych dla wartości zmiennopozycyjnych.

Nazwa

Zakres

Liczba znaczących cyfr

  float

  1,17x10-38 ... 3,4x1038

  6

  double

  2,22x10-308 ... 1,79x10308

  15

  long double

  3,36x10-4932 ... 1,18x104932

  18


  Każdy typ zmiennopozycyjny ma swój zakres, który jest szerokością wartości, jakie dany typ mpoże pomieścić, lecz dodatkowo występują tutej cyfry znaczące. W typach całkowitych wartości mają dokładność bezwzględną, natomiast typy zmiennopozycyjne pozwalają wyrażać bardzo duże wartości, ale nie oznacza to, że każda ostatnia z tych cyfr jest dokładna. Typy zmiennopozycyjne są mało precyzyjne ponieważ po cyfrach znaczących (tak jak to podano w tabeli) np. float po 6 cyfrach wartość zmiennej zostanie zaokrąglona.

WAŻNE!!!

Jeżeli zmienna określonego typu bez znaku (ujemnego) osiągnie swoją maksymalną wartość, zostaje "przewinięta" i zaczyna od 0, podobnie jak licznik kilometrów w samochodzie.
Trochę inaczej wygląda sprawa z liczbami ze znakiem (ujemnym). Gdy skończą się liczby dodatnie tzn. gdy zmienna osiągnie swoją maksymalną wartość dodatnią to przejdzie do największej liczby ujemnej, a potem będzie odliczała do zera potem liczby dodatnie aż do osiągnięcia maksimum i spowrotem do największej liczby ujemnej.

...powrót do menu.


Typy znakowe - char

  Zmienne znakowe (typu char) mają rozmiar jednego bajtu (8 bitów), co wystarczy do przechowywania jednej z 256 wartości. Typ char może być interpretowany jako mała liczba (od 0 do 255) lub jako element zestawu kodów ASCII (American Standard Code for Information Interchange). Zestaw znaków ASCII (czytaj: eski) oraz jego odpowiedznik ISO (International Standards Organization) służą do kodowania wszystkich liter alfabetu łacińskiego, cyf oraz znaków przestankowych.
  W kodzie ASCII mała litera "a" ma przypisaną wartość 97. Wszystkie duże i małe litery, wszystkie cyfry oraz wszystkie znaki przestankowe mają przypisane wartości pomiędzy 0 a 127. Dodatkowe 128 znaków i symboli jest zarezerwowane dla wykorzystania przez producenta komputera, choć standard kodowania stosowany przez firmę IBM stał się niejako "obowiązkowy".
  Gdy w zmiennej typu char umieszczasz znak, to w rzeczywistości jest on liczbą z zakresu od 0 do 255. Należy jednak zdawać sobie sprawę z różnicy pomiędzy wartością a znakiem np.: 5 i "5" to nie jest to samo ponieważ 5 jest wartością i ma wartość 5 natomiast "5" jest znakiem i ma wartość 53 tak jak podałem wcześniej litera "a" ma wartość 97.
  Łancuch znakowy jest tablicą znakową o stałej długości zakończoną znakiem 0 (jest to wartość 0 a nie znak "0"). Typ char deklarujemy przypisując mu nazwę, po której następuje liczba ujęta w nawiasy kwadratowe określająca maksymalną liczbę znaków, jaką łańcuch może zawierać włącznie z końcowym znakiem pustym. Jeżeli na przykład jest nam potrzebny łańcuch przechowujący 11 znaków drukowanych "Hello World", zdeklarujemy go nastęująco:

   char MyString[12]; // 11 znaków plus znak pusty

Żeby manipulować zmienną typu char należy wywoływać funkcje akceptujące łańcuchy jako parametry. W przypadku zmiennych całkowitych i zmiennopozycyjnych można im nadać wartość poprzez przypisanie np.:

int value = 10; // zmiennej value przypisano wartość 10.

Gdybyśmy chcieli w ten sam sposób przypisać wartość zmiennej typu char to kompilator zwróci komunikat o błędzie np.:

char value[3] = 10; // W żadnym razie to jest nie do przyjęcia, instrukcja przypisania tutej nie zadziała.

W takim przypadku kompilator wyświetli komunikat: "Cannot convert 'int' to 'char[3]'.".
Aby zainicjować tablicę znakową, trzeba wywołać funkcję strcpy w następujący sposób:

char MyString[12];
strcpy(MyString, "Hello World");
W ten sposób zmiennej MyString przypisaliśmy wartość "Hello World" czyli łańcuch znaków, a co jeśli chcielibyśmy przypisać jej wartość liczbową? W takim przypadku trzeba się posłużyć specyfikacją formatu:


Niżej pokaże sposoby przypisywania wartości zmiennej typu char z wykorzystaniem funkcji sprintf, jednak żeby używać tej funkcji należy w pliku źródłowym (np. Unit1.cpp) importować w sekcji include plik stdio.h, np.: #include <stdio.h>. Potem można już bez problemu wywołać funkcję sprintf:

char value[200];

sprintf(value, "%d", 10);
Label1->Caption = value;
Na etykiecie Label1 ukaże się: 10.

sprintf(value, "%5d", 10);
Label1->Caption = value;
Na etykiecie Label1 ukaże się: 10 ale przesunięte o 5 miejsc do tyłu.

sprintf(value, "%f", 10);
Label1->Caption = value;
Na etykiecie Label1 ukaże się: 1.062780013808078036200000000000000000000e+269 dlatego, że specyfikator formatu "%f" oczekuje podania jako wartość liczby zmiennopozycyjnej

sprintf(value, "%f", 10.0);
Label1->Caption = value;
Na etykiecie Label1 ukaże się: 10.000000.

sprintf(value, "%.f", 10.0);
Label1->Caption = value;
Na etykiecie Label1 ukaże się: 10.

sprintf(value, "%.2f", 10.0);
Label1->Caption = value;
Na etykiecie Label1 ukaże się: 10.00 ponieważ liczba 2 po kropce i przed f określa liczbę miejsc po przecinku, które zostaną uwzględnione w formatowaniu zmiennej.

  Dla liczb rzeczywistych można podawać szerokość pola i liczbę miejsc po przecinku (kropce dziesiętnej) lub tylko liczbę cyfr po przecinku.

sprintf(value, "%c", 'a');
Label1->Caption = value;
Na etykiecie Label1 ukaże się: a lecz należy zwrócić uwagę na to, że użyłem tutej pojedynczego cudzysłowia (') a nie podwujnego ("). W przypadku użycia cudzysłowia podwujnego zostalby wyświetlony znak s.

sprintf(value, "%s", "Hello World");
Label1->Caption = value;
Na etykiecie Label1 ukaże się: Hello World.

  Inna powszechnie stosowana funkcja to strcat służąca do wstawiania tekstu w zmienną zawierającą już tekst, np.:

sprintf(value, "%s", "Ten tekst już jest");
strcat(value, " a ten tekst został dodany");
Label1->Caption = value;
Na etykiecie Label1 ukaże się: Ten tekst już jest a ten tekst został dodany.

  Kolejna funkcja strlen zwraca długość łańcucha:

Label1-Caption = strlen("Hello World");
Na etykiecie Label1 ukaże się: 11.

  Typ char nie jest szczególnie wygodny w użyciu, ale na szczęście istnieją zmienne typu String, które obsługują łańcuchy znaków i można im nadawać wartości poprzez przypisywanie.

...powrót do menu.