Змяненне (прывядзенне) тыпаў і значэнняў
У мове Pascal існуе вельмі магутны сродак, які дазваляе абысці ўсе магчымыя абмежаванні на сумяшчальнасць тыпаў ці значэнняў (напрыклад, у аператары «:=»). Гэта аперацыя прывядзення тыпаў. Яна прымяняецца толькі для пераменных і значэнняў.
Сутнасць гэтай аперацыі ў наступным. Пры вызначэнні тыпу мы вызначаем форму захавання інфармацыі ў аператыўнай памяці, і пераменная дадзенага тыпу будзе прадстаўлена ў памяці наперад вядомай структурай. Але калі «паглядзець» на яе вобраз у памяці з пункту гледжання машыннага ўяўлення другога тыпу, тады можна будзе трактаваць тое ж самае значэнне як значэнне, прыналежнае да другога тыпу.
Фармат аперацыі прывядзення тыпаў:
Імя_тыпу (пераменная_ці_значэнне);
Гэта імя_тыпу павінна быць вядома ў праграме (азначана праграмістам або стандартнае).
Прывядзенне тыпаў не перавызначае тыпы пераменных, а толькі дае магчымасць парушыць правілы сумяшчэння тыпаў пры ўмове, што адпаведныя значэнні сумяшчальныя ў машынным уяўленні.
Прыклад.
VAR Si : 0..255;
Тады аператар Si:='A' дасць памылку на этапе кампіляцыі, а аператар Char(Si):='A' дазволіць зрабіць наданне значэння. Магчымы і другі падыход: Si:=Ord('A'), у гэтым выпадку вынік вяртаецца як Byte.
Аналагічна змяненню тыпу пераменных можна змяняць уласна тып значэнняў, а таксама выніковы тып выразаў, г. зн. дазволены такія пераўтварэнні:
Boolean(1) | Гэта лагічнае значэнне TRUE |
Longint(1) | Гэта 1, размешчаная ў 4 байтах |
Char(130-1) | Сімвал з кодам ASCII нумар 129 |
Integer('Y') | Код сімвала 'Y' у фармаце Integer, (ord('Y') вяртае вынік як Byte) |
Новы тып можа быць даўжэйшым ці карацейшым, чым першапачатковы тып значэння.
Прывядзенне тыпаў як пераменных, так і значэнняў – нетрывіяльная аперацыя. Яна патрабуе даволі высокага ўзроўню ведаў тэхнічных падрабязнасцей мовы. Напрыклад, трэба ведаць, як захоўваюцца складаныя тыпы даных (масівы, запісы, мноствы), адрасы, лікі, радкі ў памяці, якія памеры ім адводзяцца. Прывядзенне тыпаў мае сэнс толькі пры супастаўнасці машынных уяўленняў значэнняў. Успомнім, што цэлыя і сапраўдныя значэнні маюць зусім рознае машыннае кадзіраванне. Значыць, прывядзенне цэлых пераменных да сапраўдных тыпаў і наадварот – вельмі рызыкоўная аперацыя.
Калі адзін парадкавы тып пераўтвараецца ў іншы, такое пераўтварэнне можа прывесці да ўсячэння ці павелічэння памераў памяці, пры параўнанні з зыходным значэннем. Пры гэтым можна атрымаць «дрэнныя» адказы:
VAR li : Longint; i : Integer;
BEGIN
li := 1234567; {>32767}
I := Integer(li+1);
Writeln(i);
END.
Першапачаткова ў пераменнай l маем: (1 234 567)10 = (12D 687)16 Þ Þ Longint. Пераменная lі атрымае значэнне двух апошніх байтаў, пры гэтым старэйшы біт гэтага поля змяшчае значэнне 1, г. зн. пераменная і будзе мець адмоўнае значэнне і надрукуецца –10 616. Гэта добра відаць з наступнай схемы.
Заўвага 1. Пры прывядзенні значэння ў больш шырокі тып (напрыклад, Longint(1)) значэнні будуць цалкам запісаны ў малодшыя байты, калі ж значэнне прыводзіцца да больш кароткага тыпу, ад яго бяруцца зноў жа малодшыя байты (а старэйшыя ігнаруюцца). У такім выпадку прыведзенае значэнне можа не раўняцца зыходнаму.
Прыклад.Вынік выканання Byte(534)будзе роўны 22;
534 кадзіруецца ў тып Word як 2 ×162 + 22 = 2 ×162 + 16 + 6. Значыць,
53410 = 21616.
Малодшы байт (16)16 = 16 + 6 = 22 мы атрымалі, а старэйшы – асноўны – згубіўся.
Заўвага 2.Калі зыходнае значэнне адмоўнае, а зададзены тып пашырае памер яго захавання, тады знак будзе захоўвацца.
Калі ж практычна трэба карыстацца аперацыяй прывядзення тыпаў? Тады, напрыклад, калі працуем на мяжы значэнняў для дадзенага тыпу.
VAR A, B : Word;
BEGIN
A := 55000;
B := A-256;
Write ( А + B );
Паколькі А + В > 65535, а А + В дае тып выразу Word, значыць, вынік дзеяння Word(A+B) заведама дрэнны. Выправім гэтую сітуацыю так:
Write(Longint(A)+B)
Радкі сімвалаў
Аб’яўленне радковых пераменных:
VAR ідэнтыфікатар : STRING [max_даўж];
або
VAR ідэнтыфікатар : STRING;
Абмежаванні: 0£ max_даўж £255. Калі пры вызначэнні апушчана даўжыня радка, тады па змаўчанні яна складае 255. Паколькі даўжыня можа быць рознай, значыць, STRING – гэта дынамічныя радкі.
Прывядзём розныя прыклады радкоў.
1. Першая форма запісу:
'Нумар п/п | ФІО | Пасада |'
дзе | – сімвал вертыкальнай рыскі мае код #179 у альтэрнатыўнай кодавай табліцы.
2. Другая форма запісу:
'Нумар п/п '#179' ФІО '#179' Пасада '#179
3. Радок #7#32#179#32#32#179 эквівалентны радку ^G' | |'
Тып STRING без даўжыні з’яўляецца базавым радковым тыпам, і ён сумяшчальны з усімі вытворнымі радковымі тыпамі.
Пры спробе запісаць у пераменную радок даўжэй, чым аб’яўлена ў азначэнні, лішняя справа частка адсякаецца. Калі ў пераменную пішацца радок, карацейшы за аб’яўлены, запамінаецца яго бягучая даўжыня.
Радкі розных даўжынь сумяшчальныя паміж сабой у аператары надання значэння і аперацыях параўнання.
Наданне значэння радкам
Прыклады надання значэння радковым пераменным.
VAR A : STRING[6];
{... значэнне A:}
A :='група 1'; {Þ А:='група ' і даўжыня радка 6;
гэта не памылковая сітуацыя}
VAR A : STRING[10];
...
A :='група 1'; {Þ А:='група 1' (і даўжыня 8)}
VAR A : STRING[2];
...
A :='група 1'; {Þ А:='гр' (і даўжыня 2)}
Любы сімвал у радку можна атрымаць па яго нумары, напрыклад A[5].
Кожны радок заўсёды «ведае», колькі сімвалаў у ім атрымліваецца ў дадзены момант, таму што сімвал S[0] утрымлівае код, які роўны ліку сімвалаў у значэнні радка S. Гэта значыць, што даўжыня радка S заўсёды роўна Ord(S[0]). Ёсць убудаваная функцыя length(S), якая вяртае бягучую даўжыню радка.
Вывад. Для вызначанай радковай пераменнай S даўжынёй N сімвалаў адводзіцца N + 1 байтаў памяці, з якіх нулявы байт утрымлівае даўжыню радка, а астатнія N байтаў адведзены для сімвалаў радка.
Прыклад.
VAR Myline : STRING[80];
BEGIN
Myline:='';
Writeln(Ord(Myline[0])); {Þ 0}
Myline:='abcd';
Writeln(Ord(Myline[0])); {Þ 4}
Myline[0]:=#2; {можна (Chr(2))}
Writeln(Myline); {Þ аб}
END.
Заўвага. Першапачаткова радок утрымлівае «смецце», і заўсёды трэба перад выкарыстаннем кожнага радка ініцыялізаваць радкі пустымі значэннямі ці чым-небудзь яшчэ.
Радковыя выразы
Разгледзім аперацыі, працэдуры і функцыі, якія выкарыстоўваюцца для работы з радкамі.
1. Аперацыя сашчэплівання радкоў: + .
Ёсць убудаваная функцыя Concat(str1, str2, …, strn), якая выконвае сашчэпліванне радкоў str1, ..., strn.
Напрыклад, сашчапіць 4 радкі можна адным з двух наступных спосабаў:
'А..'+'Я'+' - '+'літары' Þ 'А..Я - літары',
або
Concat('А..','Я',' - ','літары') Þ 'А..Я - літары'.
2. Аперацыі адносін: >, =, <>, <, <=, >=.
Параўнанне радкоў адбываецца пасімвальна, пачынаючы ад першага сімвала ў радку. Радкі лічацца роўнымі, калі: 1) маюць аднолькавую даўжыню; 2) пасімвальна эквівалентныя (параўноўваюцца коды). Калі пры пасімвальным параўнанні выявіцца, што адзін сімвал большы за другі (яго код большы), тады радок, які яго ўтрымлівае, таксама лічыцца большым.
Прыклады.
'abcd' = 'abcd' Þ true
'abcd' <> 'abcde' Þ true
'abcd' > 'abcD' Þ true ('d'>'D')
'abcd' > 'abc' Þ true.
Рэдагаванне радкоў
1. Функцыя Copy(S, Start, N) капіруе з радка S падрадок даўжынёй N сімвалаў, пачынаючы з пазіцыі Start (параметры Start, N – тыпу Integer).
Калі значэнне Start большае за даўжыню радка S, тады вынікам будзе пусты радок. Калі значэнне N большае, чым колькасць сімвалаў ад Start да канца радка S, тады вернецца рэшта радка S ад пазіцыі Start да канца радка.
Выкарыстанне функцыі Copy:
Прыклады.
SCopy := Copy('ABC***123', 4, 3); {SCopy='***'}
SCopy := Copy('ABC', 4, 3); {SCopy=''}
SCopy := Copy('ABC***123', 4, 11); {SCopy='***123'}
2. Функцыя Pos(Subs, S)зварочвае нумар сімвала ў радку S, пачынаючы з якога ў радок S уключаецца падрадок Subs (тып выніку Pos – Byte). Калі S не ўтрымлівае ў сабе Subs, тады функцыя верне 0.
Выкарыстанне функцыі Pos:
Няхай: S:='abcdef'.
Pos('de', S) Þ 4.
Pos('r', S) Þ 0.
3. Працэдура Delete(S, Start, N) выдаляе N сімвалаў радка S, пачынаючы з пазіцыі Start.
S := 'РАДОК';
Delete(S, 2, 3); Þ {S='РК'}
Калі Start = 0 ці перавышае даўжыню радка S, тады радок не зменіцца; калі N = 0, тады радок не зменіцца; калі N большае за рэшту радка, будзе выдалены падрадок ад Start і да канца радка S.
Выкарыстанне функцыі Delete:
Delete(S, 16, 255) – укарочваюцца радкі, даўжэйшыя за 16 сімвалаў.
4. Працэдура Insert(Subs, S, Start) устаўляе падрадок Subs у радок S, пачынаючы з пазіцыі Start.
Выкарыстанне функцыі Insert:
S:='Пачатак-канец';
Insert('сярэдзіна -', S, 9);
Атрымаем вынік: S = 'Пачатак-сярэдзіна-канец'.
Калі даўжыня радка S аказваецца пры ўстаўцы большай за аб’яўленую, тады радок аўтаматычна ўкарочваецца да аб’яўленай даўжыні S (абсякаецца правы канец).
5. Працэдура запаўнення FillChar(V, Len, C), дзе V – пераменная любога тыпу, Len (тып Word) – лік байтаў пераменнай V, якія будуць запоўнены значэннем C (C – тыпу Byte ці Char).
Выкарыстанне працэдуры FillChar:
VAR S: STRING;
...
FillChar(S[1], 80, ' ');
S[0]:=chr(80);
Заўвага. У такім выпадку абавязкова трэба сказаць, якой даўжыні стаў радок.
Пераўтварэнне радкоў
1. Працэдура Str(V, S) пераўтварае лікавае значэнне V у радок S. Пасля V можа запісвацца фармат у такім выглядзе:
V:m або V:m:n,
дзе n < m, m, n – даныя цэлага тыпу; m – шырыня поля для ліку; n – колькасць знакаў пасля дзесятковай кропкі.
Для цэлых лікаў задаюць толькі поле m. Калі ж для сапраўдных лікаў задаюць толькі m, тады лік запішацца ў экспаненцыяльнай форме.
Выкарыстанне працэдуры Str:
Str(6.66:8:2, S); Þ {S=' 6.66'}
Str(6.66:8:0, S); Þ {S=' 7'}
Заўвага. Калі m > 0, тады лік выраўноўваецца па правым краі, а калі m < 0, тады выраўноўванне адбываецца па левым краі, а лішкі як бы сціраюцца: Str(6.66:-8:2, S); Þ {S='6.66'}.
VAR F, n : Integer;
S : STRING;
...
F:=-5; n:=1;
Str(-123.426:F:n,S); {S='-123.5'}
Str(6.66:8:2, S); {S=' 6.66'}
2. Працэдура Val(S,V,ErrorCode) пераўтварае значэнне радка S у велічыню цэлалікавага ці сапраўднага тыпу і запісвае ў лікавую пераменную V. Пераменная ErrorCode – тыпу Integer. Калі пераўтварэнне магчыма, тады пераменная ErrorCode роўная 0, у адваротным выпадку яна мае нумар сімвала ў радку S, на якім працэдура спынілася.
Выкарыстанне працэдуры Val:
VAR V:Longint;
S:='14.2E+2'; Val(S,V,C); {V=1420; C=0}
S:='14.2A+2'; Val(S,V,C); {V=?; C=5}