Przykłady zastosowania i sposoby konwersji zmiennych jednego typu do zmiennych innego typu.

Menu


Jak skonwertować tekst na liczbę i odwrotnie.

    Sposoby konwersji tekstu na liczby zostały opisane w dziale Łańcuchy Znaków, więc nie będę tutaj tego wszystkiego przepisywał, podam jedynie opis najbardziej przydatnych (moim zdaniem) metod klasy AnsiString przeznaczonych do konwersji pomiędzy różnymi typami zmiennych.

ToInt() - metoda konwertująca zmienną typu String na int, np.:
int i = Edit1->Text.ToInt();
Przy czym obiekt Edit1 w treści musi zawierać tekst reprezentujący liczbę całkowitą.
 
ToIntDef() -

metoda konwertująca zmienną typu String na int z tą jednak różnicą, że jeśli konwersja się nie powiedzie to zwracana jest wartość domyślna podana w nawiasie, np.:
int i = Edit1->Text.ToIntDef(10);
Przy czym obiekt Edit1 w treści powinien zawierać tekst reprezentujący liczbę całkowitą, w przeciwnym razie zmiennej i zostanie przypisana wartość domyślna, w przykładzie będzie to liczba 10. Jako wartość domyślną można podawać tylko liczby.
 

ToDouble() -

metoda konwertująca zmienną typu String na double lub float, np.:
float i = Edit1->Text.ToDouble();
Przy czym obiekt Edit1 w treści musi zawierać tekst reprezentujący liczbę, jeżeli jest to liczba zmiennopozycyjna (ułamek dziesiętny) to część całkowita od dziesiętnej musi być rozdzielona przecinkiem a nie kropką, np.: 100,25.
 

CurrToStr -

metoda konwertująca zarówno zmienne int, float, double lub String na zmienną String, np.:
String a = CurrToStr(Edit1->Text);
Przy czym obiekt Edit1 w treści musi zawierać tekst reprezentujący jakąś wartość liczbową i może to być zarówno liczba całkowita jak i dziesiętna. Jednak konwersja typów String na String nie ma sensu, dlatego metoda ma znacznie większe zastosowanie przy konwersji zmiennych int, float lub double na typ String, np.:
int x = 10;
Edit1->Text = CurrToStr(x);
float y = 10.2;
Edit2->Text = CurrToStr(y);

 

CurrToStrF -

ta metoda działa podobnie jak CurrToStr z tą jednak różnicą, że pozwala formatować konwertowaną wartość na kilka sposobów, np.:
ffGeneral - jeżeli formatowana liczba zawiera wartość dziesiętną to liczba miejsc dziesiętnych zostaje ograniczona do czterech miejsc po przecinku, poza tym jeżeli po przecinku znajdują się same zera to zostają automatycznie usunięte:
float x = 100.23456;
Edit1-Text = CurrToStrF(x, ffGeneral, 2);

ffExponent - niestety nie rozumiem tego sposobu formatowania. Jeżeli ktoś wie o co z tym chodzi to proszę o kontakt i wyjaśnienie.
ffFixed - w wyniku tego formatowania do liczby całkowitej lub dziesiętnej zostają zwiększone miejsca po przecinku w ilości określonej przez wartość podaną po specyfikatorze formatu. Jeżeli konwertowana wartość jest liczbą całkowitą, to zostanie automatycznie sformatowana na liczbę dziesiętną a po przecinku zostaną wstawione zera:
float x = 91.2;
Edit1->Text = CurrToStrF(x, ffFixed, 4);
String a = "100,4";
Edit2->Text = CurrToStrF(a, ffFixed, 3);

ffNumber - działa podobnie do metody ffFixed z tą jednak różnicą, że formatowana liczba jest przedstawiana z separatorem tysiąca. Tak sformatowanej liczby nie można później przekonwertować w prosty sposób z powrotem na liczbę, trzeba najpierw usunąć wszystkie separatory tysiąca (np.: 1 000 000,2345):
float x = 1000000,2345;
Edit1->Text = CurrToStrF(x, ffNumber, 4);

ffCurrency - działa podobnie do metody ffNumber z tą jednak różnicą, że formatowana liczba oprócz separatora tysiąca, zawiera również symbol waluty zdefiniowany w systemie (np. zł):
float x = 1000,23;
Edit1->Text = CurrToStrF(x, ffCurrency, 2);

 

FloatToStr
Poprawiono błędny opis funkcji.
-

zasada stosowania jest podobna do tej stosowanej w przypadku CurrToStr. Funkcji używa się do konwersji liczb dziesiętnych na tekst, czyli zmiennych typu float lub double na zmienne typu String, np.:
float
x = 23.45678;
Edit1->Text = FloatToStr(x);

 

FloatToStrF
Poprawiono błędny opis funkcji.
-

zasada stosowania jest podobna do tej stosowanej w przypadku CurrToStrF. Funkcji używa się do konwersji liczb dziesiętnych na tekst, czyli zmiennych typu float lub double na zmienne typu String. Zasada stosowania specyfikatora formatów jest identyczna jak w przypadku funkcji CurrToStrF, np.:
float x = 2.2345;
Edit1->Text = FloatToStrF(x, ffNumber, 7, 2);
Jak widać w przykładzie pojawiają się dwa nowe elementy (zaznaczone na zielono). Pierwsza liczba określa dokładność konwertowanego tekstu przed przecinkiem, natomiast druga określa liczbę miejsc dziesiętnych (po przecinku).
Specyfikatory formatów nie ulegają zmianie: ffGeneral, ffExponent, ffFixed, ffNumber, ffCurrency.

 

StrToInt - metoda konwertująca tekst będący reprezentacją liczby całkowitej na liczbę całkowitą:
int x = StrToInt(Edit1->Text);
Uzyskany efekt będzie taki sam jak w przypadku metody ToInt().
 
StrToIntDef - metoda konwertująca zmienną typu String na int z tą jednak różnicą, że jeśli konwersja się nie powiedzie to zwracana jest wartość domyślna podana w nawiasie, np.:
int i = StrToIntDef(Edit1->Text, 10);
Przy czym obiekt Edit1 w treści powinien zawierać tekst reprezentujący liczbę całkowitą, w przeciwnym razie zmiennej i zostanie przypisana wartość domyślna, w przykładzie będzie to liczba 10. Jako wartość domyślną można podawać tylko liczby.
Uzyskany efekt będzie taki sam jak w przypadku metody ToIntDef().
 
StrToFloat - metoda konwertująca zmienną typu String na double lub float, np.:
float i = StrToFloat(Edit1->Text);
Przy czym obiekt Edit1 w treści musi zawierać tekst reprezentujący liczbę całkowitą lub dziesiętną. Jeżeli jest to liczba zmiennopozycyjna (ułamek dziesiętny) to część całkowita od dziesiętnej musi być rozdzielona przecinkiem a nie kropką, np.: 100,25. Tutaj występuje pewna rozbieżność, mianowicie jeżeli wprowadzamy liczbę dziesiętną bezpośrednio w kodzie programu to rozdzielamy część całkowitą od dziesiętnej kropką. Inaczej dzieje się jednak gdy już uruchomimy nasz program i wprowadzamy np. liczbę do obiektu Edit1 wtedy liczba dziesiętna powinna być rozdzielana przecinkiem.
Uzyskany efekt będzie taki sam jak w przypadku metody ToDouble().
 

...powrót do menu. 

Typy wariantowe.

    Jak można się domyślić typ wariantowy to taki rodzaj zmiennej, której można przypisać dowolną wartość, czyli może to być zarówno liczba lub znak, jak również łańcuch znaków, wskaźnik odwołanie lub tablica. Typ wariantowy ma zastosowanie wtedy gdy potrzebujemy zmiennej o typie modyfikowanym w czasie wykonywania programu. Żeby to dokładniej wyjaśnić posłużę się przykładem, tak więc umieszczamy  na formularzu cztery komponenty Edit1, Edit2, Edit3 i Button4 następnie tworzymy w pliku źródłowym prostą funkcję, którą nazwę Oblicz. Funkcja ta będzie dodawała do siebie dwie wartości typu Variant a następnie będzie zwracała wartość również typu Variant:

// Plik źródłowy np. Unit1.cpp
//--------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
{
}
//--------------------------------
Variant Oblicz(Variant x, Variant y)
{
 return x + y;
}
//--------------------------------

Teraz w zdarzeniu OnClick dla przycisku Button1 wywołujemy funkcję Oblicz. Najpierw wywołamy funkcję przekazując jej jako argumenty wartości typu String:

// Plik źródłowy np. Unit1.cpp
//--------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
{
}
//--------------------------------
Variant Oblicz(Variant x, Variant y)
{
 return x + y;
}
//--------------------------------
void __fastcall TForm1::Button1Click(TObject* Sender)
{
 Edit3->Text = VarToStr( Oblicz(Edit1->Text, Edit2->Text) );
}
//--------------------------------

W podanym przykładzie niezależnie od tego czy w właściwości Text obiektów Edit1 i Edit2 będzie łańcuch znaków czy liczba, funkcja oblicz "połączy" ze sobą de dwie wartości, żeby dokonać sumowania dwóch liczb trzeba wywołać funkcję Oblicz z wartościami liczbowymi, czyli np. z wartościami typu int, float, double itp.:

// Plik źródłowy np. Unit1.cpp
//--------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
{
}
//--------------------------------
Variant Oblicz(Variant x, Variant y)
{
 return x + y;
}
//--------------------------------
void __fastcall TForm1::Button1Click(TObject* Sender)
{
 Edit3->Text = VarToStr( Oblicz(Edit1->Text.ToDouble(), Edit2->Text.ToDouble()) );
}
//--------------------------------

Tak wywołana funkcja zsumuje argumenty i zwróci wynik, jednak w tym przypadku właściwość Text obiektów Edit1 i Edit2 musi zawierać wartości reprezentujące liczby.
   Reasumując zmienna typu Variant zezwala na pewną niedbałość i umożliwia tworzenie jednego typu zmiennych dla wartości różnych typów, eliminuje to konieczność ustalania z góry konwersji zmiennej jednego typu na drugi, ponieważ wszystkim zajmie się kompilator.

...powrót do menu. 

Przysłanianie zmiennych.

O tym, że pisząc kod programu należy nadawać zmiennym różne nazwy wiedzą zapewne wszyscy, czyli taki kod jest błędny:

// Plik źródłowy np. Unit1.cpp
//--------------------------------

 String a = "Globalna";
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 String a =
"Lokalna";
 Edit1->Text = a + a;
}

//--------------------------------

Przedstawiony kod jest błędny ponieważ utworzyłem dwie zmienne typu AnsiString, jedną globalną i jedną lokalną i obydwie mają taką samą nazwę, co w C++ jest niedopuszczalne, z tego względu, że kompilator w takiej sytuacji nie wiem o którą zmienną chodzi i w takiej sytuacji zawsze użyje zmiennej lokalnej pomijając zupełnie zmienną globalną, dlatego ten kod powinien wyglądać następująco:

// Plik źródłowy np. Unit1.cpp
//--------------------------------

 String a = "Globalna";
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 String b = "Lokalna";
 Edit1->Text = a + b;
}
//--------------------------------

Taki kod jest już poprawny.
Teraz pewnie niektórych zaskoczę, ale można używać zmiennych tych samych lub różnych typów o takich samych nazwach, trzeba je tylko przysłaniać, a do przysłaniania zmiennych służy podwójny dwukropek:

// Plik źródłowy np. Unit1.cpp
//--------------------------------

 String a = "Globalna";
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 String a = "Lokalna";
 Edit1->Text = ::a + a;
}
//--------------------------------

lub:

// Plik źródłowy np. Unit1.cpp
//--------------------------------

 String a;
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 ::a = "Globalna";
 String a = "Lokalna";
 Edit1->Text = ::a + a;
}
//--------------------------------

I tak to właśnie wygląda. Obowiązują pewne zasady, po pierwsze można zadeklarować tylko dwie zmienne o takiej samej nazwie, a po drugie jedna zmienna musi być lokalna, a druga globalna, po trzecie podwójny dwukropek zawsze odnosi się do zmiennej globalnej. Jaki jest sens stosowania zmiennych o takich samych nazwach - nie wiem.

...powrót do menu. 

Konwersja liczb arabskich na rzymskie.

Nigdy nie potrzebowałem dokonywać konwersji liczb arabskich na rzymskie, no ale nigdy nie wiadomo, kiedy to będzie potrzebne, dlatego przedstawiam tutaj prostą funkcję, ale skutecznie konwertującą liczby arabskie na rzymskie. W poradzie posłużę się obiektem Edit1 w którym zostaną wyświetlone liczby rzymski oraz obiektem CSpinEdit1 z zakładki Samples, który będzie podawał liczbę do konwersji:

// Plik źródłowy np. Unit1.cpp
//--------------------------------

AnsiString ArabicToRoman(int arabic)
{
 unsigned short int n[] = {1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000};
 AnsiString r[]         = {"I", "IV", "V", "IX", "X", "XL", "L", "XC", "C", "CD", "D", "CM", "M"};
 AnsiString roman = "";
 int i = (sizeof(n) / sizeof(n[0])) - 1;;
 do
 {
  while(arabic >= n[i])
  {
   arabic -= n[i];
   roman += r[i];
  }
 --i;
 }
 while(i >= 0);

 return roman;
}
//--------------------------------
void __fastcall TForm1::CSpinEdit1Change(TObject *Sender)
{
 Edit2->Text = ArabicToRoman(CSpinEdit1->Value);
}
//--------------------------------

...powrót do menu. 

Konwersja liczby zmiennopozycyjnej na łańcuch znaków.

W bibliotece stdlib.h istnieje funkcja umożliwiająca konwersję liczby zmiennopozycyjnej na łańcuch znaków:

char *ecvt(double value, int ndig, int *dec, int *sign);

Przedstawiona funkcja działa jednak zupełnie inaczej niż np. funkcja FloatToStr, czy FloatToStrF. Funkcja ecvt w odróżnieniu od innych przerabia liczbę zmiennopozycyjną na łańcuch znaków, co w istocie powoduje usunięcie przecinka i przedstawienie liczby w postaci wartości dziesiętnej z określoną przez parametr ndig liczbą cyfr, czyli mamy na przykład liczbę zmiennopozycyjną 9.876 (value = 9.876) i określamy w parametrze ndig, że długość łańcucha ma wynosić 10, w efekcie po konwersji otrzymamy wynik 9876000000. Oprócz tych dwóch parametrów funkcja podaje jeszcze informację o liczbie cyfr w wartości dziesiętnej liczby zmiennopozycyjnej - parametr dec, czyli jeśli mamy np. liczbę zmiennopozycyjną 143567.6789 to dec przyjmie wartość 6 bo 143567.- gdzie przy obliczaniu tej wartości cyfry po przecinku nie są brane pod uwagę z jednym wyjątkiem, jeżeli jako parametr value podamy liczbę zmiennopozycyjną w zapisie wykładniczym, to przy obliczaniu parametru dec brane są pod uwagę zarówno liczby przed jak i po przecinku. Ostatni parametr sign określa czy mamy do czynienia z liczbą dodatnią - przyjmie wartość 0, czy z liczbą ujemną - przyjmie wartość 1.

// Plik źródłowy np. Unit1.cpp
//--------------------------------

#include <stdlib.h>
#include <stdio.h>

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 char *string;
 double value;
 int dec, sign;
 int ndig = 10;
 char Buf[288];

 value = 9.876;
 string = ecvt(value, ndig, &dec, &sign);
 sprintf(Buf, "string = %s dec = %d sign = %d", string, dec, sign);
 Edit1->Text = (String)Buf;

 value = -123.45;
 ndig = 15;
 string = ecvt(value,ndig,&dec,&sign);
 sprintf(Buf, "string = %s dec = %d sign = %d", string, dec, sign);
 Edit2->Text = (String)Buf;

 value = 0.6789e5; // Zapis wykładniczy
 ndig = 5;
 string = ecvt(value,ndig,&dec,&sign);
 sprintf(Buf, "string = %s dec = %d sign = %d", string, dec, sign);
 Edit3->Text = (String)Buf;
}
//--------------------------------

...powrót do menu. 

Podział liczby zmiennopozycyjnej na cześć całkowitą i cześć ułamkową.

W bibliotece math.h znajdują się funkcje modf (dla liczb typu double) i modfl (dla liczb typu long double) umożliwiające rozbicie liczby zmiennopozycyjnej na dwie części, czyli na cześć całkowitą i cześć ułamkową.

double modf(double x, double *ipart);
long double modfl(long double x, long double *ipart);

Funkcje są proste w użyciu i nie wymagają jakiegoś szczególnego opisu. Przedstawię tutaj cztery różne przykłady wykorzystania  funkcji modf. Operacje na funkcji modfl wyglądają tak samo z tą różnicą, że należy stosować zmienne long double:

// Plik źródłowy np. Unit1.cpp
//--------------------------------

#include <stdio.h>
#include <math.h>

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 double fraction, integer;
 double number = 100000.567;
 char Buf[255];

 fraction = modf(number, &integer);
 sprintf(Buf, "Liczba: %lf zawiera całość: %lf i część ułamkową: %lf", number, integer, fraction);
 Edit1->Text = (String)Buf;
}
//--------------------------------

 

// Plik źródłowy np. Unit1.cpp
//--------------------------------

#include <math.h>

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 double fraction, integer;
 double number = 100013.567;
 char Buf[255];

 fraction = modf(number, &integer);
 Edit1->Text = Format("Cześć całkowita: %.f", ARRAYOFCONST((integer)));
 Edit2->Text = Format("Cześć ułamkowa: %.3f", ARRAYOFCONST((fraction)));
}
//--------------------------------

 

// Plik źródłowy np. Unit1.cpp
//--------------------------------

#include <math.h>

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 double fraction, integer;
 double number = 100013.567;
 char Buf[255];

 fraction = modf(number, &integer);
 TVarRec vr[] = {(int)integer, fraction};
 Edit1->Text = Format("Cześć całkowita: %d część ułamkowa: %.3f", vr, sizeof(vr));
}
//--------------------------------

 

// Plik źródłowy np. Unit1.cpp
//--------------------------------

#include <math.h>

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 double fraction, integer;
 double number = 100013.567;
 char Buf[255];

 fraction = modf(number, &integer);
 Edit1->Text = "Cześć całkowita: " + (String)integer;
 Edit2->Text = "Cześć ułamkowa: " + FloatToStrF(fraction, ffNumber, 7, 3);
}
//--------------------------------

...powrót do menu.