You are on page 1of 169

KAUNO TECHNOLOGIJOS UNIVERSITETAS

Praktins informatikos katedra

J.Blonskis, V.Buknaitis
J.Konien, D.Rubliauskas

C++ PRAKTIKUMAS

Kaunas 2001

Turinys
1 skyrius. C++ elementai..........................................................................5
2 skyrius. Masyvai, failai, eiluts ...........................................................26
3 skyrius. Struktros...............................................................................55
4 skyrius. Klass apibrimas. Objektas ................................................62
5 skyrius. vedimo, ivedimo srautai......................................................67
6 skyrius. Klasi savybs. Objektikai orientuotas programavimas ......77
7 skyrius. Tiesiniai vienkrypiai sraai...............................................103
8 skyrius. Dvikrypiai tiesiniai sraai.................................................136
9 skyrius. Tiesini sra rinkiniai.......................................................147
10 skyrius. Netiesiniai sraai ..............................................................152
11 skyrius. Savarankikas darbas .........................................................158

vadas
C kalba ir jos modifikacija C++ pasiymi labai dideliu lakonikumu,
sintaksini struktr lankstumu ir universalumu, todl i kalb
daniausiai pradedama mokytis jau turint programavimo kitomis kalbomis
patyrim.
i knyga skirta skaitytojui, kuriam inomos pagrindins programavimo
kalbose vartojamos svokos, program struktrizavimo priemons, kuris
sugeba naudoti standartines duomen struktras, valdanias struktras,
programavimo aplinkas. Knygelje glaustai pateikiamos C++ pagrindins
preimons (sakini konstrukcijos, duomen tipai, funkcijos). Gausiai
pavyzdiais iliustruojamos pagrindins C++ priemons, kurios, autori
nuomone, btinos pradinei painiai su ia kalba. Pagrindinis dmesys
skirtas klasms ir j savybms.
Programavime plaiai vartojamas dinaminis atminties skirstymas. Tai
leidia kurti efektyvesnes programas. Dinamins duomen struktros
leidia kurti programuotojui norimos konfigracijos ir sudtingumo
duomen tipus. Tai labai lanksti ir efektyvi priemon, naudojama
duomenims saugoti bei apdoroti.
iame leidinyje pristatomos pagrindins klasikins dinamins duomen
struktros: tiesiniai vienkrypiai sraai ir j modifikacijos (stekas, dekas,
eil, iedas), dvikrypiai tiesiniai sraai, tiesini sra rinkiniai, medio
tipo sraas. Nagrinjamos pagrindins operacijos su sraais:
formavimas, perira, paieka, rikiavimas, alinimas, terpimas,
naikinimas.
Visi veiksmai iliustruojami realiomis programomis, paraytomis ir
patikrintomis su C++4.5. Knyga skirta studentams, studijuojantiems
duomen struktras, taiau stengtasi pristatyti dinamines duomen
struktras detaliai su kuo daugiau pavyzdi, kad bt suprantama ir
ingeidiam moksleiviui ar programavimo mgjui.
i knyga skirta praktinei painiai su C++, todl isamesnms kalbos
studijoms reikalinga specialiai tam skirta literatra. C++ kalbai skirt
knyg daug, taiau jos silomos usienio kalbomis. Lietuvikai parayt
knyg labai maai. Autoriai tikisi, kad i knyga palengvins pradedaniam
programuotojui pasirinkti jam tinkam literatr.

1 skyrius. C++ elementai


1.1. Programos struktra
Pradedant programuoti su C++ kalba, siloma atkreipti dmes tokias ios
kalbos ypatybes:
yra tik viena programos struktrizavimo priemon funkcija;
programos svok atitinka pagrindin funkcija, kuri ymima vardu
main;

identifikatoriuose didiosios ir maosios raids nesutapatinamos;


programos objekt (struktr, kintamj, funkcij) apraai gali bti bet
kurioje programos vietoje svarbu tik tai, kad objektas bt apibrtas
prie j naudojant;
aprauose plaiai vartojami funkcij prototipai;
C++ kalboje nedidelis standartizuot operatori skaiius, todl
naudojamos vairios bibliotek sistemos;
kreipiantis kintamuosius ir struktras, plaiai vartojamos rodykls;
daugel duomen tip galima interpretuoti keliais vairiais bdais.

Tipin programos C++ kalba (programos failo) struktra:


/* Instrukcijos pirminiam procesoriui
/* Globaliniai apraai
/* Funkcij prototipai
main()
{
/* Pagrindins funkcijos tekstas
}
/* Funkcij apraai

*/
*/
*/
*/
*/

Apraant programos struktr, panaudotos tokios C++ kalbos sintaksins


konstrukcijos:
komentarai paaikinimams skirtas simboli rinkinys, kurio ribos
ymimos simboli poromis /* ir */; paraius eilutje du simbolius be
5

tarpo // toliau esantis tekstas iki eiluts pabaigos suprantamas kaip


komentarai;

main() pagrindins programos funkcijos antrat;

sudtinis sakinys tarp skliaust {} raytas sakini rinkinys, su


kuriais programoje elgiamasi taip kaip su vienu sakiniu;

Programos struktros aprayme komentarais parodyta, kokia tvarka joje


turi bti surayti struktriniai elementai:
Programos pradioje suraomos instrukcijos pirminiam procesoriui
(preprocessor), kuriose nurodoma, kokius programos teksto
pertvarkymus reikia atlikti prie jos kompiliavim.
Globaliniais apraais apibriami tie programos objektai, kurie gali
bti vartojami visame rengiamos programos faile (tiek pagrindinje,
tiek vartotojo funkcijose).
Vartotojo funkcijos gali bti apraomos ne tik programos gale, bet ir
globalini apra dalyje.
Suraius pagalbines funkcijas programos gale, jos tekst lengviau skaityti
ir analizuoti; tada nesilaikoma reikalavimo, kad funkcijas reikia pirma
aprayti, o tik po to vartoti. io prietaravimo ivengiama globalini
apra dalyje pateikiant programos gale surayt funkcij prototipus.
Funkcij prototipais vadinami j antrai sakiniai.
Programai tikslinga suteikti vard, uraom teksto pirmoje eilutje kaip
komentar. ia naudinga parayti daugiau paaikinim apie program.
Visa tai leis lengviau ir greiiau atpainti reikaling program.

1.1 pratimas. Programa klausia vartotojo, ar giedras dangus. Kaip atsakym


vartotojas paspaudia klavi 1, jeigu giedras dangus, ir 0 prieingu
atveju. Programa atspausdina ekrane vest reikm ir j perduoda
funkcijai, kuri analizuoja atsakym ir iveda ekrane piln praneim.
#include <iostream.h>
#include <conio.h>

// vedimo/ivedimo srautai
// Tekstinio ekrano tvarkykl

void Atsakymas(int);
//
//
Pagrindin programa
void main() {
//
char simbolis;
//
int Dangus;
//
cout << "Ar saule sviecia?\n"; //

Funkcijos prototipas
Pagrindin funkcija
Kintamojo apraas
Kintamojo apraas
Ivedimas ekrane

cout << " Taip 1 Ne 0 \n";


cin >> Dangus;
// vedimas klaviatra
cout << "Atsakymas:" << Dangus << "\n";
cout << "Dabar ";
Atsakymas(Dangus);
// Kreipinys funkcij
cout << endl << "Paspauskite bet kok simbolini klavi
<< " ir ENTER" << endl;
// endl eiluts pabaiga
cin >> simbolis;

}
//
void Atsakymas(int Ats)
if (Ats == 1) cout <<
else cout << "danguje
}

Funkcija
{
"giedras dangus!!!\n";
labai daug debesu\n";

Programos pradioje suraytos instrukcijos pirminiam procesoriui, kurios


ymimos simboliu #. terpimo instrukcijomis include nurodoma, koki
fail tekstai turi bti terpti instrukcij paymtose vietose pirminio
apdorojimo metu. terpiam fail vardai raomi tarp simboli < > arba
tarp kabui (""), jeigu failas yra sukurtas vartotojo. Jeigu programoje
vartojamos asmenins pagalbins bibliotekos, instrukcijomis include
turi bti nurodomi iose bibliotekose esani priemoni prototip failai,
kuri vardai turi pltinius .h (header).

1.2. Kintamj tipai ir apraymas. Pradini reikmi


priskyrimas
Kintamj apra sintaks:
tipas kintamj sraas [= pradin reikm ]

Kaip ir kitose kalbose, duomen tipai nurodomi baziniais odiais. C++


kalboje yra vartojami ie baziniai elementars duomen tipai:
1.1 lentel. Pagrindiniai tipai

Tipas
char
int
long
short
unsigned
float
double

Galimos reikms
128..127
32768..32768
2147483648..2147483647
32768..32768
0..65535
3.41038..3.41038
1.710308..1.710308

Tokio aprao pavyzdys programoje Pratimas1 yra pagrindinje


funkcijoje:
int Dangus;

Programoje visi kintamieji kiekvienu momentu privalo bti apibrti, t.y.


turti konkrei reikm. Kalbos kompiliatorius kintamiesiems skiria
atmint, taiau nepasirpina, kas ten yra. Programuotojas privalo tai
numatyti. Rekomenduojama programos kintamj apra dalyje nurodyti
pradines j reikmes. Programos pavyzdyje galima buvo parayti:
int Dangus = 0;
arba atskiru priskyrimo sakiniu:
Dangus = 0;
Aprauose vienodo tipo kintamuosius galima grupuoti, pavyzdiui:
int Dangus = 0,

Medis = 0,

Katinas = 0;

Tai galima aprayti ir taip:


int Dangus, Medis, Katinas;
Dangus = Medis = Katinas = 0;

Nors abu bdai duoda t pat rezultat, taiau pirmasis tinkamesnis. Jis
vaizdesnis ir suprantamesnis, nes vienoje vietoje viskas pasakyta apie
kintamj. J naudojant bus maiau klystama, nes nereiks dukart kartoti
kintamojo vardo. Jis leidia lengviau suprasti ir modifikuoti program, nes
kintamj reikms pasakomos j aprao vietoje ir kiekviena
inicializuojama atskirai, taigi, ir pakeitimus darant, pradines reikmes
galima skirti skirtingas.
Sveikojo tipo kintamj aprayme galima taikyti nuorod unsigned.
Taip sukuriami kintamieji, galintys turti tik teigiamas sveiko tipo
reikmes, pavyzdiui:
unsigned int X;

// reikmi intervalas: 0..65535

Programose labai naudingos konstantos. Jos apraomos panaudojant


kalbos rezervuot od const, pavyzdiui:
const

int

A = 125;

const

float

B = 13.5;

1.2 pratimas. Programa parodo, kad C++ kalboje leidiama maiyti skirting
tip kintamuosius. Maiant tipus char ir int, naudojamas simbolio
ASCII lentels skaitmenis atitikmuo, o maiant tipus int ir float,
paprasiausiai pridedama arba atmetama trupmenin skaiiaus dalis.
void main() {
int a, b, c;
char x, y;
float num, toy;
a = b = c = 27;
x = y = 'A';
num = toy = 3.6792;
a =
x =
num
c =

y;
b;
= b;
toy;

//
//
//
//

a bus lygus 65 (simbolis A)


x bus lygus 27 (simbolis )
num bus lygus 27.00
c bus lygus 3

Kintamasis galioja nuo jo paskelbimo vietos. Kintamuosius galima


aprayti bet kurioje vietoje. Tikslinga prisiminti, kad:

programos teksto pradioje prie main funkcij surayti kintamieji yra


globals ir galioja visame tolesniame tekste;
kintamieji, kuri apraas yra funkcijoje, vadinami lokaliais ir galioja
tik joje;
esant vienodam globalaus ir lokalaus kintamojo pavadinimams,
pirmenyb suteikiama lokaliam, t.y. toje funkcijoje globalus negalioja;
kintamieji gali bti apraomi j panaudojimo vietoje, taiau tai
nerekomenduojama.

1.3 pratimas. i programa iliustruoja, kaip galima aprayti kintamuosius, ir


kuriose programos vietose jie galios.
#include <stdio.h>
void head1(void);
void head2(void);
void head3(void);
int count;

// Globalus kintamasis

//
main() {
int index;

Pagrindin programa
// index galioja tik funkcijoje main

head1();
head2();
head3();
for (index = 8; index > 0; index) {
int stuff;
// stuff galioja tik i skliausteli ribose
for (stuff = 0; stuff < 7; stuff++)
printf("%d ", stuff);
printf (" indeksas = %d\n", index); }
}
int counter;
// counter galioja tik nuo ios vietos
//
Pirmoji antrat
void head1(void) {
int index;
// index galioja tik funkcijoje head1
index = 23;
printf("Pirmoji antraste: %d\n", index);
}
//
Antroji antrat
void head2(void) {
int count;
// count galioja tik funkcijoje head2
// ir panaikina globalaus kintamojo galiojim
count = 53;
printf("Antroji antraste: %d\n", count);
counter = 77;
}
//
Treioji antrat
void head3(void) {
printf("Trecioji antraste: %d\n", counter);
}

vykdius program ekrane matysime tokius rezultatus:


Pirmoji antraste: 23
Antroji antraste: 53
Trecioji antraste: 77
0 1 2 3 4 5 6 indeksas
0 1 2 3 4 5 6 indeksas
0 1 2 3 4 5 6 indeksas
0 1 2 3 4 5 6 indeksas

10

=
=
=
=

8
7
6
5

0
0
0
0

1
1
1
1

2
2
2
2

3
3
3
3

4
4
4
4

5
5
5
5

6
6
6
6

indeksas
indeksas
indeksas
indeksas

=
=
=
=

4
3
2
1

Priskyrimo sakinyje panaudojome operatori = (lygybs enklas). Kiti


daniausiai vartojami operatoriai parodyti 1.2 lentelje. Operacijoms
ymti naudojami enklai surayti 1.3 lentelje.
1.2 lentel. Daniausiai naudojami operatoriai

Operatorius
++

k++
++k

k
k
s += k;
s = k;

+=
=

Pavyzdiai ir paaikinimai
k reikm panaudojama, po to didinama vienetu.
k reikm didinama vienetu, po to panaudojama.
k reikm panaudojama, po to mainama vienetu.
k reikm mainama vienetu, po to panaudojama.
s = s + k;
s = s k;
1.3 lentel. Operacij enklai

Aritmetins operacijos
+

sudtis
atimtis
dalybos modulis

*
/

daugyba
dalyba

==
!=
>

Sulyginimo operacijos
ar lygios dvi reikms?
ar pirma maesn u antr?
<
ar nelygios dvi reikms?
>= ar pirma nemaesn antr?
ar pirma didesn u antr?
<= ar pirma nedidesn u antr?
Logins operacijos

&&
!

login daugyba ir (and)


loginis neigimas ne (not)

login sudtis arba (or)

Raant aritmetines iraikas naudojami paprasti skliaustai. Standartins


matematins funkcijos yra suraytos bibliotekoje math.h.
1.4 pratimas. Programoje naudojamos vairios palyginimo operacijos.
void main() {
int x, y, z;
char a, b, c;
float r, s, t;

11

x = y = z = 11;
a = b = c = 40;
r = s = t = 12.987;
if
if
if
if
if

(x == y) z = -13;
(x > y) a = 'A';
(!(x > y)) a = 'B';
(b <= c) r = 0.0;
(r != s) t = c/2;

if (x = (r != s)) z =
printf("6. x = %d z =
if (x = y) z = 222;
printf("7. x = %d z =
if (x != 0) z = 333;
printf("8. z = %d\n",
if (x) z = 444;
printf("9. z = %d\n",

printf("1.
printf("2.
printf("3.
printf("4.
printf("5.

z
a
a
r
t

=
=
=
=
=

%d\n",
%d\n",
%d\n",
%f\n",
%f\n",

z);
a);
a);
r);
t);

1000;
%d\n", x, z);
%d\n", x, z);
z);
z);

x = y = z = 77;
if ((x == y) && (x == 77)) z = 33;
printf("10. z = %d\n", z);
if ((x > y) || (z > 12)) z = 22;
printf("11. z = %d\n", z);
if (x && y && z) z = 11;
printf("12. z = %d\n", z);
if ((x = 1) && (y = 2) && (z = 3)) r = 12.00;
printf("13. x = %d y = %d z = %d r = %f\n", x, y, z, r);
if ((x == 2) && (y = 3) && (z = 4)) r = 14.56;
printf("14. x = %d y = %d z = %d r = %f\n", x, y, z, r);
if (x == x)
printf("15.
if (x != x)
printf("16.

z
z
z
z

=
=
=
=

1.234;
%d\n", z);
5.678;
%d\n", z);

Programos rezultatai:
1.
2.
3.
4.
5.
6.

12

z
a
a
r
t
x

=
=
=
=
=
=

-13
40
66
0.000000
20.000000
1 z = 1000

// visada vykdoma slyga


// niekada nevykdoma slyga

7. x = 11 z = 222
8. z = 333
9. z = 444
10. z = 33
11. z = 22
12. z = 11
13. x = 1 y = 2 z = 3 r = 12.000000
14. x = 1 y = 2 z = 3 r = 12.000000
15. z = 1
16. z = 1

1.3. Funkcijos
Programos Pratimas1 pabaigoje parayta funkcija Atsakymas, kurios
prototipas uraytas prie pagrindin funkcij main. Funkcijos prototipo
uraas baigiamas simboliu ; (kabliatakis). Funkcijos aprao sintaks:
[reikms tipas] vardas
([formali parametr sraas])
{
funkcijos tekstas
}

Jeigu funkcijos vardui yra suteikiama reikm, jos tekste privalo bti
sakinys
return reikm;

Jeigu tokio sakinio nra, funkcijai reikm nesuteikiama. Funkcijos


reikms tipas yra nurodomas odiu void (tuias), jeigu funkcija
negrina reikms. Reikmi neturinios C++ kalbos funkcijos atitinka
kitose kalbose (pavyzdiui Paskalio) procedras. Kreipiniai tokias
funkcijas programose sudaro atskirus sakinius.
Jeigu funkcija neturi argument, argument sraas gali bti paliekamas
tuias arba ymimas odiu void. Pavyzdiui,
void Atsakymas(void);
Funkcijos prototipe nra tikslo vardinti parametrus: kompiliatoriui
pakanka inoti, kiek yra parametr ir kokie j tipai, todl aprae vardai
gali bti praleidiami.
Pagrindin funkcija main(), kuri programoje gali bti tik viena, nurodo
kompiliatoriui, kur prasideda programoje vykdom veiksm apraymai.
13

Pagrindins funkcijos ir pagalbini funkcij tekstai yra sudaromi pagal tas


paias taisykles. Tekst sudaro funkcijoje vartojam objekt apraai,
programos vykdom skaiiavim ir valdymo sakiniai, komentarai.
Funkcija skaiiavim rezultatus gali perduoti jos vartotojui dviem bdais:
per parametr sra;
per funkcijos vard.
Norint gauti funkcijos skaiiavim rezultatus per parametr sra, reikia
perduoti kreipinio metu adres vietos, kur turi bti patalpinti grinami
duomenys. Adresus gali saugoti rodykls tipo parametrai (r. 26 psl.).
Funkcijos prototipe nurodomi rodykls tipo parametrai, pavyzdiui:
void Keisti(int *, int);
ia pirmasis parametras rodo, kad kreipinio metu reikia perduoti funkcijai
int tipo kintamojo adres, kai tuo tarpu antrasis parametras reikalauja
reikms, kuri gali bti nurodoma kreipinio metu kaip konstanta,
kintamasis ar rodykl reikm. Pavyzdiui:
Keisti(&a, 5);

Keisti(&a, x);

Keisti(&a,*p);

1.5 pratimas. Funkcija Keisti demonstruoja abi parametr


Pagrindin funkcija parodo ekrane gaunamus rezultatus.
#include <iostream.h>
#include <conio.h>
void Keisti(int *, int);
//
Pagrindin programa
void main() {
int a = 20, b = 10, *c = &a;
cout << "
a b
cout << "Pradines reiksmes : "
<< a << " " << b << " " << *c
Keisti(&a, b);
cout << "Po pirmo keitimo
: "
<< a << " " << b << " " << *c
Keisti(&b, 20);
cout << "Po antro keitimo
: "
<< a << " " << b << " " << *c
Keisti(c, b);
cout << "Po trecio keitimo : "
<< a << " " << b << " " << *c
Keisti(&b, *c);

14

*c \n";
<< "\n";
<< "\n";
<< "\n";
<< "\n";

formas.

cout << "Po ketvirto keitimo: "


<< a << " " << b << " " << *c << "\n";

}
//
Funkcija Keisti
void Keisti(int *p1, int p2)
{ *p1 = *p1 + 10;
p2 = p2 + 10;

vykdius program ekrane matomi rezultatai:


Pradines reiksmes :
Po pirmo keitimo
:
Po antro keitimo
:
Po trecio keitimo :
Po ketvirto keitimo:

a
20
30
30
40
40

b
10
10
20
20
30

*c
20
30
30
40
40

1.4. Duomen vedimas/ivedimas


Apraant programos ir vartotojo dialog, duomen vedimui bei ivedimui
panaudojama iorini sraut bibliotekos iostream.h nukreipimo
operatoriai << ir >>. Praneim ivedimui ekran yra vartojama
struktra:
cout << simboli eilut

Vardas cout ymi standartin ivedimo sraut (ekran). C++ kalbos


simboli eiluts yra tarp dvigub kabui (") rayti kompiuterio alfabeto
ir valdani simboli rinkiniai. Valdantys simboliai gali bti terpiami bet
kurioje eiluts vietoje (1.4 lentel).
J sintaks: \simbolis
1.4 lentel. Valdantys simboliai

Pavadinimas
Skambutis
Eiluts pabaiga
kit eilut
kitos eiluts pradi
Horizontali tabuliacija
Vertikali tabuliacija
Nulinis simbolis

C kalboje
\a
\r
\f
\n
\t
\v
\0

ASCII kodas
7
13
12
10
9
11
0

Daniausiai vartojamas valdantis simbolis \n, kuris perkelia ekrano


ymekl naujos eiluts pradi. ymeklio perklimui naujos eiluts
15

pradi rekomenduojama naudoti operatori endl. Jeigu norime, kad


simboli eilutje bt terptas simbolis " arba \, vartojami atitinkamai \"
arba \\.
Rezultat formatavimui bibliotekoje iomanip.h saugomi manipuliatoriai, kurie gali bti terpiami ivedimo srautus:
n lauko plotis simboliais,
n skaitmen skaiius.

setw (n)
setprecision (n)

Jei setw nurodyto lauko dydio skaiiui nepakanka, manipuliatorius


ignoruojamas. Nuoroda setw galioja artimiausiai ivedamai reikmei, o
setprecission iki naujo nurodymo.
1.6 pratimas. Programa demonstruoja, kaip veikia manipuliatoriai setw ir
setprecission.
#include <iostream.h>
#include <iomanip.h>
main() {
float A = 18.236;
cout << "1. A=" << setw(9) << A << endl;
cout << "2. A=" << setprecision(3) << A << endl;
cout << "3. A="
<< setw(10) << setprecision(5) << A <<endl;
A = 123.45678;
cout << "4. A=" << A << endl;
}

Programos darbo rezultatas bus toks:


1.
2.
3.
4.

A=
18.236
A=18.2
A=
18.236
A=123.46

Skaitymas i standartinio vedimo srauto (klaviatros):


cin >> Kintamasis

Klaviatroje renkami duomenys sudaro ASCII kodo simboli sraut, kurio


interpretavimo bd nurodo kintamojo, kuriam nukreipiami duomenys,
tipas.

16

Keli kintamj reikmes galima vesti taip:


cin >> a >> b >> c;

Be i sraut klasi, C++ kalboje yra vartojamos ir klasikins


vedimo/ivedimo bibliotekos. Tokios bibliotekos yra trys: stdio.h
(klasikinis buferizuotas I/O input/output), io.h (emo lygio
nebuferizuotas UNIX standarto I/O), conio.h (specialios I/O funkcijos).
Pratimuose analizuojamos tik bibliotekos stdio.h funkcijos.
Apraant I/O operacijas, vartojama srauto svoka. Srautas tai
abstrakcija, leidianti atsiriboti nuo konkretaus I/O renginio (disko,
juostos, terminalo). Srautai bna dviej tip:

Tekstinis srautas eilutes, atskiriamas specialiais simboliais (CR


carriage return, LF line feed), suskaidyta simboli seka. Tekstinio
srauto informacija nebtinai yra identika duomenims matomiems
konkreiame atvaizdavimo renginyje (spausdintuve, displjuje), nes
dalis simboli (CR, LF) yra skirta ne vaizdavimui, o srauto perdavimo
valdymui;

Dvejetainis srautas bit seka, tiksliai atitinkanti informacij


konkreiame renginyje.

Kiekviena programa automatikai atidaro 5 standartinius tekstinius


srautus:
stdin (vedimas),
stdout (ivedimas),
stderr (praneimai apie klaidas),
stdaux (papildomas),
stdprn (spausdintuvas).
Jie susiejami su standartiniais sisteminiais I/O renginiais. Daniausiai
srautai stdin, stdout, stderr yra susiejami su konsole (klaviatra ir
ekranas). Standartin I/O rengin galima pakeisti (perskirti) DOS
priemonmis.
Standartini sraut (klaviatros ir ekrano) valdymui vartojamos funkcijos
printf ir scanf. J prototipai:
int printf (const char *ablonas, [<Kintamj sraas>]);
int scanf(const char *ablonas, <Atminties lauk sraas>);

17

ablonas tai simboli eilut su terptais raom arba skaitom


duomen formatais, kurie aprao duomenims skiriamo lauko struktr
arba j interpretavimo bd. Funkcijoje scanf skaitomiems duomenims
skiriami atminties laukai yra nurodomi adresais. Tipin formato struktra
yra tokia:
%[<Poymis>][<Lauko dydis>]
[.<Tikslumas>]<Duomen tipas>
Poymiai daniausiai naudojami tokie:
sulygiuoti pagal kairj krat;
+ ivedant skaii, nurodyti jo enkl (+ ar );
Duomen tipai ymimi raidmis. Pagrindiniai tipai yra tokie:
d arba i sveikasis,
o atuntainis sveikasis,
u sveikasis, be enklo,
x eioliktainis sveikasis,
c simbolinis tipas,
f slankaus kablelio,
s simboli eilut,
e rodiklin forma,
p rodykl.
1.7 pratimas. Programa iliustruoja komandos printf veikim.
void main() {
int a;
long int b;
short int c;
unsigned int d;
char e;
float f;
double g;
a
b
c
d
e
f
g

=
=
=
=
=
=
=

1023;
2222;
123;
1234;
'X';
3.14159;
3.1415926535898;

printf("1.
printf("2.
printf("3.
printf("4.

18

a
a
a
b

=
=
=
=

%d\n", a);
%o\n", a);
%x\n", a);
%ld\n", b);

//
//
//
//

deimtainis skaiius
atuntainis skaiius
eioliktainis skaiius
deimtainis ilgas skaiius

printf("5. c = %d\n", c);


printf("6. d = %u\n", d);
printf("7. e = %c\n", e);
printf("8. f = %f\n", f);
printf("9. g = %f\n", g);
printf("\n");
printf("10. a = %d\n", a);
printf("11. a = %7d\n", a);
printf("12. a = %7d\n", a);
c = 5;
d = 8;
printf("13. a = %*d\n", c, a);
printf("14. a = %*d\n", d, a);
printf("\n");
printf("15. f = %f\n", f);
printf("16. f = %12f\n", f);
printf("17. f = %12.3f\n", f);
printf("18. f = %12.5f\n", f);
printf("19. f = %12.5f\n", f);

//
//
//
//
//

deimtainis trumpas
be enklo
simbolis
realus skaiius
dvigubo tikslumo realus sk.

// paprastas sveikas skaiius


// lauko plotis 7 simboliai
// lygiuojama pagal kair krat
// lauko plotis 5 simboliai
// lauko plotis 8 simboliai
//
//
//
//
//

paprastas realus skaiius


lauko plotis 12 simboli
realiai daliai 3 simboliai
realiai daliai 5 simboliai
lygiuojama pagal kair krat

vykdius program ekrane matysime:


1.
2.
3.
4.
5.
6.
7.
8.
9.

a
a
a
b
c
d
e
f
g

=
=
=
=
=
=
=
=
=

1023
1777
3ff
2222
123
1234
X
3.141590
3.141593

10.
11.
12.
13.
14.

a
a
a
a
a

= 1023
=
1023
= 1023
= 1023
=
1023

15.
16.
17.
18.
19.

f
f
f
f
f

= 3.141590
=
3.141590
=
3.142
=
3.14159
= 3.14159

19

1.5. Ciklai ir slygins iraikos


Ciklo while sintaks yra tokia:
while (kartojimo slyga) kartojamas sakinys;

Kartojamas sakinys yra vykdomas tol, kol kartojimo slyga yra tenkinama
(true). Jei ciklo viduje kintamasis, nuo kurio priklauso kartojimo slygos
nutraukimas, nra keiiamas, ciklas taps aminu. Ciklas nei karto nebus
vykdomas, jeigu kartojimo slyga jau pradioje bus netenkinama
(false). Jeigu cikl sudaro keletas sakini, tuomet jie skliaudiami
skliaustais {}. Taip gaunamas sudtinis sakinys.
1.8 pratimas. Programa iliustruoja ciklo while veikim.
void main() {
int count = 0;
while(count < 6) {
printf("count = %d\n", count);
count++; }
}

vykdius program ekrane matysime:


count
count
count
count
count
count

=
=
=
=
=
=

0
1
2
3
4
5

Panaus yra ciklas dowhile. Jo aprao sintaks:


do kartojamas sakinys while (kartojimo slyga);

Nuo ciklo while is ciklas skiriasi tuo, kad jis visuomet bus vykdomas
bent vien kart, nes kartojimo slyga tikrinama jau vykdius kartojam
sakin.
1.9 pratimas. Programa iliustruoja ciklo dowhile veikim.
void main() {
int i = 0;
do {
printf("i = %d\n", i);
i++;
} while(i < 5);

20

vykdius program ekrane matysime:


i
i
i
i
i

=
=
=
=
=

0
1
2
3
4

Ciklo for sintaksin struktra:


for (i1; i2; i3)

kartojamas sakinys;

Sakinyje nurodyta iraika i1 skaiiuojama tik vien kart, prie


pradedant cikl, kuomet tikrinama, ar tenkinama i2 iraika. Jei taip
vykdomas kartojimo sakinys. Iraikos i3 reikm perskaiiuojama po
kartojimo sakinio vykdymo, ir grtama prie iraikos i2 tikrinimo.
Taigi, galime apibendrinti, kad i1 apibria ciklo parametro pradin
reikm, i2 nurodo sustojimo slyg, o i3 kitimo dsn.
1.10 pratimas. Programa iliustruoja ciklo for veikim.
void main() {
int i;
for(i=0; i<6; i++)
printf("i = %d\n", i);
}

vykdius program ekrane matysime:


i
i
i
i
i
i

=
=
=
=
=
=

0
1
2
3
4
5

Valdymo struktros. Pradsime nuo vienos i populiariausi struktros


ifelse. Jos sintaks yra tokia:
if (slyga) <aka TAIP>;
else <aka NE>;

C++ kalboje nra loginio duomen tipo, todl santykiams suteikiama


skaitmenin reikm, kuri yra 1, kai santykio operacija tenkinama, ir 0,
21

kai santykio operacija netenkinama. C++ kalboje slygas galima aprayti ne


tik santykiais, bet ir bet kokiomis kitomis skaitmeninmis iraikomis. Jei
tokios iraikos reikm yra 0, laikoma, kad slyga netenkinama, o jei
reikm kitokia, laikoma, kad slyga tenkinama. Dar viena domi C++
kalbos savyb kalboje nra loginio tipo, bet logines iraikas vartoti
galima. Logini iraik skaitmeniniai argumentai, kuri reikms
nenulins (0), interpretuojami kaip logins reikms TRUE, o nulins
(=0) laikomos reikmmis FALSE. Logini iraik reikms taip pat
bna skaitmenins 0 (FALSE) ir 1 (TRUE).
Programuojantiems Paskalio kalba, siloma atkreipti dmes tai, kad:

C++ kalbos sakinyje if prie ak else yra raomas ; (kabliatakis).

vertinant tai, kad logins reikms C++ kalboje nra, teisingas bus
uraas:

if (Ats) cout << "giedras dangus!!!\n";


else
cout << "danguje labai daug debesu\n";

ia else aka bus vykdoma tik esant atsakymo nulinei reikmei, kitais
atvejais bus vykdoma aka TRUE. Jeigu programos vartotojas netiksliai
atsakys programos klausim, tuomet is sakinys ir programos pavyzdyje
esantis sakinys dirbs skirtingai. Aukiau pateiktoje programoje
1.1 pratimas else aka bus vykdoma visais atvejais, iskyrus atsakym
lyg 1.
1.11 pratimas. Programa iliustruoja valdymo struktros ifelse veikim.
void main() {
int data;
for (data=0; data<10; data++) {
if (data == 2) printf("data = %d\n", data);
if (data < 5)
printf("data = %d, t.y. maziau uz 5\n", data);
else
printf("data = %d, t.y. daugiau uz 4\n", data);
} }

vykdius program ekrane matysime:


data = 0, t.y. maziau uz 5
data = 1, t.y. maziau uz 5
data = 2

22

data
data
data
data
data
data
data
data

=
=
=
=
=
=
=
=

2,
3,
4,
5,
6,
7,
8,
9,

t.y.
t.y.
t.y.
t.y.
t.y.
t.y.
t.y.
t.y.

maziau uz 5
maziau uz 5
maziau uz 5
daugiau uz 4
daugiau uz 4
daugiau uz 4
daugiau uz 4
daugiau uz 4

Dar du nauji valdymo sakiniai, tai break ir continue. ie sakiniai


neturi joki parametr ir daniausiai yra naudojami cikluose; break
nutraukia ciklo vykdym ir veiksmai tsiami nuo pirmo sakinio, esanio
u ciklo, o continue nutraukia tik vienos iteracijos vykdym ir
sugrina kartojimo slygos tikrinim.
1.12 pratimas. Programa iliustruoja sakini break ir continue veikim.
void main() {
int xx;
for (xx=5; xx<15; xx++) {
if (xx == 8)
break;
printf("Break ciklas; xx = %d\n", xx);
}
for (xx=5; xx<15; xx++) {
if (xx == 8)
continue;
printf("Continue ciklas; xx = %d\n", xx);
} }

vykdius program ekrane matysime:


Break ciklas; xx
Break ciklas; xx
Break ciklas; xx
Continue ciklas;
Continue ciklas;
Continue ciklas;
Continue ciklas;
Continue ciklas;
Continue ciklas;
Continue ciklas;
Continue ciklas;

= 5
= 6
= 7
xx =
xx =
xx =
xx =
xx =
xx =
xx =
xx =

5
6
7
9
10
11
12
13

23

Continue ciklas; xx = 14

switch-case struktra yra tokia:


switch (iraika) {
case ym1: sakinys1;
case ym2: sakinys2;
default
: sakinys3;

Jei iraika yra lygi ym1, bus vykdomi sakinys1, sakinys2 ir


sakinys3; jei lygi ym2 sakinys2 ir sakinys3, o visais likusiais
atvejais tik sakinys3. Taiau daniau i struktra yra naudojama kartu
su operatoriumi break:
switch (iraika) {
case ym1: sakinys1; break;
case ym2: sakinys2; break;
default
: sakinys3; break;

iuo atveju, jei iraika lygi ym1, vykdomas tik sakinys1; jei lygi
ym2 tik sakinys2, o likusiais atvejais sakinys3.
1.13 pratimas. Programa iliustruoja struktros switch-case veikim.
void main() {
int i;
for(i=3; i<13; i++) {
switch (i) {
case 3 : printf("Trys\n");
break;
case 4 : printf("Keturi\n");
break;
case 5 :
case 6 :
case 7 :
case 8 : printf("Penki - astuoni\n");
break;
case 11 : printf("Vienuolika\n");
break;
default : printf("Neaprasyta reiksme\n");
break;
} } }

24

vykdius program ekrane matysime:


Trys
Keturi
Penki - astuoni
Penki - astuoni
Penki - astuoni
Penki - astuoni
Neaprasyta reiksme
Neaprasyta reiksme
Vienuolika
Neaprasyta reiksme

25

2 skyrius. Masyvai, failai, eiluts


2.1. Rodykl, adresas
Kiekvienam programoje apraytam kintamajam kompiliatorius skiria
atminties lauk, kur apibdina visa grup parametr: adresas, lauko
dydis, saugom duomen tipas ir reikm. Programos tekste panaudotas
kintamojo vardas nurodo, kad turi bti manipuliuojama su jo reikme.
Apsiriboti manipuliavimu vien tik kintamj reikmmis galima tik
paprastus
skaiiavimo
algoritmus
apraaniose
programose.
Sudtingesnse taikomosiose ir sisteminse programose, kuriose yra
aktuals racionalaus dinaminio atminties paskirstymo, dinamini struktr
sudarymo ir kompiuterio rangos valdymo fiziniame lygyje klausimai,
tenka manipuliuoti ne tik atmintyje saugomomis kintamj reikmmis,
bet ir j adresais. Adres reikmi saugojimui yra skirtos rodykls, kuri
apra sintaks:
lauko tipas *rodykls vardas

Programos tekste struktra *rodykls vardas reikia, kad turi bti


vartojama rodykls rodomo lauko reikm. Paioms rodyklms gali bti
suteikiamos tik to paties tipo objekt, kuriems buvo apibrtos rodykls,
adres reikms.
Pavyzdys:
int x, *px;
px = &x;

Priskyrimo operatorius px = &x rodyklei px suteikia kintamojo x adreso


reikm, todl x reikm dabar galima kreiptis tiek vardu x, tiek
struktra *px. Rodykls tipo kintamiesiems btina nurodyti pradin
reikm, kuri daniausiai bna tuias adresas: px = NULL.
2.1 pratimas. Programa iliustruoja, kaip naudojamos rodykls. Kintamieji
pt1 ir pt2 yra rodykls (tai rodo vaigduts prie juos). Ura
&index galime skaityti kaip kintamojo index adresas. O realiai
ioje programoje yra tik vienas kintamasis, kurio reikm keiiame.
26

main() {
int index, *pt1, *pt2;
index = 39;
pt1 = &index;
pt2 = pt1;
printf("index *pt1 *pt2");
printf("%4d %4d %4d\n", index, *pt1, *pt2);
*pt1 = 13;
printf("%4d %4d %4d\n", index, *pt1, *pt2);
}

vykdius program ekrane matysime:


index *pt1 *pt2
39
39
39
13
13
13

2.2. Vienmatis masyvas


Labai glaudiai su rodyklmis yra susijs masyvo tipas, kuris yra skirtas
vienodo tipo duomen (element) rinkiniams saugoti. Masyv apra
sintaks:
element tipas masyvo vardas [element skaiius]

iame aprayme skliaustai [ ] yra btini struktros elementai. Masyvo


narius ymi kintamieji su indeksais, kuri vard sintaks:
masyvo vardas[indeksas]

Pavyzdiui, masyvo apraas: int A[10]; masyvo elementas: A[5].


Indeksais gali bti tik intervalo [0, n-1] sveikosios reikms (n
masyvo element skaiius).
Pastaba: Masyvo vardas be indekso reikia jo nulinio elemento adres.
2.2 pratimas. Programa demonstruoja situacij, kai gretimuose atminties
laukuose surayti vienodo tipo duomenys (a, b, c, d) panaudoti
masyvo formavimui. Pradi nurodo pirmojo kintamojo adresas: pi =
&a;
#include <iostream.h>
int

a=1,

b=2,

c=3,

d=4,

*pi;

27

main() {
int i = 0, mas[4];
pi = &a;
// Kintamojo a adresas
while(i<4) mas[i++] = *(pi++);
// Masyvo formavimas
// Masyvo ivedimas ekran atvirkia tvarka
while(i) cout << mas[--i] << "\t";
cout << endl;
}

Kai reikmi didinimo ar mainimo operacijos yra taikomos rodyklms, j


reikms yra keiiamos ne vienetu, o su rodykle susieto lauko dydiu. i
rodykli savyb pavyzdio programoje yra panaudota kintamj grups
a, b, c, d reikmi perrinkimui.

9Papildykite program taip, kad ji parodyt ekrane vis joje vartojam


kintamj ir masyvo mas element adresus. Apraant adres ivedim,
naudokite rodykli ablon %p. Adresai bus ivedami eioliktainje
skaiiavimo sistemoje.
2.3 pratimas. Reikia surasti masyvo element sum. Duomenys vedami
klaviatra. Reikmms sumuoti padaroma funkcija, kuri rezultat
grina funkcijos vardu. Funkcijai perduodamas masyvo pirmojo
elemento adresas: A (galima rayti &A[0]).
#include <iostream.h>
int Suma(int *, int);
//
Pagrindin programa
void main() {
int A[10], i, n;
// A[0], A[1], ... , A[9]
cout << "Iveskite n reiksme: ";
cin >> n;
for (i=0; i<n; i++) {
cout << "A[ " << i << " ]= ";
cin >> A[i];
}
cout << " Suma = " << Suma(A, n) << endl;
}
//
Funkcija Suma
int Suma(int *pr, int k) {
int S = 0, i = 0;
while(i<k) { S += *(pr+i); i++; }
return S; }

28

2.3. Dinaminis atminties iskyrimas


Dirbant su masyvais btina sitikinti, kad norimas duomen skaiius tilps
kompiuterio atmintyje. Galimi keli bdai iskirti atminiai. Vienas
paprasiausi yra funkcija:
void *malloc(Kiekis);

ia nurodomas praomos atminties Kiekis baitais. Jeigu atmintis buvo


skirta, tai grinama rodykl pirmj tos atminties bait, kitaip funkcijos
reikm yra NULL.
Kreipinio metu atminties kiek patogu nurodyti kaip duomen element
skaiiaus ir vieno elemento uimamos vietos baitais sandaug, pavyzdiui:
n * sizeof(float)
kur n reali skaii kiekis, o funkcija sizeof grina nurodyto
duomen tipo (ia realaus) apimt baitais.
Funkcija malloc grina rodykl nurodyto tipo atmint: kreipinio metu
nurodomas rodykls tipas.
2.4 pratimas. Klaviatra vedamas duomen skaiius. Jeigu duomenims
saugoti yra vietos atmintyje, tai duomenys vedami klaviatra
masyv, kurio rodykl yra saugoma kintamuojame A. Toliau
duomenys surikiuojami majimo tvarka.
#include <iostream.h>
#include <alloc.h>
//
Atminties skyrimas ir duomen vedimas
int *Duomenys(int);
void Tvarka (int *, int);
// Rikiavimas
void Sp
(int *, int);
// Ivedimas ekrane
//
Pagrindin programa
void main() {
int n, *A;
cout << "Iveskite n reiksme: ";
cin >> n;
A = Duomenys(n);
if (A != NULL) {
cout << " n= " << n << endl;
cout << " Ivestas masyvas:\n";
Sp(A, n);
Tvarka(A, n);
cout << " Sutvarkytas masyvas:\n";

29

Sp(A, n);
free(A); }
// Masyvo uimama atmintis atlaisvinama
cout << endl;
}
//
Duomen vedimas
int *Duomenys(int n) {
int *x, i;
x = (int *) malloc(n * sizeof(int));
if (x == NULL)
cout << "Truksta atminties" << endl;
else {
for(i=0; i<n; i++) {
cout << "Iveskite " << (i+1) << "-a elementa ";
cin >> *(x+i); }
cout << endl;
}
return x;
}
//
Rikiavimas
void Tvarka(int *x, int n) {
int i, j, c;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if (*(x+j) > *(x+i) ) {
c = *(x+i);
*(x+i) = *(x+j);
*(x+j) = c; }
}
//
Ivedimas ekrane
void Sp(int *x, int n) {
int i = 0;
while(i < n) {
cout << (i+1) << "-elementas: " << *(x+i) << endl;
i++; }
}

9 Atminties iskyrimui patogu naudoti operatori new. Pakeiskite


2.3 pratimo funkcijos Duomenys eilut:
x = (int *) malloc(n * sizeof(int));

nauja eilute:
x = new int[n];

Ibandykite program.
dvimaiams masyvams.
30

Isiaikinkite

new

galimybes,

taikym

2.4. Dvimatis masyvas


Dvimaio masyvo (matricos) apraas:
duomen tipas masyvo vardas
[eilui skaiius] [stulpeli skaiius];

Pavyzdiui, uraas int A[10][8] rodo, kad bus 10 eilui (0, 1,


2, , 9) ir kiekviena j turs po 8 elementus (stulpeliai 0, 1, 2, , 7).
Matricos elementas veiksmuose nurodomas dviem indeksais, kurie raomi
atskiruose lautiniuose skliaustuose: A[2][3].
Sudtingesniuose udaviniuose tikslinga sukurti savo duomen tipus.
Masyvo tipas sukuriamas taip:
typedef
vardas

masyvo

element

tipas

masyvo

tipo

indeks apraas;

Pavyzdiui:
typedef int Masyvas [55];
typedef float Matrica [10][15];
const Kiek = 15
typedef double Lentele [Kiek][Kiek];

ia buvo sukurti fiksuotos apimties masyv tipai.


Dabar galima aprayti kelet to paties tipo masyv:
Masyvas A, B, C;

Matrica P, D, R;
Lentele Pirma, Antra;

2.5 pratimas. Klaviatra vedami duomenys, kurie saugomi matricoje.


Suskaiiuojama matricos kiekvienos eiluts element suma. Rezultatai
suraomi vienmat masyv.
#include <iostream.h>
#include <alloc.h>
typedef int mas [10];
typedef int matr[10][15];
int Duomenys(matr, int *, int *);
void Sp
(mas, int);
int Suma
(mas, int);

// Duomen vedimas
// Spausdinimas
// Masyvo element suma

31

//
Pagrindin programa
void main() {
matr A;
mas S;
int n, m, i, j;
Duomenys(A, &n, &m);
// Duomen vedimas klaviatra
if (A != NULL) {
cout << "----------------------\n";
for (i=0; i<n; i++)
// Matricos spausdinimas
for (j=0; j<m; j++) cout << A[i][j] << endl;
cout << "----------------------\n";
for (i=0; i<n; i++) {
// Matricos spausdinimas
cout << "Eilute Nr " << (i+1) <<": ";
Sp(A[i], m); }
// Vienos eiluts spausdinimas
cout << "----------------------\n";
// Skaiiavimai
for (i=0; i<n; i++) S[i] = Suma(A[i], m);
Sp (S, n); }
// Suformuoto masyvo spausdinimas
cout << endl;

}
//
Duomen vedimas
int Duomenys(matr D, int *n, int *m) {
int i, j;
cout << "Iveskite n reiksme: ";
cin >> *n;
cout << "Iveskite m reiksme: ";
cin >> *m;
for (i=0; i<*n; i++) {
cout << "Eilute Nr:" << (i+1) << endl;
for (j=0; j<*m; j++) {
cout << "Iveskite " << (j+1) << "-a elementa ";
cin >> D[i][j]; } }
cout << endl;
return 1; }
}
//
Spausdinimas
void Sp(mas x, int n) {
int i = 0;
while (i<n) cout << x[i++] << " " << endl; }
//
Masyvo element sumos skaiiavimas
int Suma(mas D, int k) {
int i, Sk=0;
for (i=0; i<k; i++) Sk += D[i];
return Sk; }

32

9 Galima

turti funkcij,
Ibandykite i funkcij:

kuri

suformuot

rezultat

masyv.

// funkcijos prototipas
void Suma (mas, matr, int, int);

i funkcija, vis matricos eilui element sumas surao vienmat


masyv, kurio vardas nurodomas kreipinio metu pirmuoju parametru.
void Suma(mas R, matr D, int eil, int st ) {
int i, j;
for (i=0; i<eil; i++) {
*(R+i) = 0;
for(j=0; j<st; j++) *(R+i) += D[i][j]; }
}

2.5. Duomen failai


Apdorojant didesns apimties duomen srautus, patogu duomenis saugoti
failuose. Failo kintamieji apraomi tipo FILE rodykle:
FILE *F;

Failai paruoiami darbui funkcija, kurios prototipas toks:


#include <stdio.h>
FILE *fopen(const char *FailoVardas, const char *M);

ia FailoVardas nurodomas kaip simboli eilut: konstanta tarp


kabui, arba konstantos vardu, arba kintamuoju, turiniu t reikm. Failo
paruoimo darbui bvis nurodomas antruoju parametru M (simbolin
eilut: konstanta, jos vardas arba kintamasis). Galimos bvio reikms
suraytos 2.1 lentelje.
2.1 lentel. Failo paruoimo darbui bsenos

r
w
a

tik skaitymui;
tik raymui; jeigu failas egzistavo, tai naikinamas ir
sukuriamas naujai;
papildymui gale; jeigu failo nebuvo, tai sukuriamas;

Bvio reikm papildius raide t (rt, wt, at), failas bus paruoiamas
darbui kaip tekstinis. Bvio reikm papildius raide b (rb, wb, ab),
failas bus paruoiamas darbui kaip binarinis. Jeigu nebus panaudota nei t,
nei b raids, tai failas bus atidaromas darbui priklausomai nuo globalinio
kintamojo fmode reikms (r. fcntl.h). Kiekvienas bvio variantas
33

gali bti papildytas enklu + (plius) (pvz.: r+, w+, wt+). Tai reikia, kad
failai paruoiami atnaujinimui (leidiama skaityti ir rayti).
Toliau pristatome pagrindini buferizuot I/O funkcij prototipus.
int fclose(FILE *rod);

//

failo udarymas

int putc(int simbolis, FILE *rod);

//

simbolio raymas

int getc(FILE *rod);

// simbolio skaitymas

int putw(int sk, FILE *rod);

//

int getw(FILE *rod);

// skaiiaus skaitymas

skaiiaus raymas

char *fgets(char *s, int n, FILE *rod);


// skaito eilut s i n simboli
int fputs(const char *s, FILE *rod);

//

eiluts s raymas

int fread(void *buf, int t, int n, FILE *rod);


// siunia n po t bait turini blok i failo rod bufer buf;

// funkcijos reikm rodo perskaityt blok skaii


int fwrite(void *buf, int t, int n, FILE *rod);
// Siunia n po t bait turini blok i buferio buf fail rod;

// funkcijos reikm rodo perskaityt blok skaii


int fprintf(FILE *rod, const *char f [,<sraas>]);
// fail rod, naudojant ablon f, raomi srao elementai;

// ablonas ir argument sraas sudaromi taip, kaip ir funkcijai


// printf
int fscanf(FILE *rod, const *char f [,<sraas>]);

// skaitymas pagal ablon. Funkcijos reikm


// skmingai perskaityt element skaiius
int feof(FILE *rod);

// failo pabaiga nenulin funkcijos reikm

int ferror(FILE *rod); //

klaida nenulin funkcijos reikm

int remove(const *char vardas);

//

alinamas failas

Fail apdorojimo programoms apdorojam fail vardai gali bti


perduodami pagrindins funkcijos parametrais. Funkcijos prototipas:
int main(int n, char *argv[ ]);

34

ia n argument skaiius, o argv argumentams skirto eilui masyvo


rodykl. Argument reikms yra nurodomos programos ikvietimo
komandoje ir yra atskiriamos tarpais. Nulin argument masyvo eilut
tai paios programos pavadinimas.
2.6 pratimas. Duomen faile duom6.dat surayti skaiiai. Reikia
duomenis i failo surayti masyv ir atspausdinti ekrane. Suskaiiuoti
masyvo element sum ir atspausdinti ekrane.
#include
#include
#include
#include

<io.h>
<stdio.h>
<iostream.h>
<conio.h>

const Kiek = 15;


typedef int mas [Kiek];
FILE *F;
void Sp
(mas, int);
// Spausdina masyv
int Suma (mas, int);
// Sumuoja masyvo elementus
//
Pagrindin programa
void main() {
mas A;
int n = 0;
F = fopen("duom6.dat", "r");
if (F == NULL) printf("Failas neatidarytas");
else {
while (!feof(F) && ( n < Kiek)) {
fscanf(F, "%d", &A[n]); n ++; }
Sp(A, n);
printf("Suma=%5d\nPabaiga", Suma(A, n)); }

}
//
Spausdina masyv
void Sp(mas X, int n) {
int i = 0;
while (i<n) cout << X[i++] << " " << endl;
}
//
Sumuoja masyvo elementus
int Suma(mas R, int k) {
int i = 0, S = 0;
while (i<k) S += R[i++];
return S;
}

35

2.7 pratimas. Duomen faile duom7.dat surayti skaiiai. Reikia


duomenis i failo surayti masyv. Masyvo element reikms
atspausdinamos kitame faile.
#include
#include
#include
#include
#include

<iostream.h>
<stdio.h>
<alloc.h>
<conio.h>
<stdlib.h>

const Kiek = 10;


typedef int mas [Kiek];
void SpF(mas, int, char);
// Masyvo element ivedimas fail
int Ivesti(mas, int *);
// Skaitymas i failo
//
Pagrindin programa
void main() {
mas A;
int n = 0;
if (Ivesti(A, &n)) {
cout << "\nDuomen failo nra\n";
getch();
exit(1); }
SpF(A, n, 'A');
}
//
Skaitymas i failo
int Ivesti(mas A, int *n) {
FILE *F;
F = fopen("duom7.dat", "r");
if (F == NULL) {
printf( "Failas neatidarytas");
return 1; }
else {
while(!feof(F) && (*n < Kiek)) {
fscanf(F, "%d", &A[*n]);
n++; }
// Borland C++4.5 realizacijoje raoma (*n)++
fclose(F);
return 0; }
}
//
Masyvo element ivedimas fail
void SpF(mas X, int n, char R) {
FILE *F;
int i = 0;
F = fopen("duom7.rez", "w");

36

if (F == NULL)
printf("Failas neatidarytas spausdinimui");
else {
while (i<n)
fprintf(F, "%c[%2d]=%4d\n", R, i, X[i++]);
fclose(F); }
}

Duomen failas: Duom7.dat


5 6 98 -5 12 3 4 5
21 -3 4 5 23 1
23 34 45 5 6 -123

9 Duomen

Rezultat failas: Duom7.rez


A[ 1]=
A[ 2]=
A[ 3]=
A[ 4]=
A[ 5]=
A[ 6]=
A[ 7]=
A[ 8]=
A[ 9]=
A[10]=

5
6
98
-5
12
3
4
5
21
-3

vedimo funkcijoje Ivesti skaitymo cikl pakeiskite

tokiu:
while((fscanf(F, "%d", &A[*n]) != EOF ) &&
(*n < Kiek)) *n++;

9 Dabar duomen vedimo funkcijoje skaitymo cikl pakeiskite tokiu:


while((fscanf(F, "%d", &A[*n]) != EOF ) &&
(*n++ < Kiek));

Palyginkite visus tris variantus ir pasirinkite, kuris Jums suprantamiausias.


Silome programas rayti paprastesnes ir aikesnes, nes jas lengviau ir
greiiau suvokti ne tik Jums, po kurio laiko modifikuojant, bet ir kitiems,
turintiems maiau praktinio programavimo gdi.
2.8 pratimas. Duomen faile suraytos tak, esani koordinai
ploktumoje, koordinats (x, y). Reikia duomenis surayti
matric, kur pirmame stulpelyje bt tak x koordinats, antrame
stulpelyje y koordinats. Parayti funkcij, kuri matricos treiame
stulpelyje surayt tak atstumus iki koordinai pradios tako.
Ketvirtame stulpelyje paymti, kokiam ketviriui takas priklauso.
Nuliuku ymti takus, esanius ant ai. Rezultat faile atspausdinti
37

matricos duomenis, uraant kiekvieno stulpelio prasm nusakanius


pavadinimus ir numeruojant eilutes. Gale parayti, kiek kuriame
ketvirtyje yra tak, ir kiek yra tak ant ai.
#include
#include
#include
#include
#include
#include
#include

<iostream.h>
<stdio.h>
<alloc.h>
<conio.h>
<stdlib.h>
<math.h>
<time.h>

typedef float mas[][4];


const
char *Duomenys
= "Duom8.dat";
const
char *Rezultatai = "Duom8.rez";
void RezFailas();
//
int Failas();
//
mas *Ivesti(int);
//
void Spausdinti(mas *, int, int); //
void Atstumai(mas *, int);
//
void Vieta(mas *, int);
//
//
Pagrindin programa
void main() {
mas *A;
int n;
RezFailas();
if((n = Failas()) == 0) {
cout<<" Duomenu nerasta\n";
getch();
exit(0); }
A = Ivesti(n);
if (A == NULL) {
cout<<"NERA NERA \n";
getch();
exit(1); }
cout << "Masyvas ivestas n = "<< n
Spausdinti(A, n, 0);
Atstumai(A, n);
Spausdinti(A, n, 1);
Vieta(A, n);
Spausdinti(A, n, 2);
}

38

Rezultat failo paruoimas


Randa kiek yra duomen
Duomen vedimas
Rezultat spausdinimas
Tak atstumai
Tak padtis ploktumoje

<< endl;

//
Paruoia rezultat fail. Urao dat ir laik
void RezFailas() {
FILE *F;
char Data[9], Laikas[9];
if(F = fopen(Rezultatai, "w")) {
_strdate(Data);
_strtime(Laikas);
fprintf(F, "%s %s\n", Data, Laikas);
fclose(F); }
}
//
Patikrina, ar yra duomen failas ir kiek jame tak
int Failas() {
FILE *F;
int n = 0, k;
if ((F = fopen(Duomenys, "r")) == NULL ) {
cout << "Duomenu failo nera\n";
return 0; }
while(!feof(F)) {
n++;
fscanf(F, "%d%d\n", &k, &k); }
fclose(F);
return n;
}
//
Skaito duomenis i failo masyv
mas *Ivesti(int n) {
FILE *F;
mas *A;
if ((F = fopen(Duomenys, "r")) == NULL) {
cout << "Duomenu failas neatidarytas\n";
getch();
return NULL; }
A = (mas *) malloc(n*4*sizeof(float));
if(A == NULL) {
cout << "Truksta masyvui atminties\n";
getch();
return NULL; }
n = 0;
while(!feof(F)) {
fscanf(F, "%f%f\n", &(*A)[n][0], &(*A)[n][1]);
n++; }
fclose(F);
return A;
}

39

//
Spausdina duomenis ir rezultatus
/* Raktas k valdo:
kai 0, spausdina tik tak koordinates (duomenis);
kai 1, spausdina duomenis ir tak atstumus iki koordinai pradios tako;
kai 2, spausdina duomenis, atstumus ir tak vietas koordinai ploktumoje.*/
void Spausdinti(mas *C, int n, int k) {
FILE *F;
int i;
if ((F = fopen(Rezultatai, "a")) == NULL) {
cout << "Rezultatu failas neatidarytas\n";
getch(); return; }
switch(k) {
case 0:
fprintf(F, "Duomenys\n");
fprintf(F, "*********************\n");
fprintf(F, " Nr.
x
y
\n");
break;
case 1:
fprintf(F, "\nDuomenys ir atstumai iki koord.
pradzios\n");
fprintf(F, "******************************\n");
fprintf(F, " Nr.
x
y
Atstumas \n");
break;
case 2:
fprintf(F, "\nDuomenys, atstumai ir tasko vieta
koord. plokstumoje\n");
fprintf(F, "**************************************\n");
fprintf(F, " Nr.
x
y
Atstumas
Vieta \n");

break;
}
for(i=0; i<n; i++) {
switch(k){
case 0: fprintf(F," %3i %7.2f %7.2f \n", i+1,
(*C)[i][0],(*C)[i][1]);
break;
case 1: fprintf(F, "%3i %7.2f %7.2f %7.2f \n",
i+1, (*C)[i][0],(*C)[i][1],(*C)[i][2]);
break;
case 2:
fprintf(F, "%3i %7.2f %7.2f %7.2f %7.2f \n",
i+1, (*C)[i][0],(*C)[i][1],(*C)[i][2],(*C)[i][3]);
break;
}}
switch(k) {

40

case 0:
fprintf(F, "*********************\n");
break;
case 1:
fprintf(F, "******************************\n");
break;
case 2: fprintf(F,
"**************************************\n");
break;

}
fclose(F);

}
//
Skaiiuojami tak atstumai iki koordinai pradios tako
void Atstumai(mas *D, int n) {
float x, y;
for (int i = 0; i<n; i++) {
x = (*D)[i][0];
y = (*D)[i][1];
(*D)[i][2] = sqrt(x*x + y*y); }
}
//
Nustatoma tako padtis koordinai ploktumoje
/* 14 nurodo ketvirio numer, o 0 kad takas yra ant vienos i ai. */
void Vieta(mas *D, int n) {
float x, y;
for (int i=0; i<n; i++) {
x = (*D)[i][0];
y = (*D)[i][1];
if ((x>0) && (y>0)) (*D)[i][3] = 1;
else if ((x>0) && (y<0)) (*D)[i][3] = 4;
else if ((x<0) && (y>0)) (*D)[i][3] = 2;
else if ((x<0) && (y<0)) (*D)[i][3] = 3;
else (*D)[i][3] = 0; }
}

Duomen failo pavyzdys:


15
13
-15
-22
0
5
-5
0
-1

12
-5
-45
22
5
0
0
-5
-1

41

Rezultat failo pavyzdys:


06/08/99 21:48:34
Duomenys
*********************
Nr.
x
y
1
15.00
12.00
2
13.00
-5.00
3 -15.00
-45.00
4 -22.00
22.00
5
0.00
5.00
6
5.00
0.00
7
-5.00
0.00
8
0.00
-5.00
9
-1.00
-1.00
*********************
Duomenys ir atstumai iki koord. pradzios
******************************
Nr.
x
y
Atstumas
1
15.00
12.00
19.21
2
13.00
-5.00
13.93
3 -15.00
-45.00
47.43
4 -22.00
22.00
31.11
5
0.00
5.00
5.00
6
5.00
0.00
5.00
7
-5.00
0.00
5.00
8
0.00
-5.00
5.00
9
-1.00
-1.00
1.41
******************************
Duomenys, atstumai ir tasko vieta koord. plokstumoje
**************************************
Nr.
x
y
Atstumas
Vieta
1
15.00
12.00
19.21
1.00
2
13.00
-5.00
13.93
4.00
3 -15.00
-45.00
47.43
3.00
4 -22.00
22.00
31.11
2.00
5
0.00
5.00
5.00
0.00
6
5.00
0.00
5.00
0.00
7
-5.00
0.00
5.00
0.00
8
0.00
-5.00
5.00
0.00
9
-1.00
-1.00
1.41
3.00
**************************************

42

2.9 pratimas. Naudodamiesi C++ aplinkos pagalbine informacija (Ctrl+F1)


isiaikinkite, kaip sudaryta struktrizuoto tekstinio failo
Duom9.txt papildymo programa. Failo eilutse yra saugomi
duomenys apie vairiems asmenims priklausanius telefonus.
Duomen elementams yra skiriamos tokios eilui atkarpos: pavard
[1, 20], vardas [21, 40], telefono numeris [41,50]. Sukurkite tokios
struktros fail ir patikrinkite program. Programos vykdymo pabaigos
slyg isiaikinkite nagrindami jos tekst.
#include
#include
#include
#include

<string.h>
<stdio.h>
<stdlib.h>
<conio.h>

FILE *failas;
char buf[50], e1[20], e2[20], e3[10];
const char vardas[] = "Duom9.txt";
int Init
(const char *, char *);
void Duomenys(FILE *);
void Rodyti (FILE *);
//
Pagrindin programa
void main() {
buf[0] = '\0';
if (!Init(vardas, "a")) exit(1); // Failo paruoimas darbui
Duomenys(failas);
// Duomenys vedami klaviatra fail
fclose(failas);
if (!Init(vardas,"r")) exit(1); //Failo paruoimas skaitymui
Rodyti(failas);
// Duomenys siuniami ekran
fclose(failas);

}
// Naujo failo atidarymas skaitymui/raymui arba seno papildymui
int Init (const char *v, char *mode) {
if ((failas = fopen(v, mode)) == NULL) { // Failo nebuvo
// Naujo sukurti nepavyko
if ((failas = fopen(v, "w+")) == NULL) {
fprintf(stderr,
"Atidaryti fail raymui/skaitymui nepavyko.\n");
return 0; }
// Klaidos poymis
else return 1; }
// Naujai sukurtas failas
else return 2;
// Surastas failas ir atidarytas
}

43

//
Duomenys vedami klaviatra fail
void Duomenys(FILE *failas) {
int i;
while(buf[0] != 'q') {
// vedimo pabaiga nurodoma eilute, kurios pirmas simbolis yra 'q'

buf[0]= '\0';

// Struktrizuotos eiluts sudarymo ir raymo ciklai

printf("Nurodykite pavarde, varda ir telefono numeri:\n");


scanf("%s %s %s", e1, e2, e3);
strcat(buf, e1);
for(i=strlen(buf); i<20; i++) strcat(buf, " ");
strcat(buf, e2);
for(i=strlen(buf); i<40; i++) strcat(buf, " ");
strcat(buf, e3);
strcat(buf, "\n");
if (buf[0] != 'q')
fwrite(buf, strlen(buf), 1, failas); }

}
//
Duomenys siuniami ekran
void Rodyti(FILE *) {
while(fgets(buf, strlen(buf)+1, failas))
printf("%s",buf);
}

9Sudarykite

pagalbin funkcij buferinio kintamojo buf papildymui


formatuotais laukais.

9Pakeiskite

programoje blok raymo komand fwrite eilui


raymo komanda fputs.

9Pakeiskite program taip, kad jos darb bt galima nutraukti vedus


vieno simbolio eilut: "Q" arba "q". Norint tai padaryti, reikia i
klaviatros perskaityti i karto vis eilut ir tik po to j skanuoti su
funkcija sscanf.
2.10 pratimas. Panaudodami duomen sraut apdorojimo klas ofstream
vedame duomenis matric ir atlik veiksmus (sukeiiami vietomis
stulpeliai su didiausia ir maiausia matricos reikme) ivedame
rezultatus.
#include
#include
#include
#include

44

<fstream.h>
<stdio.h>
<stdlib.h>
<iomanip.h>

const num = 15;


typedef int matr[num][num];
void read(char *, matr, int *);
// Duomen skaitymas
void print(char *, matr, int, char *); // Spausdinimas
int max(matr, int);
// Didiausio paieka
int min(matr, int);
// Maiausio paieka
void swap(matr, int, int, int);
// Stulpeli sukeitimas
int test(char *, char *);
// Fail paruoimas
//
Pagrindin programa
void main(void) {
int n;
matr a;
char inbuff[12], outbuff[12];
// Fail vardams saugoti
// Rodykls fail vardus *duom ir *rezult
cout << "Koks duomenu failo vardas?\n";
char *duom = gets(inbuff);
cout << "Koks rezultatu failo vardas?\n";
char *rezult = gets(outbuff);
if (test(duom, rezult)) {
cout << "Klaida atidarant failus"; exit(0); }
read(duom, a, &n);
// Duomen skaitymas matric
// Duomen spausdinimas fail
print(rezult, a, n, "Pradiniai duomenys");
swap(a, n, min(a, n), max(a, n));
print(rezult, a, n, "Rezultatai"); // Rezultat spausdinimas
cout << "Pabaiga\n\a";
}
//
Duomen skaitymas
void read(char *is, matr a, int *n) {
ifstream infile(is);
// Duomen failo atidarymas
infile >> *n;
// vedama n reikm
(*n)--;
// Matricos vedimas
for(int i=0; i<=*n; i++)
for(int j=0; j<=*n; j++)
infile >> a[i][j];
infile.close();
// Failo udarymas
}
//
Spausdinimas
void print(char *os, matr a, int n, char *text) {
// Rezultat failas paruoiamas papildymui
ofstream offile(os, ios::app);

45

offile << '\n' << text << '\n' << "


";
for(int j=1; j<=n+1; j++) offile << setw(5) << j;
offile << " \n
|";
for(j=0; j<=n; j++) offile << "-----";
offile << " \n";
for(int i=0; i<=n; i++) {
offile << setw(3) << (i+1) << " |";
for(int j=0; j<=n; j++)
offile << setw(5) << a[i][j];
offile << " \n"; }

}
//
Randamas stulpelis su didiausia reikme
int max (matr a, int n) {
int m = -1000, p = -1;
// p - stulpelio numeris
for(int i=0; i<=n; i++)
for(int j=0; j<=n; j++)
if (a[i][j] > m) { m = a[i][j]; p = j; }
return p; }
//
Randama maiausia reikm
int min(matr a, int n) {
int m = 1000, p = -1;
// p - stulpelio numeris
for(int i=0; i<=n; i++)
for(int j=0; j<=n; j++)
if (a[i][j] < m) { m = a[i][j]; p = j; }
return p; }
//
Sukeiiami du stulpeliai vietomis
void swap(matr a, int n, int mine, int maxe) {
int p;
for(int i=0; i<=n; i++) {
p = a[i][mine];
a[i][mine] = a[i][maxe];
a[i][maxe] = p; } }
//
Pagrindin programa
int test(char *is, char *os) {
ifstream duomenys(is);
// Patikrinamas duomen failas
if (!duomenys) return 1;
duomenys.close();
ofstream rezultatai(os);
// Patikrinamas rezultat failas
if (!rezultatai) return 1;
// rezultat fail ivedamas praneimas
rezultatai << "Matrica \n";
rezultatai.close();
return 0;

46

}
Duomen failas
4
15 1 5
6
2 25 6
7
5 -5 5 -45
1
2 3
4

Rezultat failas
Matrica
Pradiniai duomenys
1
2
3
4
|-------------------1 |
15
1
5
6
2 |
2
25
6
7
3 |
5
-5
5 -45
4 |
1
2
3
4
Rezultatai
1
2
3
4
|-------------------1 |
15
6
5
1
2 |
2
7
6
25
3 |
5 -45
5
-5
4 |
1
4
3
2

2.6. Simboli eiluts


Simboli masyvai gali bti vartojami simboli eilutms apdoroti.
Naudojant masyvus simboliams saugoti, reikia atsiminti, kad C++ kalboje
eilui reikmi pabaigas priimta ymti nulinio ASCII kodo simboliu,
kuris ymimas '\0'. Simbolinio tipo konstantos taip pat yra raomos tarp
apostrof, pavyzdiui 'a', 'D'. Eiluts tipo konstantos raomos tarp
kabui, pavyzdiui, "Katinas".
2.11 pratimas. Klaviatra vedamas odis (simboli eilut be tarp). Programa
vestoje simboli eilutje visas masias raides keiia didiosiomis.
#include <iostream.h>
#include <conio.h>
void main() {
char Eil[80];
int i, c;
c = 'a' - 'A';
// Atstumas tarp raidi kod lentelje
cout << "veskite eilut maosiomis raidmis ir be
tarp\n";
cin >> Eil;
for(i=0; Eil[i] != '\0'; i++)

47

if (Eil[i] >= 'a')


cout << Eil << endl;

Eil[i] -= c;
}

Sudarykite program, kuri skaiiuot ir parodyt ekrane vis


klaviatra vestos eiluts lotynik raidi pasikartojimo danius.
Didiosios ir maosios raids turi bti interpretuojamos vienodai.
Neumirkite, kad C kalboje char ir int tipai yra suderinami
Prie nagrindami tolesnius pavyzdius, apvelgsime kelias funkcijas,
palengvinanias darb su eilutmis.
char *strcpy(char *dest, const char *src);
Eilut src kopijuoja dest iki nulinio simbolio. Grina rodykl dest.
char *stpcpy(char *dest, const char *src);
Eilut src kopijuoja eilut dest iki nulinio simbolio. Grina
dest + strlen(src).
char *strcat(char *dest, const char *src);
Eiluts src kopij prijungia prie eiluts dest galo. Grina rodykl
sujungtas
eilutes
(dest).
Grinamos
eiluts
ilgis
yra:
strlen(dest) + strlen(src).
const char *strchr(const char *s, int c);
char *strchr(
char *s, int c);
Eilutje s ieko simbolio c. Paieka pradedama nuo eiluts pradios ir

baigiama suradus pirmj simbol, lyg nurodytam. Nulinis simbolis


laikomas eiluts dalimi, todl jo paieka taip pat galima. Pavyzdiui,
strchr(strs,0) grina rodykl nulin simbol. Funkcija grina
rodykl surast simbol eilutje, arba NULL neradus.
2.12 pratimas. Programa iliustruoja funkcijos strchr veikim.
#include <string.h>
#include <stdio.h>
int main(void) {
char string[20];
char *ptr, c = 'r';
strcpy(string, "Nagrinelama eilute");
ptr = strchr(string, c);
if (ptr) printf("Simbolis %c yra:
%d-as\n", c, ptr-string);
else printf("Tokio simbolio eiluteje nera\n");

48

return 0;
}

vykd program, ekrane matysime eilut:


Simbolis r yra: 3-as

9 Pertvarkykite program taip, kad ji ivardyt ekrane visas dialogo su


vartotoju metu nurodytos raids pozicijas klaviatra vestoje eilutje.
int strcmp(const char *s1, const char *s2);

Palygina eilutes. Lygina eilutes, pradedant pirmaisiais simboliais iki tol,


kol bus surasti nesutampantys simboliai arba bus surasta vienos i eilui
pabaiga.
Jeigu s1 yra...
maesn u eilut s2
lygi eilutei s2
didesn u eilut s2

strcmp grina reikm, kuri yra...


< 0
== 0
> 0

int strcmpi(const char *s1, const char *s2);

Palygina eilutes, kaip ir ankstesn, tik masias ir didisias raides laiko


vienodomis.
size_t strlen(const char *s);

Grina simboli skaii eilutje. Nulinis simbolis neskaiiuojamas.


char *strncpy(char *dest,
const char *src, size_t maxlen);

Kopijuoja i eiluts src eilut dest nurodyt simboli skaii


maxlen. Jeigu eilutje src simboli maiau, negu nurodytas kiekis
maxlen, tuomet rezultate bus tiek, kiek surasta; jeigu daugiau negu
reikia, tai tiek kiek nurodyta. Grinama rodykl dest eilut.
2.13 pratimas. Programa iliustruoja funkcijos strncpy veikim.
#include <stdio.h>
#include <string.h>
int main(void) {
char string[10];
char *str1 = "abcdefghi";
strncpy(string, str1, 3);
string[3] = '\0';
printf("%s\n", string);

49

return 0;
}

vykd program, ekrane matysime eilut:


abc

char *strtok(char *s1, const char *s2);


Funkcija grina rodykl s1 fragment (od) i simboli, kuri nra
eilutje s2, o u fragmento terpia nulinio kodo simbol. Kartojant kreipin
su NULL vietoje pirmo argumento, grinama rodykl kit od. Kai
nauj odi nebra, grinama rodykl NULL.
2.14 pratimas. Programa iliustruoja funkcijos strtok veikim.
#include <string.h>
#include <iostream.h>
#include <conio.h>
void main() {
char Eil[30] = "Joju, dairausi ir dainuoju";
char *p, sep[5]= ", ";
cout << Eil << endl;
// Visa tiriama eilut
// strtok terpia ribotuv NULL u surasto odio
p = strtok(Eil, sep);
if (p) cout << p << endl;
// Pirmasis odis
// Antras kreipinys su argumentu NULL grina antro odio adres
p = strtok(NULL, sep);
if (p) cout << p << endl;
// Antrasis odis
cout << Eil << endl;
// Tik pirmasis odis
}

vykd program, ekrane matysime eilut:


Joju, dairausi ir dainuoju
Joju
dairausi
Joju

9 Pertvarkykite pavyzdio program su ciklo operatoriumi taip, kad ji


parodyt ekrane visus tiriamos eiluts odius. Analizs ciklo pabaigos
poymiu vartokite grinamos rodykls reikm NULL. Atskiriamus i
50

eiluts odius i pradi suraykite odi masyv ir tik po to


parodykite ekrane.
char *_strtime(char *buf);

Kompiuterio laik urao eilutje buf, kurios ilgis privalo bti 9 Eiluts
forma HH:MM:SS, kur HH valandos, MM minuts ir SS sekunds.
Grina eiluts buf adres. Eilut baigiama nuliniu simboliu.
char *_strdate(char *buf);

Kompiuterio dat urao eilutje buf, kurios ilgis privalo bti 9 Eiluts
forma MM/DD/YY, kur MM mnuo, DD mnesio diena ir YY met
paskutiniai du skaiiai. Grina eiluts buf adres. Eilut baigiama
nuliniu simboliu.
2.15 pratimas. Programa iliustruoja funkcij _strdate
veikim.

ir _strtime

#include <time.h>
#include <stdio.h>
void main(void) {
char data[9];
char laikas[9];
_strdate(data);
_strtime(laikas);
printf("Data: %s Laikas: %s\n", data, laikas);
}

vykd program, ekrane matysime vykdymo dienos dat ir laik,


pavyzdiui:
Data: 10/22/00

Laikas: 11:13:16

2.16 pratimas. Klaviatra vedama simboli eilut, kur odiai skiriami bent
vienu tarpu. Reikia atspausdinti eiluts odius po vien ekrane,
nurodant odio pradios ir pabaigos indeksus. Ankstesniame pratime
eiluts vedimo pabaiga buvo pirmas sutiktas tarpas arba eiluts
pabaiga, todl paraius kelis odius, buvo vedamas tik pirmasis.
Visos eiluts vedimui galima naudoti funkcij:
#include <stdio.h>
char *gets(char *s);

51

Skaitomos eiluts pabaigos simbolis '\n' automatikai pakeiiamas


simboliu '\0'. Sudarant program, tikslinga vis eilut perskaityti
jai skiriam simboli masyv ir po to analizuoti po vien simbol.
#include
#include
#include
#include

<iostream.h>
<conio.h>
<stdio.h>
<string.h>

typedef char Mas[80];


void zodis(Mas, Mas, int *);
// odio atskyrimas
//
Pagrindin programa
void main() {
Mas Eil, Z;
int i, c;
cout << "veskite eilut maosiomis raidmis\n";
cout << " odius atskirkite tarpais\n";
gets(Eil);
// Simboli eilut
cout << Eil << endl;
// Eilut spausdinama ekrane
strcat(Eil, " "); // Po paskutinio odio bus tarpas
i = 0;
while(Eil[i] != '\0') {
// odi atskyrimas:
c = i;
//
odio pradia;
zodis(Eil, Z, &i);
// surastas odis pradedant i vieta;
if (Z[0] != '\0')
// jeigu buvo odis, tai spausdinamas
cout << "Pradia: " << c << " Pabaiga: " << (i-1)
<< " *" << Z << "*" << endl;
i++; }
//
Praleidiamas tarpas
}
//
odio atskyrimas
/* I eiluts A, pradedant simboliu, numeris n, iskiriamas odis.
Surasto odio simboliai suraomi eilut B. Gale nulinis simbolis */
void zodis(Mas A, Mas B, int *n) {
int i = 0;
while((A[*n] != '\0') && (A[*n] != ' '))
B[i++] = A[(*n)++];
B[i] = '\0';
}

9 Ibandykite skaitymo po vien simbol funkcij:


int getc(FILE *stream);

52

Skaitant i klaviatros, turi bti vartojamas failo vardas stdin. Eiluts


skaitymo bufer apraymo pavyzdys:
// Tuias ciklas!
while((Eil[i++] = getc(stdin)) != '\n');
str[--i]='\0';
// Eiluts pabaigos ym

9 Pertvarkykite

odi atskyrimo program taip, kad ji ekrane


parodyt tik ilgiausi od. odio ilgio skaiiavimui siloma vartoti
toki funkcij:
int length(char* x) {
int i = 0;
while(x[i++]);
return
--i; }

Atskiro simboli eilui tipo C++ kalboje nra. Eiluts yra saugomos
simboli masyvuose, kur j pabaigos yra ymimos nulinio kodo simboliais
'\0'. Daugumoje C++ kalbos realizacij yra toki masyv apdorojimo
bibliotekos, kuriose yra vairios eilui struktros analizs ir j tvarkymo
funkcijos. Borland C++ realizacijoje ios priemons yra paskirstytos
dviejose bibliotekose: string.h (struktros analiz ir tvarkymas) ir
stdlib.h (tip keitimas).
2.17 pratimas. Savarankikai isiaikinkite pavyzdio programlje vartojam
eilui tvarkymo funkcij paskirtis ir kreipimosi jas bdus.
#include <iostream.h>
#include <string.h>
#include <conio.h>
typedef char zodis[15];
typedef char string[80];
int main() {
zodis x;
string z, t;
cout << "Iveskite savo varda ir
cin >> z >> x;
strcat(z, " ");
strcat(z, x);
strcpy(t, z);
strlwr(t);
cout << "Mazosiomis raidemis: "
strupr(t);

pavarde\n";
// Eilui sujungimas

// Maosios raids
<< t << endl;
// Didiosios raids

53

cout << "Didziosiomis raidemis: " << t << endl;


cout << "Buvo ivesta: " << z << endl;
cout << "Buvo raidziu: " << (strlen(z)-1) << endl;
}

Pertvarkykite program taip, kad ji i klaviatra vestos eiluts


atskirt odius ir paskirstyt du masyvus: skaii ir kitoki odi.
Abiej masyv elementai ir skaii masyvo suma turi bti parodomi
ekrane. Eilui pertvarkymui skaiius vartokite bibliotekos
stdlib.h funkcijas, kuri prototipai:
double atof(const char *s);
int atoi(const char *s);
Jos grina skaii reikmes arba 0, jeigu argumento eiluts negalima
pertvarkyti skaii.

54

3 skyrius. Struktros
Struktr apra sintaks:
struct <struktrinio tipo vardas>
{ <lauk apra sraas> }
[<kintamj sraas>];

Lauk apra sra elementai atskiriami kabliatakiais, o kintamj


srao elementai kableliais. Jei aprae nra kintamj srao, jis
apibria tik nauj struktrini duomen tip, taiau jo realizacijoms
atmintyje vietos neskiria. Atskiro struktros tipo apibrimo ir realizavimo
pavyzdys:
// Apibrimas
struct telefonas { char
vardas[30];
unsigned longint tel;
// Realizavimas
struct telefonas Tel, *P, TelMas[100];

Kreipiantis struktr elementus vartojami sudtiniai vardai:


<struktros vardas>.<lauko vardas>

Galimos rodykls sruktr tipo reikmes:


P = &Tel;

// struct telefonas *P;

Lauk vard uraymo, panaudojant rodykles, pavyzdiai:


(*P)->Tel, P->Tel, P->Tel.vardas

3.1 pratimas. Klaviatra vedamas moni sraas spausdinamas lentele faile.


#include
#include
#include
#include

<stdio.h>
<stdlib.h>
<iomanip.h>
<conio.h>

struct zmogus { char


char
int
float

vardas [10];
pavarde[10];
gim_met;
ugis;
};

55

FILE *F;
const char Duomenys[]="Prat31.rez";
int Atidaro(const char *, char *);
void Lentele();
//
Pagrindin programa
void main(void ) {
if (Atidaro(Duomenys, "w")) exit(0);
Lentele();
fclose(F);
cout << "Pabaiga\n\a";
}
//
Failo atidarymas
int Atidaro( const char *Vardas, char *Forma){
if (( F = fopen( Vardas, Forma )) == NULL )
{ cout<< "Failas neatidarytas"; return 1;}
else return 0; }
//
Duomenys vedami klaviatra ir spausdinami faile
void Lentele() {
struct zmogus A;
int n;
cout << "Kiek zmoniu bus ?\n";
cin >> n;
fprintf(F,"..........................................\n");
fprintf(F,":
Vardas : Pavarde : gim. m. : ugis :\n");
fprintf(F,"..........................................\n");

while(n--) {
cout << "Iveskite varda
\n"; cin >> A.vardas ;
cout << "Iveskite pavarde
\n"; cin >> A.pavarde;
cout << "Iveskite gimimo metus \n"; cin >> A.gim_met;
cout << "Iveskite ugi
\n"; cin >> A.ugis;
fprintf(F, ":%10s :%10s :
%4d : %3.2f :\n",
A.vardas, A.pavarde, A.gim_met, A.ugis); }
fprintf(F,"..........................................\n");

fclose(F);

Programos darbo rezultatai faile Prat31.rez:

..........................................
:
Vardas : Pavarde : gim. m. : ugis :
..........................................
:
Petras : Petraitis :
1933 : 2.15 :
:
Jurgis : Jurgelis :
1582 : 1.58 :
:
Kazys :
Kazelis :
1258 : 1.25 :
..........................................

56

Struktr masyvai sudaromi taip pat, kaip ir paprast duomen tip.


Rekomenduojama sukurti duomen tip, po to j naudoti.
3.2 pratimas. Klaviatra vedami duomenys suraomi struktr masyve. Po to
jie spausdinami lentele.
#include
#include
#include
#include

<stdio.h>
<stdlib.h>
<iomanip.h>
<conio.h>

struct zmogus { char


vardas [10];
char
pavarde[10];
int
gim_met;
float ugis; };
FILE *F;
const char Duomenys[]="Prat32.rez";
int Atidaro(const char *, char *);
void Ivesti(zmogus *, int *);
void Lentele(zmogus *, int);
//
Pagrindin programa
void main(void ) {
zmogus A[10];
int n = 0;
Ivesti(A, &n);
if (Atidaro(Duomenys, "w")) exit(0);
Lentele(A, n);
fclose(F);
cout<<"Pabaiga\n\a";
}
//
vedimas klaviatra
void Ivesti(zmogus *B, int *n) {
int i = 0;
cout << "Kiek zmoniu bus ?\n";
cin >> *n;
while(i < *n) {
cout << "*********************\n";
cout << (i+1) << "-ojo zmogaus duomenys:\n";
cout << "Iveskite varda
\n"; cin >> B[i].vardas;
cout << "Iveskite pavarde
\n"; cin >> B[i].pavarde;
cout << "Iveskite gim. metus\n"; cin >> B[i].gim_met;
cout << "Iveskite ugi
\n"; cin >> B[i].ugis;
cout << "Aciu \n";
i++; }
}

57

//
Failo atidarymas
int Atidaro(const char *Vardas, char *Forma) {
if ((F = fopen(Vardas, Forma)) == NULL )
{ cout << "Failas neatidarytas"; return 1; }
else return 0;
}
//
Ivedimas lentele
void Lentele(zmogus *C, int n) {
int i = 0;
fprintf(F,"..........................................\n");
fprintf(F,":
Vardas : Pavarde : gim. m. : ugis :\n");
fprintf(F,"..........................................\n");

while(i < n) {
fprintf(F, ":%10s :%10s :
%4d : %3.2f :\n",
C[i].vardas, C[i].pavarde, C[i].gim_met, C[i].ugis);
i++; }
fprintf(F,"..........................................\n");

fclose(F);
}

3.3 pratimas. Klaviatra vedami duomenys suraomi tipizuot fail. Po to


jie skaitomi i to failo ir parodomi ekrane.
#include
#include
#include
#include

<stdio.h>
<stdlib.h>
<iomanip.h>
<conio.h>

FILE *failas;
const char Rezultatai[]="Prat33.rez";
struct telefonas { char vardas [10];
char pavarde[10];
long tel;
} T;
int Atidaro ( const char *, char *);
void Raso();
void Skaito();
//
Pagrindin programa
void main(void ) {
if (Atidaro(Rezultatai, "w")) exit(0);
Raso();
fclose(failas);
if (Atidaro(Rezultatai, "r")) exit (0);
Skaito();

58

fclose(failas);
cout << "Pabaiga\n\a";

}
//
vedamus duomenis surao fail
void Raso() {
char buf[50] = "";
printf("Programos nutraukimas - eilute 'q'\n");
while(buf[0] != 'q') {
printf("Nurodykite varda, pavarde ir telefono numeri:\n");
gets(buf);
if (buf[0] != 'q') {
sscanf(buf, "%s%s%ld", T.vardas, T.pavarde, &T.tel);
fwrite(&T, sizeof(struct telefonas), 1, failas); } }
}
//
Failo atidarymas
int Atidaro(const char *Vardas, char *Forma) {
if ((failas = fopen(Vardas, Forma)) == NULL)
{ cout << "Failas neatidarytas"; return 1; }
else return 0;
}
//
Skaito i failo
void Skaito() {
printf(".......................................\n");
printf(":
Vardas
: Pavarde : telefonas :\n");
printf(".......................................\n");
while(fread(&T, sizeof(struct telefonas), 1, failas))
printf( ":%10s :%10s : %10ld :\n",
T.vardas, T.pavarde, T.tel);
printf(".......................................\n");
}

9 Pertvarkykite program, kad pagrindinje funkcijoje pagal vartotojo


pageidavimus bt galima pasirinkti tokius veiksmus: duomen failo
turinio ivedimas ekrane, naujo failo formavimas arba esanio failo
papildymas. Programos akojimui vartokite operatori case.
9 Papildykite program failo rikiavimo pagal pavardes alfabeto tvarka
funkcija. Rikiuojamo failo duomenys i pradi turi bti perraomi
ra masyv ir tik po to rikiuojami. Lyginant eilutes turi bti
vartojamos ne santykio operacijos, bet bibliotekos string.h
funkcijos
arba
makrokomandos:
stricmp,
strnicmp,
strncmpi, strcmpi.

59

Kuriant sudtingesnes programas tikslinga inoti kelet domesni


funkcij savybi. Kalboje C++ realizuota labai efektyvi funkcij savyb
polimorfizmas, kuri dar vadinama daugiavariantikumu arba funkcij
persidengimu (overloading). Senose C++ kalbos versijose polimorfini
funkcij apraai turi bti paymimi baziniu odiu overload. Kalbos
realizacijose Borland C++ tai daryti nebtina.
3.4 pratimas. Demonstruojama ivedimo ekrane polimorfin funkcija print,
kurios darbas priklauso nuo kreipinyje urayto duomen tipo.
#include <stdio.h>
#include <conio.h>
// overload
inline void
inline void
inline void

print;
// Bordland C galima praleisti.
print(int
x) {printf("%d\n"
, x); }
print(double x) {printf("%5.2f\n", x); }
print(char *x) {printf("%s\n",
x); }

void main(void ) {
print(3.14);
print(15);
print("Simboliu eilute");
}

// Slankaus kablelio skaiius


// Sveikas skaiius
// Simboli seka

ia baziniu odiu inline paymtos terpiamos funkcijos. terpiamos


funkcijos yra makrokomand analogai pirminis procesorius rao
funkcijos tekst kiekvieno kreipinio j vietoje. Jei funkcij tekstai
trumpi, toks funkcij tekst terpimas padidina program darbo greit.
3.5 pratimas. Dar viena labai naudinga funkcij savyb argument
parinkimas pagal nutyljim.
#include <stdio.h>
#include <conio.h>
struct upe { char *vardas;
char *salis; } x, y, z, k;
//
Funkcija Rodo
void Rodo(struct upe *d, char *a = NULL, char *b = NULL) {
d->vardas = a;
d->salis = b; }
//
Pagrindin programa
void main(void) {
Rodo(&x);

60

Rodo(&y, "Nemunas");
Rodo(&z, "Merkys", "Lietuva");
Rodo(&k, "Nilas");
printf("%10s %10s \n", x.vardas,
printf("%10s %10s \n", y.vardas,
printf("%10s %10s \n", z.vardas,
printf("%10s %10s \n", k.vardas,

x.salis);
y.salis);
z.salis);
k.salis);

vykdius program ekrane matysime:


(null)
Nemunas
Merkys
Nilas

(null)
(null)
Lietuva
(null)

61

4 skyrius. Klass apibrimas.


Objektas
C++ kalboje struktra, jungianti savyje kintamuosius, skirtus duomenims
saugoti, ir funkcijas, kurios naudoja tik tuos kintamuosius, vadinama
klase.
Kintamieji vadinami duomenimis, o funkcijos metodais. Objektiniame
programavime priimta, kad duomenimis tiesiogiai gali naudotis tik tos
klass metodai.
Klass aprao struktra:
class <Klass Vardas> { <Duomen elementai>
public: <Metodai>
};

Klasje duomenys ir metodai gali bti raomi bet kokia seka. Klass
elementai (duomenys ir metodai) gali turti poymius. Poymis klasje
galioja tol, kol bus sutiktas kito poymio uraas. Jeigu poymio urao
nra, tuomet pagal nutyljim bus priimtas private visiems elementams
iki pirmojo poymio urao, jeigu jis bus. Yra tokie poymiai:

private (lokalusis). Elementai prieinami tik klass viduje.

public (globalusis). Klass elementai prieinami jos iorje.

protected (apsaugotasis). Klass elementai prienami klasje, kuri


paveldi duotj klas. ia jie galioja private teismis.

Programavimo technologijos poiriu reikt laikytis tam tikros tvarkos.


Rekomenduojama pradioje surayti duomenis, po to metodus. Metod
srae taip pat reikalinga tvarka. Pirmuoju srae turt bti klass
konstruktorius. Tai metodas, skirtas klass objekto pradini duomen
reikmms nurodyti. Jo vardas privalo sutapti su klass pavadinimu.
Konstruktorius neturi grinamos reikms. Toliau metod srae turi bti
darbo su duomenimis metodai. Gale raomas destruktorius, jeigu toks
yra. Tai metodas, naikinantis objekt. Destruktoriaus vardas turi sutapti su
klass vardu, kurio pradioje paraomas simbolis ~. Pavyzdiui:
62

class Katinas {
public
Katinas() { }

~Katinas() { }

// Konstruktorius
// Destruktorius

Konstruktorius ir destruktorius privalo bti public.


Konstruktorius, kuris neturi parametr, ikvieiamas darbui pagal
nutyljim. Galima parayti:
Katinas A;

// vietoje Katinas A();

Destruktorius skirtas tos klass objektui naikinti kompiuterio atmintyje.


Jeigu jo nra, objektas naikinamas baigus vykdyti program. Programos
darbo eigoje kreipinys destruktori naikina objekt. Jeigu objekto
duomen laukai gauna atmint dinamikai, tuomet btina destruktoriuje
parayti veiksmus, kuriais atsisakoma atminties, skirtos duomen laukams.
Destruktoriai, kaip ir konstruktoriai, negrina jokios reikms. Jeigu klas
turi destruktori, bet nra kreipinio j, tuomet, pagrindinei funkcijai
baigus darb, jis yra vykdomas pagal nutyljim.
Metodai klasje gali bti pilnai aprayti. Tokius metod apraus tikslinga
turti, jeigu j tekstas yra trumpas. Kit metod apraai ikeliami u klass
rib. Tuomet klasje raomas tik metodo prototipas. Metodo aprao klass
iorje struktra:
<Grinamos reikms tipas> <Klass Vardas>::
<Metodo vardas> (<Parametr sraas>)
{ <Programos tekstas> }

Klass tipo kintamieji vadinami objektais. J apraymas analogikas kit


tip kintamj apraams. Sukuriami objektai gali bti statiniai, dinaminiai.
Galima turti objekt masyvus. Objektai gali bti dinamini sra
elementais.
4.1 pratimas. Sukuriama klas, apraanti vieno studento savyb svor.
Klasje yra du metodai: duomen skaitymo klaviatra ir duomen
rodymo ekrane. Pagrindinje funkcijoje sukuriami du objektai.
Duomenys vedami panaudojant metod Skaito, o parodomi ekrane
panaudojant metod Rodo. Metodai klasje apraomi kaip public,
nes juos naudojame klass iorje.
#include <iostream.h>
#include <conio.h>

// vedimo/ivedimo priemons
// Ryio su ekranu priemons

63

//
Klass apraymas
class Studentas {
char *pav;
float svoris;
public:
void Skaito() {
// Metodas
cout << "Iveskite pavarde: \n";
cin >> pav;
cout << "Iveskite svori:\n";
cin >> svoris; };
void Rodo() {
// Metodas
cout << pav << " " << svoris << endl; };
};
//
Pagrindin programa
void main() {
Studentas A, B;
// Sukuriami objektai
A.Skaito();
B.Skaito();
B.Rodo();
A.Rodo();
}

4.2 pratimas. Sukuriama klas studentas, kuri turi du duomen laukus,


skirtus saugoti pavardei ir svoriui. Konstruktorius studentas
suteikia pradines reikmes duomen laukams. Reikms nurodomos
objekto sukrimo metu. Konstruktoriaus ir metodo Rodo apraai
ikelti u klass rib. Metodas Rodo iveda ekrane studento pavard ir
svor. terpiami metodai RodoVarda ir RodoSvori skirti gauti
informacij apie duomen laukuose saugom pavard ir svor.
Metodas Duomenys skirtas nauj duomen perdavimui objekt.
Vidini metod informacijai apdoroti klasje nra. Klass objektai
skiriami tik duomen registracijai.
#include <stdio.h>
#include <stdlib.h>
#include <iostream.h>
#include <conio.h>
//
Klass apraymas
class student {
char *vardas;
float svoris;
public:

64

student(char *, float);
void Rodo();
char *RodoVarda() { return vardas; }
float RodoSvori() { return svoris; }
void Duomenys(char *a, float b)
{ vardas = a;
svoris = b; }

//
//
//
//
//

Konstruktorius
Metodas
Metodas
Metodas
Metodas

};
//
Pagrindin programa
void main() {
clrscr();
student X("Petraitis", 13.5); // Objektas X
student Y(" ", 0);
// Objektas Y
X.Rodo();
// Objekto X duomenys
cout << "Objekto student X duomenys \n";
cout << X.RodoVarda() << " : "<< X.RodoSvori();
cout << endl;
// Duomen persiuntimas kitam objektui, t.y. Y = X
Y.Duomenys(X.RodoVarda(), X.RodoSvori());
Y.Rodo();
// Objekto Y duomenys

}
//
Metod apraai
student::student(char *a, float b)
{ vardas = a; svoris = b; }
void student::Rodo()
{ cout << vardas << " : " << svoris << endl; }

vykdius program ekrane matysime:


Petraitis : 13.5
Objekto student X duomenys
Petraitis : 13.5
Petraitis : 13.5

4.3 pratimas. Sukuriama klas darbui su skaiiais masyve. Numatyti


veiksmai: papildyti sra nauja reikme, paalinti nurodyt reikm ir
perirti ekrane turimus srao skaiius. Klas nagrinti ir panaudoti
paprasiau, kai metod apraai pateikiami atskirai. Metod apraus
siloma rayti tuoj po klasi (arba kiekvienos klass) apra.
#include <iostream.h>
#include <conio.h>
const dydis = 50;

65

//
Klass apraymas
class sar {
int A[dydis];
int ilg;
public:
void sar();
// Konstruktorius
void add(int);
// Srao papildymo metodas
void del(int);
// Reikms alinimo metodas
void get();
// Srao rodymo ekrane metodas
};
//
Metod apraai
void sar::sar() { ilg = 0; }
// Konstruktorius
void sar::add(int naujas) {
// Papildymo metodas
if (ilg == dydis) {
// Sraas papildomas, jeigu srae dar nebuvo
cout << "sarasas pilnas";
return; }
for(int i=0; i<ilg; i++)
if (A[i] == naujas) return;
A[ilg++] = naujas; }
void sar::del(int elem) {
// alinimo metodas
for(int i=0; i<ilg; i++)
if (A[i] == elem) {
for(int j=i; j<ilg-1; j++) A[j] = A[j+1];
ilg--; } }
void sar::get() {
// Ivedimo ekrane metodas
for(int i=0; i<ilg; i++) cout << A[i] << " ";
cout << endl;
}
//
Pagrindin programa
void main() {
clrscr();
sar Rasa;
// Objekto apraas
Rasa.sar();
// Objektas paruoiamas
Rasa.add(10);
// Srao papildymai
Rasa.add(20);
Rasa.add(30);
Rasa.get();
// Ekrane matome: 10 20 30
Rasa.del(20);
// aliname
Rasa.get();
// Ekrane matome: 10 30
}

66

5 skyrius. vedimo, ivedimo srautai


5.1. Ivedimas ekrane ir vedimas klaviatra
vedimo sraut klas istream ir ivedimo sraut klas ostream
apraytos faile iostream.h. J objektai cin ir cout palaiko klasse
numatytus veiksmus.
Anksiau buvo nagrinjami operatoriai >> ir <<.
Ivedam skaii formatui valdyti buvo panaudotos faile iomanip.h
esanios priemons setw(int) ir setprecission(int).
Klass ostream metodas width(int) skirtas nurodyti ivedamo
sraute duomen laukams. Galioja artimiausiam dydiui. Tai setw
analogas.
5.1 pratimas. Parodomas duomen lauko valdymo metodas.
#include <iostream.h>
#include <conio.h>
main() {
for(int i=2; i<6; i++) {
cout.width(3);
cout << "i=";
cout.width(i);
cout << i << endl; }
}

vykdius program ekrane matysime:


i= 2
i= 3
i=
4
i=
5

Ivedant duomenis nurodytu formatu nepanaudotos pozicijos upildomos


tarpo simboliais. Metodas fill(int) leidia pakeisti upildymo
simbol norimu. Pakeitimas galioja iki naujo nurodymo.
67

5.2 pratimas. Demonstruojamas duomen lauk upildymas simboliais.


#include <iostream.h>
#include <iomanip.h>
#include <conio.h>
main() {
cout.fill('.');
for(int i=2; i<6; i++) {
cout << "i=";
cout.width(i);
cout << i << endl; }
}

vykdius program ekrane matysime:


i=.2
i=..3
i=...4
i=....5

5.3 pratimas. Metodas put skirtas vienam simboliui ivesti ekrane.


#include <iostream.h>
#include <conio.h>
main() {
char zodis[] = "Katinas";
for(int i=0; zodis[i]; i++)
cout.put(zodis[i]);
cout << endl;
}

vykdius program ekrane matysime:


Katinas

5.4 pratimas. Metodas put programose danai vartojamas kartu su funkcija


int toupper(int), kuri maj raid keiia didija. Kiti
simboliai nekinta.
#include <iostream.h>
#include <conio.h>
#include <ctype.h>

68

main() {
char sim;
char zodis[] = "Katinas ir Pele";
for(int i=0; zodis[i]; i++) {
sim = toupper(zodis[i]);
cout.put(sim); }
cout << endl << zodis << endl;
}

vykdius program ekrane matysime:


KATINAS IR PELE
Katinas ir Pele

5.5 pratimas. vedimo klasje metodas get skirtas vieno simbolio vedimui
klaviatra.
#include <iostream.h>
#include <conio.h>
#include <ctype.h>
main() {
char sim;
cout << "Ar dar dirbsite?( T/N ): ";
do {
sim = cin.get();
sim = toupper(sim); }
while((sim != 'T') && (sim != 'N'));
cout << "Jus pasirinkote : " << sim << endl;
}

vykdius program ekrane matysime:


Ar dar dirbsite?( T/N ): t
Jus pasirinkote : T

5.6 pratimas. vedimo klasje metodas getline skirtas vienos eiluts


vedimui klaviatra. Matome, kad paprastai vedama eilut iki pirmojo
tarpo simbolio arba iki galo, jeigu tarpo simbolio nebuvo. Panaudoj
getline metod galima vesti norim simboli skaii: nurodomas
skaiius. Jeigu tiek simboli nebuvo, vedami visi simboliai iki eiluts
galo. vedama eilut visuomet papildoma nuliniu simboliu (eiluts
galas).
69

#include <iostream.h>
#include <conio.h>
#include <ctype.h>
main() {
char A[30];
int n;
cout << "Iveskite eilute:\n";
cin >> A;
// Pirmasis eiluts odis
cout << "Eilute: *" << A << "*\n";
cin.getline(A, 12);
//Vienuolika simboli ir '\0'
cout << "Eilute: *" << A << "*\n";
cin.getline(A, sizeof(A));
// Iki galo arba tiek, kiek telpa
cout << "Eilute: *" << A << "*\n";
n = cin.gcount();
// Eiluts ilgis su nuliniu simboliu
cout << "n= " << n << endl;
}

vykdius program ekrane matysime:


Iveskite eilute:
Rainas Katinas ir Pilka Pele
Eilute: *Rainas*
Eilute: * Katinas ir*
Eilute: * Pilka Pele*
n=12

5.7 pratimas. vedimo klasje metodas getline gali turti trei parametr,
nurodant simbol, kuriuo baigiamas vedimas. Pavyzdyje parayta
raid Z. Jeigu vedamoje eilutje jos nebus, tuomet bus vedami visi
eiluts simboliai arba tik tiek, kiek nurodyta, jeigu eilutje j yra
daugiau.
#include <iostream.h>
#include <conio.h>
#include <ctype.h>
main() {
char A[30];
cout << "Iveskite eilute:\n";
cin.getline(A, sizeof(A), 'Z');
cout << "Eilute: *" << A << "*\n";
}

70

5.2. vedimas i failo ir ivedimas fail


vedimo srautu i failo klas ifstream ir ivedimo srautu fail klas
ofstream apraytos faile fstream.h. Galima sukurti objektus, kurie
nukreipia vedimo\ivedimo srautus i\ failus. Jiems atitinkamai galioja
operatoriai >> ir <<. Konstruktoriaus parametru yra failo vardas. ia yra
metodai, kuriuos turi jau nagrintos sraut klass. Failo udarymui yra
metodas close().
5.8 pratimas. Duomen faile Duom58.txt yra skaiius 15. Rezultat faile
Rez58.txt rasime skaii 15.
#include <iostream.h>
#include <fstream.h>
#include <conio.h>
main() {
ofstream R("Rez58.txt");
ifstream D("Duom58.txt");
int A;
D >> A;
cout << " A= " << A << endl;
R << A;
}

vykdius program ekrane matysime:


A= 15

Rezultat faile bus:


15

5.9 pratimas. Duomen failo Duom59.txt perraymas eilutmis nauj


fail Rez59.txt.Taip programikai gaunama failo kopija.
Metodas eof skirtas failo pabaigai nustatyti: grina reikm 0, kai
failo pabaiga dar nepasiekta, ir 1, kai jau turime failo pabaig.
#include <iostream.h>
#include <fstream.h>
#include <conio.h>
main() {
ofstream R("Rez59.txt");

71

ifstream D("Duom59.txt");
char A[80];
while(!D.eof()) {
D.getline(A, sizeof(A));
cout << A << endl;
R << A << endl; }
}

vykdius program duomen ir rezultat failuose matysime:


Batuotas Katinas
pagavo gauruota peliuka.
Tupi sarka kamine.

5.10 pratimas. Duomen failo Duom510.txt perraymas odiais nauj


fail Rez510.txt. Ankstesnje programoje pakeitus skaitymo i
failo metod operatoriumi >>, gausime rezultat faile atskirus duoto
teksto odius.
#include <iostream.h>
#include <fstream.h>
#include <conio.h>
main() {
ofstream R("Rez510.txt");
ifstream D("Duom510.txt");
char A[80];
while(!D.eof()) {
D >> A;
cout << A << endl;
R << A << endl; }
}

vykdius program duomen faile, rezultat faile ir ekrane matysime:


Batuotas
Katinas
pagavo
gauruota
peliuka.
Tupi
sarka
kamine.

72

5.11 pratimas. Duomen failo perraymas simboliais nauj fail


Rez511.txt ir ekran. Ankstesnje 5.9 pratimo programoje
pakeitus skaitymo i failo metod get, gausime rezultat faile ir
ekrane duomen failo kopij.
#include <iostream.h>
#include <fstream.h>
#include <conio.h>
main() {
ofstream R("Rez511.txt");
ifstream D("Duom511.txt");
char sim;
while(!D.eof()) {
sim = D.get();
cout << sim;
R << sim; }
D.close();
R.close();
}

Dirbant su duomen failais reikia patikrinti ar failas buvo surastas ir


skmingai atidarytas. Kiekvienu skaitymo i failo ingsniu btina
patikrinti, ar veiksmas buvo skmingai atliktas. Tam skirtas metodas
fail(), kurio rezultatas yra 0, kai klaid nebuvo, ir 1, kuomet vyko
trikis. Klaid praneimams ekrane skirtas ivedimo srautu objektas cerr.
Metodas fail() naudojamas ivedime, norint sitikinti, ar veiksmas
buvo skmingas (buvo vietos naujam raui).
5.12 pratimas. Duomen failo Duom512.txt.skaiiai perraomi nauj
fail Rez512.txt.
#include <iostream.h>
#include <fstream.h>
#include <conio.h>
main(){
ofstream R("Rez512.txt");
ifstream D("Duom512.txt");
int a;
if (D.fail()) cerr << "Neatidarytas duomenu failas";
else {
while((!D.eof()) && (!D.fail())) {

73

D >> a;
if(!D.fail()) {
R << a << endl;
cout << a << endl; }
} }
D.close();
R.close();
}
"Duom.dat"
15 12
45 -56
15 89

"Rez13.rez"
3

15
12
45
-56
3
15
89

5.13 pratimas. iose klasse yra write ir read metodai, skirti duomen
mainams su failais bait lygyje. Programa urao faile duot struktr,
o po to perskaito ir parodo ekrane. Metoduose uraas (char *)
nusako kompiliatoriui, kad bus naudojama rodykl skirtingus tipus.
#include <iostream.h>
#include <fstream.h>
#include <conio.h>
struct Studentas{ char pav[20];
int
metai;
float ugis; };
main() {
Studentas A;
Studentas S = {"Petriukas ", 21, 187.5};
ofstream R("Rez513.txt");
R.write((char *) &S, sizeof(Studentas));
R.close();
ifstream D("Rez513.txt");
D.read((char *) &A, sizeof(Studentas));
cout << A.pav << A.metai << " " << A.ugis << endl;
D.close();
}

74

5.14 pratimas. Analogikai galima sukurti baitin fail struktriniams


duomenims i tekstinio failo saugoti. Programa demonstruoja duomen
failo Duom514.txt perraym fail Rez514.txt ir po to
skaitym i jo ir duomen raym ekrane.
#include <iostream.h>
#include <fstream.h>
#include <conio.h>
struct Studentas{ char pav[20];
int
metai;
float ugis; };
main() {
char sim;
Studentas A;
ofstream R("Rez514.txt");
ifstream D("Duom514.txt");
while(!D.eof()) {
// Skaitomi duomenys
D.getline(A.pav, sizeof(A.pav));
D >> A.metai >> A.ugis;
sim = ' ';
// Eiluts pabaiga
while((!D.eof()) && (sim != '\n'))
{ sim = D.get(); cout << sim; }
// Duomenys ekrane
cout << A.pav << " " << A.metai << " " << A.ugis;
cout << endl;
// Duomenys faile
R.write((char *) &A, sizeof(Studentas)); }
D.close();
R.close();
// Skaitomi failo duomenys ir parodomi ekrane
ifstream C("Rez15.txt");
while(!C.eof()) {
C.read((char *) &A, sizeof(Studentas));
if (!C.fail())
cout << A.pav << A.metai << " " << A.ugis;
cout << endl; }
C.close();
}

75

Duomen failas:
Katinas Batuotas
Rapolas Didysis
Barbora Bulvyte

76

45
15
25

12.5
159.98
199.45

6 skyrius. Klasi savybs. Objektikai


orientuotas programavimas
6.1. Paveldjimas
Objektiniame programavime viena svarbiausi savybi, apibriani
objekt sveik, yra paveldjimas.
class A
class B

Klas B, kuri paveldi klas A, vadinama protviu (bazin klas). Klas A,


kuri alia savo duomen ir metod paveldi kit klas B, vadinama
palikuonimi (ivestin klas). Protvio duomenys ir metodai paveldimi
kaip private, t.y. juos gali naudoti tik palikuonio metodai. Jeigu norima
tiesiogiai kreiptis i iors protvio metodus, reikia nurodyti paveldjimo
atribut public.
6.1 pratimas. Sukuriama klas Langas, skirta tekstinio ekraninio lango
parametrams saugoti ir langui ekrane formuoti. Sukuriama klas
Trys, skirta duomenims saugoti, keisti ir demonstruoti ekraniniame
lange. i klas paveldi klas Langas. Jos metodai naudojami tik savo
klass viduje.
#include <iostream.h>
#include <conio.h>
#include <stdio.h>
//
Klas Langas
class Langas { int x1, y1, x2, y2; // Lango koordinats
int fonas;
// ir fono spalva
public:
Langas(int, int, int, int, int);
void Ekranas();
};

77

//
Klass Langas metodai
Langas::Langas(int xv, int yv, int xa, int ya,
int spalva)
{ x1 = xv; y1 = yv; x2 = xa; y2 = ya; fonas = spalva;}
void Langas::Ekranas() {
window(x1, y1, x2, y2);
textbackground(fonas);
clrscr();
}
//
Klas Trys
class Trys: Langas { int
a;
float b;
char c;
public:
trys(int, float, char, int, int, int, int, int);
void add (int
k) { a += k; }
// Didina a
void addf(float k) { b += k; }
// Didina b
void addc(char k) { c += k; }
// Didina c
void Rodo();
// Rodo ekrane
};
//
Klass Trys metodai
Trys::trys(int r1, float r2, char r3,
int xv, int yv, int xa, int ya, int spalva):
Langas(xv, yv, xa, ya, spalva) {
a = r1; b = r2; c = r3;
Ekranas();
}
void Trys::Rodo() {
cprintf("Grazu:");
cprintf(" %5i %5.2f %3c \r\n", a, b, c);
}
//
Pagrindin programa
main() {
int Spalva = 2;
window(1, 1, 80, 25);
textbackground(BLACK);
clrscr();
Trys A(5, 2.5, 'b', 10, 10, 50, 15, BROWN);
textcolor(Spalva++);
textcolor(Spalva++);

78

A.Rodo();
A.Rodo();

A.add (10 );
A.addf(25.3);

textcolor(Spalva++);
textcolor(Spalva++);
getch();

A.Rodo();
A.Rodo();

A.addc(3

);

vykdius program ekrane rudo fono lange matysime:


Grazu:
Grazu:
Grazu:
Grazu:

5
15
15
15

2.50
2.50
27.80
27.80

b
b
b
e

alia spalva
ydra spalva
Raudona spalva
Violetine spalva

6.2 pratimas. Sukuriama klas Pirmas, kuri paveldi antroji klas Antras.
Pagrindinje funkcijoje sukuriami kiekvienos klass objektai.
Demonstruojamas kreipinys protvio klass metod. Kad galima bt
taip kreiptis, btina nurodyti paveldjimo atribut public.
Konstruktoriuje Antras kreipinys konstruktori Pirmas raomas
tuoj po antrats. Jis paveldimam laukui x suteikia reikm 5.
#include <iostream.h>
// Paveldimo metodo panaudojimas
#include <conio.h>
// pagrindinje funkcijoje
//
Klas Pirmas
class Pirmas { int x;
public:
Pirmas(int a) { x = a; }
void Rodo()
{ cprintf("Pirmas::rodo() %5d \n\r", x); }
};
//
Klas Antras
class Antras: public Pirmas { int y;
public:
Antras(int b):Pirmas(5) { y = b; }
void Rodo(){
cprintf("Antras::rodo() %5d \n\r", y); }
};
//
Pagrindin programa
void main() {
window(1, 1, 80, 25);
textbackground(BLACK);
clrscr();
window(10, 10, 40, 18);
textbackground(GREEN);
clrscr();

79

window(13, 12, 37, 16);


textcolor( BLACK );
Pirmas A(10);
A.Rodo();
Antras B(25);
B.Rodo();
B.Pirmas::Rodo();
getch();
}

vykdius program ekrane alios spalvos lange matysime:


Pirmas::rodo()
Antras::rodo()
Pirmas::rodo()

10
25
5

6.3 pratimas. Demonstruojamas hierarchinis klasi paveldjimas. Sukuriamos


trys klass: ymeklio valdymo Vieta, raids raymo ekrane
nurodytoje vietoje nurodyta spalva Raide ir odio raymo ekrane po
vien raid Zodis. Klas Vieta ymeklio nevaldo. Ji skirta
ymeklio koordinatms saugoti ir keisti.
#include <iostream.h>
#include <conio.h>
#include <stdio.h>
#include <string.h>
//
Klas Vieta
class Vieta { int x, y;
public:
Vieta(int Xs, int Ys) { x = Xs; y = Ys; }
int KoksX() { return x; }
int KoksY() { return y; }
void Kitas(int Xs, int Ys) { x = Xs; y = Ys; }
};
//
Klas Raid
class Raide: Vieta { int spalva;
char sim;
public:
Raide(int Xp, int Yp,int Sp, char Simb):
Vieta(Xp, Yp) { spalva = Sp; sim = Simb; }
void Kita(int a, int b, int c, char s) {
Kitas(KoksX()+a, KoksY()+b);
spalva +=c ;

80

sim =s;
}
void Rodo() {
textcolor(spalva);
gotoxy(KoksX(), KoksY());
cprintf("%c", sim );
} };
//
Klas Zodis
class Zodis: Raide { char Zd[];
public:
Zodis(char A[]):Raide(1, 1, 1, 'A')
{ strcpy (Zd, A); }
void Spausd();
};
void Zodis::Spausd() {
int i = 0;
while(Zd[i] != '\0') {
Kita(1, 1, 1, Zd[i]);
Rodo();
i++; }
}
//
Pagrindin programa
void main(){
window(1, 1, 80, 25);
textbackground(BLACK);
clrscr();
Raide A(10, 2, RED, 'G');
A.Rodo();
A.Kita(2, 1, 1, 'R');
A.Rodo();
Zodis B("Kaunas\0");
B.Spausd();
getch();
}

vykdius program ekrane skirtingomis spalvomis matysime:


K
a
u
n
a
s

G
R

81

6.4 pratimas. Demonstruojamas paveldimo metodo panaudojimas. Klas


Zodis turi metod Rodo. Klas Raide taip pat turi metod Rodo,
kuri paveldi Zodis.
Sukurtas objektas Zodis B;
B.Rodo(); kreipinys savo klass objekt, o
B.Raide::Rodo(); kreipinys paveldtos klass objekt.
Klas Zodis turi paveldti klas Raide su nuoroda public.
#include <iostream.h>
#include <conio.h>
#include <stdio.h>
#include <string.h>
//
Klas Vieta
class Vieta { int x, y;
public:
Vieta(int Xs, int Ys) { x = Xs; y = Ys; }
int KoksX() { return x; }
int KoksY() { return y; }
void Kitas(int Xs, int Ys) { x = Xs; y = Ys; }
};
//
Klas Raide
class Raide: Vieta { int spalva;
char sim;
public:
Raide(int Xp, int Yp, int Sp, char Simb): Vieta(Xp, Yp)
{ spalva = Sp; sim = Simb; }
void Kita(int a, int b, int c, char s) {
Kitas(KoksX()+a, KoksY()+b);
spalva +=c ;
sim =s;
}
void Rodo() {
textcolor(spalva);
gotoxy(KoksX(), KoksY());
cprintf("%c", sim);
} };
//
Klas Zodis
class Zodis: public Raide { char *Zd;
public:
Zodis(char *A):Raide(1, 1, 1, 'A')
{ Zd = A ; }
void Rodo();
};

82

//
Zodis metodai
void Zodis::Rodo() {
// Metodo apraymas
int i =0;
while(*(Zd+i) != '\0') {
Kita(1, 1, 1, *(Zd+i));
Raide::Rodo();
i++; }
}
//
Pagrindin programa
void main() {
char *Vardas ="Lapas";
window(1, 1, 80, 25);
textbackground(BLACK);
clrscr();
Raide A(10, 3, RED, 'G');
A.Rodo();
// Ekrane raid G
A.Kita(2, 2, 1, 'R' );
A.Rodo();
// Ekrane raid R
Zodis B(Vardas);
B.Raide::Rodo();
// Ekrane raid A
B.Rodo();
// Ekrane odio Lapas raids
getch();
}

vykdius program raides ekrane matysime skirtingomis spalvomis:


A
L
a
p
a
s

G
R

6.2. Operatori perdengimas


Programavimo kalbose naudojami operatoriai pasiymi polimorfizmu
(daugiavariantikumu). Kaip pavyzdys gali bti operatorius +, kuris
taikomas tiek int, tiek float tipo kintamiesiems, nors sudties
veiksmai atliekami nevienodai.
Klasse galima naujai apibrti operatorius, t.y. pakeisti j veikim. Toks
naujas operatori perorientavimas yra vadinamas perdengimu

83

(overloading). Operatori apraai nuo funkcij skiriasi vartojamu odiu


operator:
operator <Operatoriaus simbolis>;
Perdengimas draudiamas operatoriams: .

.*

::

?:

6.5 pratimas. Demonstruojamas dviej operatori + ir perkrovimas klass


Katinas objektams. Operatoriumi + bus sudedamos dvi eiluts,
kuri viena yra objekte, o kita nurodoma parametru. Rezultate objekto
eilut pailgja. Kitas operatorius skiriamas nurodyto simbolio vis
pakartojim objekto eilutje alinimui.
#include <iostream.h>
// Operatori perkrovimas
#include <conio.h>
#include <string.h>
const N = 40;
//
Klas Katinas
class Katinas {
public:
Katinas(char *);
// Konstruktorius
void operator + (char *);
void operator - (char );
void Rodo();
~Katinas();
// Destruktorius
private:
char *Vardas;
};
//
Katinas metodai
Katinas::Katinas(char *Vardas) {
Katinas::Vardas = new char[N];
strcpy(Katinas::Vardas, Vardas); }
void Katinas::Rodo()
{ cout << Vardas << endl; }
void Katinas::operator + (char * A)
{ strcat(Vardas, A); }
void Katinas::operator - (char C) {
for(int i=0; *(Vardas+i) != '\0'; ) {
if(*(Vardas + i) == C)
for(int j=i; j<(strlen(Vardas)-1); j++)
*(Vardas + j) = *(Vardas + j+1);

84

} }

i++;

Katinas::~Katinas()
{ delete Vardas; }
//
Pagrindin programa
void main(void) {
Katinas A ("Batuotas ir piktas");
A.Rodo();
A + " Rudas! ";
A.Rodo();
A - 'a';
A.Rodo();
getch();
}

vykdius program ekrane matysime:


Batuotas ir piktas
Batuotas ir piktas Rudas!
Btuots ir pikts Ruds!

6.3. Persidengiantys metodai


Patogi programavimo priemon yra persidengiantys metodai. Gali bti
persidengiantys konstruktoriai. Persidengianios funkcijos turi t pat
vard, taiau gali turti skirtingus parametr sraus. vartojama funkcija
atpastama pagal kreipinyje surayt argument skaii ir j tip.
6.6 pratimas. Demonstruojama klasje Lapas persidengiantys konstruktoriai,
kuri vienas duomen laukams suteikia pradines reikmes, fiksuotas
klass aprayme, o kitas vartotojo nurodytas objekto sukrimo metu.
Yra keturi metodai vardu Suma. Pagal kreipinio argumentus yra
atrenkamas, kur reikia vykdyti. Kreipinyje
A.Suma((float)35.25);
nurodomas argumento tipas. To nereikt daryti, jeigu ia bt
raomas kintamojo vardas.
#include
#include
#include
#include

<iostream.h>
<conio.h>
<string.h>
<stdio.h>

// Metod perdengimas

85

//
Klas Lapas
class Lapas { int x;
float y;
char z;
public:
Lapas(int, float, char );
// Konstruktorius
Lapas() { x = 0; y = 0; z = 'z'; } // Konstruktorius
void Rodo(char *);
void Suma(int
Sk) { x = x + Sk; }
void Suma(float Sk) { y = y + Sk; }
void Suma(char Sk) { z = Sk;
}
void Suma(int A, char B)
{ x = x + 2.0 * A;
z = B + 4; }
};
//
Lapas metodai
Lapas::Lapas(int A, float B, char C)
{ x = A; y = B; z = C; }
void Lapas::Rodo(char *Eilute) {
cout << Eilute << " : ";
cout << " x= " << x << " y= " << y << "
cout << endl;
}
//
Pagrindin programa
void main(void) {
Lapas A;
Lapas B(5, 3.4, 'C');
A.Rodo("Objektas A-1");
B.Rodo("Objektas B-1");
A.Suma(5);
B.Suma('K');
A.Rodo("Objektas A-2");
B.Rodo("Objektas B-2");
A.Suma((float)35.25);
B.Suma(5, 'A');
A.Rodo("Objektas A-3");
B.Rodo("Objektas B-3");
getch();
}

86

z= " << z;

vykdius program ekrane matysime:


Pradinis A
Pradinis B
A pakeistas x
B pakeistas z
A pakeistas y
B pakeistas x ir z

Objektas
Objektas
Objektas
Objektas
Objektas
Objektas

A-1
B-1
A-2
B-2
A-3
B-3

:
:
:
:
:
:

x=
x=
x=
x=
x=
x=

0
5
5
5
5
15

y= 0
z= z
y= 3.4
z= C
y= 0
z= z
y= 3.4
z= K
y= 35.25
z= z
y= 3.4
z= E

6.4. Virtualios funkcijos


Tegul duota protvio klas Lapas ir jos palikuonio klas KnygaPirma.
Paskelbsime
Lapas *p rodykl klass Lapas objekt.
Lapas L1 klass Lapas objektas.
KnygaPirma Kn1 klass KnygaPirma objektas.
C++ egzistuoja taisykl: bet kuris kintamasis, apraytas kaip rodykl
protvio klass objekt, gali bti naudojamas kaip rodykl palikuonio
klas. Ms atveju teisinga
p = &L1;
p = &Kn1;
Su rodykle p galima pasiekti visus objekto Kn1 elementus, kuriuos jis
paveldjo i klass Lapas. Taiau negalima paimti nuosav (private)
klass KnygaPirma element. Jeigu duota rodykl palikuonio klass
objekt, tai jos pagalba negalima pasinaudoti protvio klass elementais.
Be to, reikia vertinti, kad naudojant protvio klass tipo rodykl
palikuonio klass objektui adresuoti, j didinant ar mainant, adresas keisis
protvio klass objekto dydiu.
Virtualios funkcijos leidia atlikti funkcij perkrovim (polimorfizmo
savyb) programos vykdymo metu. Tai protvio klasje su
specifikatoriumi virtual apraytos funkcijos, kurios i naujo apraytos
vienoje (ar keliose) i palikuoni klasi. Funkcij vardai, grinamos
reikms tipai ir argumentai nesikeiia.
Tegul duota iraika p = &L1 ir virtuali funkcija Rodo. Tegul i funkcija
aprayta su specifikatoriumi virtual protvio klasje Lapas ir be
specifikatoriaus
virtual
palikuonio
klasje
KnygaPirma.
87

p->Rodo() irinks protvio klass funkcij. Jei p = &Kn1, tai


p->Rodo() irinks sukurtos klass KnygaPirma funkcij.
Reikalavimai virtualioms funkcijoms:
Virtuali funkcij prototipai protvio ir palikuonio klasse turi sutapti.
Prieingu atveju funkcija bus laikoma perkraunama, o ne virtualia.
Virtuali funkcija turi bti klass komponente (negali turti
specifikatoriaus friend). Destruktorius gali turti specifikatori
virtual, konstruktoriui tas draudiama.

Jei funkcija paskelbta virtualia, tai i savyb ji isaugo visoms j


paveldjusioms klasms. Jei kurioje nors sukurtoje klasje virtuali
funkcija neaprayta (praleista), tai naudojama protvio klass versija.
Jeigu praleidus virtuali funkcij, sukurtoje klasje negalima naudoti
protvio klass funkcijos, tai ji paskelbiama
pure virtual function.
virtual Funkcijos_tipas Funkcijos_vardas (parametrai)=0;
tada visose j paveldjusiose klasse turs bti sava virtualios
funkcijos versija.
Jei kuri nors klas turi nors vien pure funkcij, tai ji vadinama
abstrakia. J galima naudoti tik kaip protvio.

6.7 pratimas. Sukuriama klas Lapas, kurioje metodas Rodo paymimas


virtualiu. Turime dvi palikuonio klases KnygaPirma ir
KnygaAntra. ia taip pat yra tokios funkcijos. Sukuriami objektai ir
parodomas virtuali funkcij vartojimas.
#include <iostream.h>
// Virtuals metodai
#include <conio.h>
//
Klas Lapas
class Lapas {
public:
virtual void Rodo( void )
{ cout << " Klases Lapas versija \n"; }
};
//
Klas KnygaPirma
class KnygaPirma: public Lapas {
public:
virtual void Rodo(void)
{ cout << " Klases KnygaPirma versija \n"; }
};

88

//
Klas KnygaAntra
class KnygaAntra: public Lapas {
public:
virtual void Rodo(void)
{ cout << " Klases KnygaAntra versija \n"; }
};
//
Pagrindin programa
void main(void) {
Lapas *p, L1;
KnygaPirma Kn1;
KnygaAntra Kn2;
p = &L1;
p->Rodo();
// Vykdomas klass Lapas metodas
p = &Kn1;
p->Rodo();
// Vykdomas klass KnygaPirma metodas
p = &Kn2;
p->Rodo();
// Vykdomas klass KnygaAntra metodas
getch();
}

vykdius program ekrane matysime:


Klases Lapas versija
Klases KnygaPirma versija
Klases KnygaAntra versija

6.8 pratimas. Modifikuotas 6.7 pratimas. Klasje KnygaAntra nra


virtualaus metodo. Sukuriama nauja klas Katinas, kuri yra klass
KnygaPirma palikuonis. ioje klasje yra metodas Rodo, kuris nra
virtualus.
#include <iostream.h>
// Virtuals metodai
#include <conio.h>
//
Klas Lapas
class Lapas {
public :
virtual void Rodo(void)
{ cout << "Klases Lapas versija \n"; }
};
//
Klas KnygaPirma
class KnygaPirma: public Lapas {
public:
virtual void Rodo(void)
{ cout << "Klases KnygaPirma versija \n";
};

89

//
Klas KnygaAntra
class KnygaAntra: public Lapas {
public:
void Matau(void)
{ cout << "Klases KnygaAntra Matau \n"; }
};
//
Klas Katinas
class Katinas: public KnygaPirma {
public:
void Rodo()
{ cout << "Klases Katinas versija \n"; }
};
//
Pagrindin programa
void main(void) {
Lapas *p, L1;
KnygaPirma Kn1;
KnygaAntra Kn2;
Katinas
Cat;
p = &L1;
p->Rodo();
// Vykdomas klass Lapas metodas
cout << "\n";
p = &Kn1;
p->Rodo();
// Vykdomas klass KnygaPirma metodas
p->Lapas::Rodo();
// Vykdomas klass Lapas metodas
Kn1.Rodo();
// Vykdomas klass KnygaPirma metodas
Kn1.Lapas::Rodo();
// Vykdomas klass Lapas metodas
cout << "\n";
p = &Kn2;
p->Rodo();
// Vykdomas klass Lapas metodas
Kn2.Matau();
// p->Matau();
Kreipinys negalimas
cout << "\n";
p = &Cat;
p->Rodo();
// Vykdomas klass Katinas metodas
Cat.Rodo();
// Vykdomas klass Katinas metodas
p->Lapas::Rodo();
// Vykdomas klass Lapas metodas
// p->KnygaPirma::Rodo();
Kreipinys negalimas
Cat.Lapas::Rodo();
// Vykdomas klass Lapas metodas
Cat.KnygaPirma::Rodo();
// Klass KnygaPirma metodas
getch();
}

90

vykdius program ekrane matysime:


Klases Lapas versija
Klases
Klases
Klases
Klases

KnygaPirma versija
Lapas versija
KnygaPirma versija
Lapas versija

Klases Lapas versija


Klases KnygaAntra Matau
Klases
Klases
Klases
Klases
Klases

Katinas versija
Katinas versija
Lapas versija
Lapas versija
KnygaPirma versija

6.9 pratimas. Klasje Lapas apraomas metodas Rodo abstraktus. ios


klass palikuonyse yra savos funkcijos, kurios atliekamos vykdymo
metu.
#include <iostream.h>
// Virtuals metodai
#include <conio.h>
//
Klas Lapas
class Lapas {
public:
virtual void Rodo(void) = 0;
};
//
Klas KnygaPirma
class KnygaPirma: public Lapas {
public:
void Rodo(void)
{ cout << "Klass KnygaPirma versija \n";
};
//
Klas KnygaAntra
class KnygaAntra: public Lapas {
public:
void Rodo(void)
{ cout << "Klass KnygaAntra versija \n";
};
//
Klas Katinas
class Katinas:public KnygaPirma {
public:
void Rodo()

91

{ cout << "Klass Katinas versija \n";


};
//
Pagrindin programa
void main(void) {
Lapas *p;
KnygaPirma Kn1;
KnygaAntra Kn2;
Katinas
Cat;
p = &Kn1;
p->Rodo();
p = &Kn2;
p->Rodo();
p = &Cat;
p->Rodo();
getch();

// Vykdomas klass KnygaPirma metodas


//Vykdomas klass Lapas KnygaAntra metodas
// Vykdomas klass Katinas metodas

vykdius program ekrane matysime:


Klass KnygaPirma versija
Klass KnygaAntra versija
Klass Katinas versija

6.5. Draugikos (friend) klass, funkcijos


Yra galimyb klasms tarpusavyje draugauti, t.y.klas A gali leisti kitai
klasei B naudotis jos priemonmis. Tokiu atveju klasje A yra skelbiama
klas B draugika apraoma su atributu friend. Klasje B raomi
metodai, kurie naudojasi klass A priemonmis kaip savomis. Draugika
klas skelbiama public dalyje.
6.10 pratimas. Klas Knyga skelbia draugika klas Lentyna. Kadangi tos
klass apraas yra toliau, tai jos antrat-prototipas raoma prie klass
Knyga apra. Klasje Lentyna esanios priemons naudoja Knyga
duomenis.
#include <iostream.h>
#include <string.h>
#include <conio.h>
class Lentyna;

92

// Klass antrat

//
Klas Knyga
class Knyga {
public:
Knyga(char *, char *, char *);
// Konstruktorius
void Rodo(void);
// Ivedimas ekrane
friend Lentyna;
// Draugika klas
private:
char pav[64];
char autorius[64];
char leidykla[64];
};
//
Knyga metodai
Knyga::Knyga(char *pav, char *autorius, char *leidykla) {
strcpy(Knyga::pav, pav);
strcpy(Knyga::autorius, autorius);
strcpy(Knyga::leidykla, leidykla);
}
void Knyga::Rodo(void) {
cout << "Pavadinimas: " << pav << endl;
cout << "Autorius: " << autorius << endl;
cout << "Leidykla: " << leidykla << endl;
}
//
Klas Lentyna
class Lentyna {
public:
void Keisti(Knyga *, char *);
char *Rasti(Knyga);
};
//
Lentyna metodai
// Klass Knyga tipo objekte pakeiia leidyklos pavadinim
void Lentyna::Keisti(Knyga * Kn, char * Leid)
{ strcpy(Kn->leidykla, Leid ); }
// Praneamas klass Knyga tipo objekto leidyklos pavadinimas
char *Lentyna::Rasti(Knyga Kn) {
static char vardas[64];
strcpy(vardas, Kn.leidykla);
return(vardas);
}
//
Pagrindin programa
void main(void) {
Knyga K("Informatika I dalis",

93

" J.Adomavicius ir kt.", "KTU");


Lentyna L;
K.Rodo();
L.Keisti(&K, "Technologija");
K.Rodo();
getch();
}

vykdius program ekrane matysime:


Pavadinimas: Informatika I
Autorius: J.Adomavicius ir
Leidykla: KTU
Pavadinimas: Informatika I
Autorius: J.Adomavicius ir
Leidykla: Technologija

dalis
kt.
dalis
kt.

Funkcijai, nepriklausaniai jokiai klasei, gali bti suteiktas draugikos


titulas. Ta funkcija gyja teis naudotis klass duomenimis ir metodais.
Tose klasse, kurios t funkcij kvieia bti draugika, raomas funkcijos
prototipas su atributu friend.
6.11 pratimas. Funkcija Lygu skelbiama draugika dviejose klasse: Point
ir Circle. Funkcija palygina skirting klasi objekt naudojamas
spalvas ir pranea ekrane, ar jos lygios, ar nelygios.
Klas Vieta skirta saugoti ymeklio vietos ekrane koordinatms.
Konstruktorius Vieta apibria sukurto objekto pradin pozicij.
Metodas set skirtas keisti koordinatms, o getX ir getY
koordinatms spausdinti ekrane.
Klas Point paveldi klas Vieta ir turi duomen lauk spalvos
kodui saugoti. Konstruktorius formuoja tako vietos ekrane
koordinates ir spalv. Metodas PutPoint padeda tak grafiniame
ekrane. Klasje skelbiama funkcija Lygu.
Klas Circle paveldi klas Vieta ir turi duomen laukus
apskritimo spalvos kodui bei spinduliui saugoti ir papildom darbui.
Konstruktorius formuoja apskritimo centro koordinai, spindulio ir
spalvos pradines reikmes. Metodas PutCircle bria apskritim
grafiniame ekrane. Klasje skelbiama funkcija Lygu.
#include <iostream.h>
#include <graphics.h>
#include <conio.h>

94

#include <stdio.h>
#include <stdlib.h>
class Circle;
//
Klas Vieta
class Vieta {
protected: int x, y;
public:
Vieta(int Xp, int Yp) { x = Xp; y = Yp; }
void set(int a, int b) { x = a;
y = b; }
int getX() { cout << "x= " << x << endl; return x; }
int getY() { cout << "y= " << y << endl; return y; }
};
//
Klas Point
class Point: public Vieta { int Spalva;
public:
Point(int Xp, int Yp, int Cp);
void PutPoint() { putpixel(x, y, Spalva); }
friend void Lygu(Point p, Circle c);
};
//
Klas Circle
class Circle: public Vieta{ int Spalva, T, R;
public:
Circle(int Xp, int Yp, int Cp, int Rp);
void PutCircle() {
T = getcolor();
setcolor(Spalva);
circle(x, y, R);
setcolor(T);
}
friend void Lygu(Point p, Circle c);
};
//
Metodai
Point::Point(int Xp, int Yp, int Cp): Vieta( Xp, Yp )
{ Spalva = Cp; }
Circle::Circle(int Xp, int Yp, int Cp, int Rp):
Vieta(Xp, Yp)
{ Spalva = Cp; R = Rp; }
void Lygu(Point p, Circle c) {
if (p.Spalva == c.Spalva)
cout << "Spalvos sutampa\n";
else cout << " Skirtingos spalvos \n";
}

95

//
void Grafika();
void main(){
Grafika();

Pagrindin programa

// Ekranas paruoiamas darbui grafiniame rime

Point Taskas(200, 100, 3);


Circle C1 (400, 200, 3, 100);
Circle C2 (200, 200, 1, 50 );
Taskas.PutPoint();
C1.PutCircle();
C2.PutCircle();

// Ekrane padedamas takas


// Ekrane briamas apskritimas
// Ekrane briamas apskritimas

Lygu(Taskas, C1);
Lygu(Taskas, C2);

// Praneama, kad spalvos lygios


// Praneama, kad spalvos skirtingos

getch();
closegraph();

}
//
Grafinio ekrano paruoimas
void Grafika() {
int A = DETECT, B;
initgraph(&A, &B, "c:\\");
if (graphresult() != grOk) {
printf("Klaida: %i %i\n ", A, B);
exit(1);}
}

Galima kitos klass metodus skelbti draugikais savo klasje ir leisti jiems
naudotis duomen laukais. Tam reikia klasje A parayti su atributu
friend klass B metod (funkcij) prototipus.
6.12 pratimas. Turime klas Kitoks, kurioje yra trys metodai, skirti darbui
su kitos klass duomen laukais: keisti apskritimo vietai ekrane,
spindulio reikmei ir spalvai. Klasje Circle tie metodai skelbiami
draugikais. Pagrindinje funkcijoje sukuriami du klass Circle
objektai C1 ir C2. Nubriamas ydras apskritimas C1 duomenimis.
Sukurtas klass Kitoks objektas CC pakeiia objekto C1 visus
duomenis. Nubriamas raudonas apskritimas. Pakeiiamas C1
spindulys ir nubriamas raudonas maesnio spindulio apskritimas

96

(gauname du raudonus koncentrikus apskritimus). Toliau tas pat


padaroma su C2 apskritimu: du koncentriki violetiniai apskritimai.
#include
#include
#include
#include
#include

<iostream.h>
<graphics.h>
<conio.h>
<stdio.h>
<stdlib.h>

class Circle;
//
Klas Kitoks
class Kitoks {
public:
void Dydis(Circle *, int);
void Vieta(Circle *, int, int);
void Spalva(Circle *, int);
};
//
Klas Circle
class Circle { int Spalva, T, R, x, y;
public:
Circle(int Xp, int Yp, int Cp, int Rp);
void PutCircle() {
T = getcolor();
setcolor(Spalva);
circle(x, y, R);
setcolor(T); }
friend void Kitoks::Dydis(Circle *, int);
friend void Kitoks::Vieta(Circle *, int, int);
friend void Kitoks::Spalva(Circle *, int);
};
//
Metodai
Circle::Circle(int Xp, int Yp, int Cp, int Rp)
{ Spalva = Cp; R = Rp; x = Xp; y = Yp; }
void Kitoks::Dydis(Circle *CC, int D) { CC->R = D; }
void Kitoks::Vieta(Circle *CC, int Nx, int Ny)
{ CC->x = Nx; CC->y = Ny; }
void Kitoks::Spalva(Circle *CC, int S)
{ CC->Spalva = S; };
//
Pagrindin programa
void Grafika();

97

void main(){
Grafika();

// Grafinio ekrano paruoimas

Circle C1(400, 200, 3, 100);


Circle C2(300, 300, 5, 50 );

// Briamas C1 ydras apskritimas

C1.PutCircle();
Kitoks CC;

// Objektas C1
// Objektas C2

// Objektas CC darbui su Circle tipo objektas

CC.Vieta(&C1, 100, 100);// Keiiama C1 vieta


CC.Spalva(&C1, RED);
// Keiiama C1 spalva
C1.PutCircle();
// Briamas C1 raudonas apskritimas
CC.Dydis(&C1, 25);
C1.PutCircle();

// Keiiamas C1 spindulys
// Briamas C1 raudonas apskritimas

C2.PutCircle();
CC.Dydis(&CC, 30);
C2.PutCircle();

// Briamas C2 violetinis apskritimas


// Keiiamas spindulys
// Briamas C2 violetinis apskritimas

getch();
closegraph();

}
//
Grafinio ekrano paruoimas
void Grafika() {
int A = DETECT, B;
initgraph(&A, &B, "c:\\");
if(graphresult() != grOk) {
printf("Klaida: %i %i\n ", A, B);
exit(1); }
}

6.6. Dinaminiai objektai


Galima turti rodykles objektus, objekt sraus: masyvus, rodykli,
masyvus, sraines struktras.
Atminties skyrimui patogu naudoti operatori new:
<rodykl> = new <tipas>;

98

Dinamikai skirtos atminties atsisakoma operatoriumi delete arba


funkcija free:
delete <rodykl>;
void free (<rodykl>);
6.13 pratimas. Turime klas Lapas. Sukuriama rodykl p klas Lapas.
Sukuriamas dinaminis objektas, kurio adresas saugomas rodyklje p.
#include <iostream.h>
#include <string.h>
#include <stdlib.h>
//
Klas Lapas
class Lapas { char *L;
public :
Lapas(char * T) { L = T;}
void Kitas(char *K) { strcpy(L, K); }
void Rodo(void) {
if (L) cout << L << " lapas \n";
else cout << "Neturiu lapo\n"; }
};
//
Pagrindin programa
void main(void) {
Lapas *p;
p = new Lapas("Klevo ");
if (!p) { cout << "Truksta atminties\n"; exit( 0 ); }
p->Rodo();
p->Kitas("Liepa");
p->Rodo();
free(p);
}

vykdius program ekrane matysime:


Klevo lapas
Liepa lapas

6.14 pratimas. Turime klas Lapas. Sukuriame rodykli masyv p, kuriame


saugosime rodykles tris objektus klass tipo Lapas. Suformuojamas
rodykli objektus masyvas. Objektai saugo tuias eilutes. Po to
klaviatra suvedami odiai ir patalpinami objekt duomen laukus
L. Programos pabaigoje atspausdinami objekt saugomi odiai ir
objektai paalinami i atminties.

99

#include <iostream.h>
#include <string.h>
#include <stdlib.h>
//
Klas Lapas
class Lapas { char *L;
public :
Lapas() { L = NULL; }
void Kitas(char *K) {
L = new char[10];
strcpy(L, K);
}
void Rodo(void) {
if (L) cout << L << " lapas \n";
else
cout << "Neturiu lapo\n"; }
};
//
Pagrindin programa
void main(void) {
int i;
Lapas *p[3];
char T[10];
for (i=0; i<3; i++) {
//
p[i] = new Lapas();
cout << "*** ";
p[i]->Rodo(); }
cout << "--------------\n";
for (i=0; i<3; i++) {
//
cout << "Iveskite: ";
cin >> T;
cout << endl;
p[i]->Kitas(T);
}
//
for (i=0; i<3; i++) p[i]->Rodo();
for (i=0; i<3; i++) free(p[i]); //
cout << "Pabaiga\n";
}

vykdius program ekrane matysime:


*** Neturiu lapo
*** Neturiu lapo
*** Neturiu lapo
-------------Iveskite: Liepa
Iveskite: Klevas
Iveskite: Maumedis

100

Masyvo sudarymas

Duomen vedimas

Spausdinimas
Naikinimas

Liepa lapas
Klevas lapas
Maumedis lapas
Pabaiga

6.15 pratimas. Turime klas


kurio elementais yra
objekt upildymas
seka, nes sraas
sunaikinimas.

Lapas. Sukuriamas tiesinis dinaminis sraas,


klass Lapas tipo objektai. Parodomas srao
duomenimis, srao spausdinimas (atvirktin
buvo formuojamas pradi) ir srao

#include <iostream.h>
#include <string.h>
#include <stdlib.h>
//
Klas Lapas
class Lapas { char *L;
public :
Lapas() { L = NULL; }
void Kitas(char *K) {
L = new char[10];
strcpy(L, K);
}
void Rodo(void) {
if (L) cout << L << " lapas \n";
else
cout << "Neturiu lapo\n"; }
~Lapas() { free(L); }
};
//
Sraas
struct sar { Lapas *Medis;
sar
*sek;};
//
Pagrindin programa
sar *Naikinti(sar *);
void main(void) {
sar *P = NULL, *R;
int i;
char T[10];
for(i=1; i<=3; i++) {
cout << "\nIveskite: ";
cin>>T;
R = new sar;
R->sek = P;
P = R;
P->Medis = new Lapas();

// Srao formavimas

101

P->Medis->Kitas(T); }
R = P;
// Srao spausdinimas
while(R) {
R->Medis->Rodo();
R = R->sek; }
P = Naikinti(P);
// Srao naikinimas
if (!P) cout << "Sarasas tuscias\n";
cout << "Pabaiga\n";

}
//
Srao naikinimas
sar *Naikinti(sar *P) {
sar *R;
while(P) {
R = P;
P = P->sek;
R->Medis->~Lapas();
free( R ); }
return P;
}

vykdius program ekrane matysime:


Iveskite: Liepa
Iveskite: Klevas
Iveskite: Slyva
Slyva lapas
Klevas lapas
Liepa lapas
Sarasas tuscias
Pabaiga

102

7 skyrius. Tiesiniai vienkrypiai


sraai
7.1. Srao struktra
Sraais vadinami tokie duomen rinkiniai, kuri elementus apibdina ne
tik j reikms, bet ir tvarkymo taisykls, ryiai tarp element. Keiiant
element tipus, ryi tarp element bdus ir tvarkymo taisykles, galima
sudaryti daugyb vairi tip sra (eiles, stekus, dekus, medius), todl
universalios srao tipo struktros sudarymas yra problematikas.
Paprasiausi sraai gali bti realizuojami masyvuose, papildant juos
tvarkymo procedromis ir upildymo charakteristika. Universalesn sra
sudarymo priemon yra dinamins struktros, kurios sudaromos i
element su nuorodomis. Tokiuose elementuose saugomos ne tik j
reikms, bet ir ryio su kitais elementais apraymai:
Reikm

Ryio dalis

Dinamins struktros elemento reikm gali bti bet kokia statin arba
dinamin struktra, o ryio dalyje yra raomos rodykls kitus to paties
srao elementus. Kadangi dinamini struktr element reikms ir
nuorodos yra apraomos skirting tip duomenimis, sra elementai
realizuojami raais, kuri struktra yra tokia:
struct <Vardas> { <Reikms laukai>;
<Ryio dalies laukai>; }

Homogeninse dinaminse struktrose, kuriose visi elementai yra vienodo


tipo, apraant ryio dalies rodykles, reikia nurodyti paios naujai
apraomos struktros tip. Kreipimasis struktros aprayme save pai
vadinamas rekursija, o struktros, kuriose yra tokie kreipiniai, vadinamos
rekursyviomis. Rekursyvios struktros elemento aprao pavyzdys:
struct list {int data;
struct list *next; }

// Rekursyvi nuoroda

I element, kuri ryio dalyje yra viena rodykl, galima sudaryti tik
tiesiniais sraais vadinamas nuosekliai sujungtas grandines. Papildant
103

tiesinius sraus tvarkymo procedromis ir iorinio ryio priemonmis,


galima sudaryti tokias tipines j modifikacijas:
tiesinius sraus, kuriuose nra apribojim srao element analizei,
tvarkymui ir apdorojimui;
eiles, kuriose nauji elementai prijungiami srao gale, o skaitymui yra
prieinamas tik pirmasis elementas (struktra FIFO first in, first out);
stekus, kuriuose galima skaityti tik vliausiai rayt element
(struktra LIFO last in, first out);
dekus, kuriuose elementai gali bti raomi ir skaitomi tiek srao
pradioje, tiek gale (struktra DEQUE double-ended que).
Tokios srains struktros labai plaiai vartojamos ne tik taikomosiose,
bet ir sisteminse programose. Pavyzdiui, stekuose yra saugomi
pertraukiam proces parametrai, organizuojami lokals duomenys. Eils
yra populiari pagalbini (buferini) atmini, kuriose kaupiami i lt
rengini gaunami arba juos siuniami duomenys, organizavimo
priemon.
Kiekvieno srao tipo realizavimui skirta dinamin struktra turi turti jos
elementus apraani struktr, rodykl arba rodykles ioriniams ryiams
skirtus elementus ir tokias tvarkymo operacijas:
naujo srao sukrimo;
naujo elemento prijungimo;
elemento paalinimo;
srao skaitymo ir analizs;
srao tvarkymo.
Sudarant sra tvarkymo procedras, reikalingas papildomas susitarimas
apie tai, kaip bus ymima srao pabaiga ir kaip bus ymimas tuias
sraas. Yra priimta tiek srao pabaig, tiek tui sra dinaminse
struktrose ymti nuline rodykle NULL.

7.2. Tiesinis dinaminis sraas


Ryys su srau palaikomas naudojant rodykl jo pradi. Rekomenduojama srao elemento struktra yra i dviej lauk: duomenims saugoti ir
ryio rodyklei urayti. Tokia struktra supaprastina veiksmus su srao
elementais.

104

Srao elemento struktra gali bti apraoma vienu arba dviem sakiniais:
struct List {
int Sk;
struct List *next;
} *First;

struct List {
int Sk;
struct List *next; };
List *First;

Tiesinio srao grafinis vaizdas parodytas 7.1 pav. ia elementas


vaizduojamas staiakampiu, padalintu tiek dali, kiek yra lauk jo
struktroje: duomen ir adreso. Duomen lauke saugomos reikms.
Rodykls tipo lauke saugomas adresas (nuoroda) kit srao element.
Nuoroda pavaizduota linija su rodykle gale. Tos linijos pradia yra
nuorodos lauko viduje. Rodykl remiasi element vaizduojant
staiakamp bet kurioje vietoje. Jeigu nuoroda neegzistuoja, tuomet linija
nra briama ir laukas lieka tuias. Tai reikia, kad adreso reikm
neapibrta, iukl. Realiose programose tokia situacija yra neleistina.
P

16

58

4
NULL

7.1 pav. Tiesinio srao vaizdavimas

16

58

P
NULL

<16>

<58>

<8>

<4>
NULL

7.2 pav. Nuorodos reikm vaizdavimas

Btina urayti tuio adreso reikm konstant NULL. Grafikai tai gali
bti ymima vairiais sutartiniais enklais, kas leidia konstruoti maesns
apimties paveiksllius. enklai naudojami, kuomet nagrinjamos
struktros nra siejamos su konkreia realizacija (pvz., Turbo Paskalyje
tuio adreso konstanta yra Nil). Sraus suvokti lengviau, kai sutartini
paymjim maiau, todl bus raoma NULL. Be to paveikslliuose bus
105

naudojamas tokio tipo paymjimas: reikm. Tai reik adres viet,


kur saugoma nurodyta reikm, pavyzdiui skaiiaus 16 nuoroda bus
urayta 16 (7.2 pav.).
Tiesinio srao formavimo ir periros iliustracijai panaudosime program
Srao formavimas. ioje programoje yra sukurta klas DinSar,
kurioje yra apraytas kintamasis P (dinaminio srao pradios rodykl),
konstruktorius, destruktorius, bei metodai sraui formuoti ir spausdinti.
Programa naudoja klass DinSar objekt A. Klasje yra keturi metodai:
srao formavimui paraytas metodas Formuoti. Jame yra imami
sveiki skaiiai i failo ir perduodami metodui Elementas, kuris
sukuria dinamin element su ta reikme ir prijungia prie formuojamo
srao pradios (steko formavimo bdas);
srao perirai yra metodas Spausdinti, kuris srao element
reikmes surao ekrane viena eilute;
klass DinSar konstruktorius DinSar sukuria objekt A ir io
objekto srao pradios rodyklei P suteikia reikm NULL, o
destruktorius ~DinSar naikina i atminties sra ir objekt A.
Detaliau veiksmai bus aptariami atskiruose skyreliuose.
//
Srao formavimas (stekas)
#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>
//
Struktros tipo apibrimas
typedef struct list {int sk;
struct list *next; } sar;
//
Klass Dinsar apibrimas
class DinSar {
sar *P;
// Srao pradia
public:
DinSar();
// Konstruktorius
~DinSar();
// Destruktorius
void Formuoti(FILE *);
// Formuoja sra
void Elementas(int);
// Prijungia element
void Spausdinti();
// Spausdina sra
};
//
Pagrindin programa
void main() {
FILE *D;

106

DinSar A;
// Klass DinSar objektas
D = fopen("Duom.dat", "r");
if (D == NULL) {
cout << "Failo 'Duom.dat' nepavyko atidaryti";
exit (1); }
A.Formuoti(D);
// Formuojamas sraas
fclose(D);
A.Spausdinti();
// Spausdinamas sraas
A.~DinSar();

}
//
Konstruktorius
DinSar::DinSar() { P = NULL; }
//
Destruktorius
DinSar::~DinSar() {
sar *D = P;
while(P != NULL) {
D = P;
// Rodykl naikinam element
P = P->next;
// Kito elemento adresas
delete( D ); }
// Elemento naikinimas
}
//
Formuoja netiesiogin sra
void DinSar::Formuoti(FILE *F) {
int k;
while(!feof(F)) {
fscanf(F, "%i", &k);
Elementas(k); }
}
//
Prijungia element
void DinSar::Elementas(int Sk) {
sar *R;
R
= new sar;
// Naujo elemento sukrimas
R->sk
= Sk;
// Upildymas duomenimis
R->next = P;
// Prijungimas prie srao
P
= R;
// Srao pradios pakeitimas
}
//
Srao spausdinimas
void DinSar::Spausdinti() {
sar *D = P;
while(D != NULL) {
cout << D->sk << " ";
// Reikms spausdinimas
D = D->next; }
// Kito elemento adresas
cout << "\n";
}

107

7.3. Tiesinio srao formavimo iliustracija


Srao formavimo esm sudaro nauj element prijungimas prie srao.
Metodo Formuoti vaidmuo yra organizuoti nuosekl duomen skaitym
i failo ir j raym dinamin sra. Metodui Elementas perduodama
nauja reikm k. Metodas Elementas sukuria nauj element, j upildo
duomenimis ir prijungia formuojamo srao pradioje (steko principas),
pakeisdamas srao pradios adres. Srao formavimo fragmentas:
typedef struct list { int sk;
struct list *next; } sar;
//
Formuoja netiesiogin sra
void DinSar::Formuoti(FILE *F) {
int k;
while(!feof(F)) {
fscanf(F, "%i", &k);
Elementas(k); }
}
//
Prijungia element
void DinSar::Elementas(int Sk) {
sar *R;
/*1*/ R
= new sar;
/*2*/ R->sk
= Sk;
/*3*/ R->next = P;
/*4*/ P
= R;
}

NULL

7.3 pav. Rodykls P reikm prie cikl

Metodo Formuoti darbo pradioje formuojamas sraas yra tuias, t.y.


srao pradios rodykls P reikm yra lygi NULL. Jeigu failas bus tuias,
tai tokia reikm ir pasiliks metodui baigus darb. i situacija grafikai
parodyta 7.3 pav.
Tarkime duomen faile Duom.dat yra tokia skaii seka:
18 7 4 9
Pirm kart cikle (7.4 pav.) i failo perskaitoma reikm k = 18. Ji
perduodama metodui Elementas. is metodas sukuria nauj element
108

su ta reikme (1 ir 2 sakiniai), po to jis prijungiamas prie srao pradios


(3 sakinys), o srao pradios rodykl perkeliama prie to naujo elemento
(4 sakinys), t.y. naujasis elementas tampa pirmuoju srae.
Antr kart cikle gauta nauja reikm k = 7 tampa nauju elementu jau
turimo srao pradioje (7.5 pav.).
P

NULL
18

NULL

P
18
R

NULL

Sukuriamas elementas, kurio adres


saugo rodykl R, ir upildomi laukai:
1, 2, ir 3 veiksmai.

Srao pradia yra naujas elementas, kurio


adres saugo rodykl R. Tas adresas yra
uraomas rodyklje P.
4 veiksmas.

7.4 pav. Pirmasis elementas srae

Perklus visus faile esanius skaiius sra, srao pradios rodykl P


rodys srao pradi (saugo pirmojo srao elemento adres).
Suformuoto srao vaizdas parodytas 7.6 pav. Matome, kad suformuotas
sraas saugo failo duomenis prieinga tvarka, nes nauji elementai buvo
prijungiami prie srao pradios.
Pastaba. Veiksmuose su srao elementais srao pradios rodykls P
prarasti negalima, nes tuomet srae esantys duomenys bus neprieinami
(prarasti).
P

18
NULL
7

Pirmuoju veiksmu sukuriamas


naujas elementas, kurio adres saugo
rodykl R.
Antruoju veiksmu raoma reikm
k = 7

109

18
NULL
7
Treiuoju veiksmu naujas elementas
prijungiamas prie srao pradios.

18
NULL
7

Ketvirtuoju veiksmu srao pradios


rodykl perkeliama prie naujo
elemento.

7.5 pav. Antrasis elementas srae

18
NULL

7.6 pav. Suformuotas sraas: faile buvo skaiiai 18 7 4 9

7.4. Tiesinio srao perira


Vienas i daugelio veiksm su srao elementais yra nuosekli j perira
nuo srao pradios iki galo spausdinant duomenis. Tam panaudojama
papildoma rodykl, kurios pradin reikm yra srao pradios rodykls P
saugomas adresas. Toliau nuosekliai darbins rodykls reikm keiiama
kito elemento i srao reikme tol, kol peririmas visas sraas
(7.7 pav.).
void DinSar::Spausdinti() {
sar *D = P;
while(D != NULL) {
cout << D->sk << " ";
D = D->next; }
cout << "\n";

110

// Reikms spausdinimas
// Kito elemento adresas

Turintiems programavimo gdius silomas lakonikesnis funkcijos


uraas:
void DinSar::Spausdinti() {
sar *D = P;
while(D) {
cout << D->sk << " ";
D = D->next; }
cout << "\n";
}

// Reikms spausdinimas
// Kito elemento adresas

Kiekviena programa privalo tvarkyti naudojam atmint taip, kad


nesusidaryt avarini situacij. Vienas i toki veiksm yra
nebereikalingo srao paalinimas i atminties. Pavyzdio programoje tam
skirta destruktorius ~DinSar. ia naudojama papildoma rodykl D
alinamo elemento adresui atsiminti. Sraas nuosekliai peririmas
naudojant jo rodykl P, kuri turi srao pradios adres. Pirmu veiksmu
atsimenamas srao pradios elemento adresas (D = P). Po to srao
pradia yra perkeliama prie tolimesnio elemento (P = P->next;), o
atjungtas nuo srao elementas D yra paalinamas.
9

18
NULL

D
Darbinei rodyklei D suteikiamas srao pradios adresas: D = P;
Galima atspausdinti pirmojo elemento reikm 9: cout << D->sk;

9
P

18
NULL

D
Pereinama prie kito elemento: D = D->next;
Galima atspausdinti elemento reikm 4: cout << D->sk;

111

18
NULL

D
Pereinama prie kito elemento: D = D->next;
Galima atspausdinti elemento reikm 7: cout << D->sk;

18
NULL

D
Pereinama prie kito elemento: D = D->next;
Galima atspausdinti elemento reikm 18: cout << D->sk;

P
D

18
NULL

NULL

Pereinama prie kito elemento: D = D->next;


Papildoma rodykl D gauna paskutinio elemento ryio dalyje esant adres NULL.
i reikm yra srao periros pabaigos poymis.
7.7 pav. Srao element perira

7.5. Tiesinio srao papildymas


Srao papildymas naujais elementais galimas:
srao pradioje;
srao pabaigoje;
srao viduje.
Naujo elemento prijungimas srao pradioje sutampa su srao
formavimo ciklo veiksmais.
Naujo elemento prijungimas srao gale yra tapatus elemento terpimui
srao viduje po nurodyto elemento. Veiksm schema parodyta 7.8 pav. ir
112

7.9 pav. Patikrinkite, ar tikrai tinka tie patys veiksmai, kai R rodo
paskutin srao element (papildymas gale).
9

18
NULL

R
123

NULL

Rodykl R rodo element, po


kurio reikia terpti nauj
element S. Jis suformuotas
pilnai. Adresin dalis turi tuio
adreso reikm.

7.8 pav. Nauj element S reikia terpti u elemento R

18
NULL

R
123

Naujam elementui S suteikiamas


adresas elemento, esanio toliau
u elemento R:
S->next = R->next;
Elemento R rodykl nukreipiama
nauj element: R->next = S;

7.9 pav. Naujo elemento terpimas

Atskiras srao papildymo atvejis yra tada, kai sraas visikai tuias.
Tuomet pakanka srao pradios rodyklei P suteikti naujo elemento
adres:
P = S;

terpimas prie nurodyt element tokio tipo srauose negalimas, nes


elementai susieti rodyklmis viena kryptimi. Galimas tik vienas atvejis:
terpti prie pirmj, kas tolygu sra papildyti pradioje nauju elementu.
terpim prie galima pakeisti terpimu po. Tam reikia surasti
element, esant prie mus dominant. Pavyzdiui, reikia rasti element,
esant prie didiausi:
sar *R,
*R1,
*T,*T1;

// Didiausios reikms elementas


// Elementas, esantis prie didiausi
// Papildomos rodykls srao perirai

113

T1 = P; T = P;
R1 = P;
R = P;
while(T != NULL) {
if(T->sk > R->sk) { R1 = T1; R = T; }
T1 = T;
T = T->next; }

Perirjus sra iki galo, rodykl R rodys element su didiausia


reikme, o rodykl R1 rodys element, esant prie didiausi. Jos abi
rodys pirmj element, kai jo reikm srae didiausia. Tai reikia, kad
veiksmuose su sraais visuomet btina nagrinti visas galimas situacijas.
terpim prie galima atlikti paprasiau. Jeigu darbo su srau veiksmai
neprietarauja element reikmi keitimui vietomis, tuomet siloma tokia
terpimo veiksm seka:

Turime surast element R, prie kur reikia terpti element S;

Sukeiiamos R ir S element reikms (ia int k;):


k = R->sk;
R->sk = S->sk;
S->sk = k;

terpiamas elementas S po elemento R:


S->next = R->next;
R->next = S;

7.6. Tiesinio srao element alinimas


Tai prieingas veiksmas terpimui, todl veiksmai analogiki. alinant
nurodyt element, btina nagrinti jo padt srae. Jeigu tai pradios
elementas, jis paalinamas srao pradios rodykl P perkeliant sekant
element:
P = P->next;
delete(R);

// alinamas elementas R
// yra pirmas, t.y. R = P

Klasikinis elemento paalinimo i srao atvejis yra, kai turime rodykl


alinamj element R ir prie j esant R1 (7.10 pav.).

114

18
NULL

R1

R1->next = R->next

7.10 pav. Elemento paalinimas

alinant elementus btina atlaisvinti atmint, kuri jie uima. Tam


naudojama funkcija delete.
Labiau patyrs programuotojas ras lakonikesni priemoni veiksmams
atlikti. Kaip vien i j galima pasilyti nurodyto elemento R alinimui
(7.11 pav.):
*R = *R->next;
ia yra tolesnio elemento turinio perklimas nurodyt. Tuo sunaikinamas
elemento R turinys. Srae turime du vienodus elementus, kuri tik vienas
prieinamas.
9

18
NULL

R
7.11 pav. Sraas po elemento paalinimo

Pastaba: io veiksmo negalima taikyti, kai R rodo paskutin element, nes


toliau jau nra kit element. iam atvejui btina atskira veiksm grup.
Tokios element alinimo procedros negalima taikyti sudtingose
srainse struktrose, kur duomen element adresai naudojami naujoms
sra sekoms formuoti. Duomenys negali keisti savo pradinio adreso.

7.7. Tiesinio srao element tvarkymas


Tipikiausias srao element tvarkymo bdas yra rikiavimas.
Paprasiausias atvejis yra, kai leidiama keisti elementuose duomenis
vietomis (analogija su masyvais). Toks bdas priimtinas, kai duomen
115

struktra elemente nesudtinga arba duomen apimtis nedidel. Visais


atvejais tikslinga elemente turti tik vien lauk duomenims nurodyti, o
duomen pilna hierarchin struktra yra apraoma atskirai.
void DinSar::Rikiavimas() {
sar *R = P, *R1;
int k;
while(R != NULL) {
R1 = R->next;
while(R1 != NULL) {
if (R1->sk > R->sk) {
k = R->sk;
R->sk = R1->sk;
R1->sk = k; }
R1 = R1->next; }
R = R->next;
}
}

// Reikmi sukeitimas

Programose dana situacija, kai negalima keisti srao element duomenis


vietomis. Reikia sukeisti element sek srae, t.y. keiiamos nuorodos.
Norint sukeisti vietomis srae du elementus, reikia turti rodykles ne tik
keiiamus elementus, bet ir prie juos esanius. ia reiks pasirpinti
keiiam element kaimynais prie ir po (7.12 pav.).

NULL

R1

S1

7.12 pav. R ir S rodo keiiamus vietomis elementus

Reikia sukeisti vietomis elementus R ir S. Tai galima padaryti taip:

R1 elemento kaimynu po padaromas elementas S:


R1->next = S;

S1 elemento kaimynu po turi bti elementas R:


S1->next = R;

Atsimename elemento po R adres:

116

pap = R->next;

Elementas R turi rodyti element po S:


R->next = S->next;

Elementas S turi rodyti element po R:


S->next = pap;

Reikia neumirti patikrinti keiiam element srae padt (pradioje,


gale ar viduje). Gaunama sudtinga veiksm seka. ymiai paprasiau
suformuoti nauj tvarking sra. Tai galima padaryti taip:
rasti duotame srae element pagal duot rikiavimo rakt;
paalinti surast element i duoto srao;
prijungti element prie naujo srao.
void DinSar::Surikiavimas() {
sar *T = P,
// T senojo srao pradia
*D, *D1, *S, *S1;
P = NULL;
// Naujas sraas tuias
while(T) {
D = T;
// Gretimi du elementai srao perirai
D1 = T;
S = T;
S1 = T;
// Didiausias S ir prie j esantis S1
while(D) {
// Didiausio paieka
if (D->sk > S->sk)
{ S = D; S1 = D1; }
D1 = D;
D = D->next; }
if (S == T) T = T->next;
// alinimas
else S1->next = S->next;
S->next = P;
// Prijungimas prie naujo srao
P = S; }
// Naujo srao pradia
}

iame pavyzdyje nebuvo kuriami nauji elementai. Jie buvo sujungiami


nauja seka, pasinaudojant jau inomomis operacijomis. T pat rezultat
galima gauti trumpesniu keliu. Silome panagrinti burbuliuko bdu
rikiuojani funkcij:
void DinSar::RikiavBurb() {
sar **T, *R;

117

int flag = 1;
while(flag) {
flag = 0;
T = &P;
while((*T)->next) {
if ((*T)->sk > (*T)->next->sk) {
R = *T;
*T = R->next;
R->next = (*T)->next;
(*T)->next = R;
flag = 1; }
T = &(*T)->next; } }
}

Tvarkymo ir kiti veiksmai vienkrypiuose srauose yra sudtingi,


reikalauja papildom darbo snaud. ymiai yra patogesni dvikrypiai
sraai, kur kiekvienas elementas turi rodykles kaimynus prie ir po.
Realiai vienkrypiai sraai naudojami su tam tikrais apribojimais: stekai,
eils, dekai.

7.8. Eils formavimas


Visuose pateiktuose pavyzdiuose sraas buvo formuojamas naujus
elementus prijungiant prie pradios, t.y. steko principu. Ne visuomet tai
patogu. Galima sra formuoti j pateikimo eils tvarka (7.13 pav.).
Formavimo procesas skaldomas du etapus:

Pirmojo elemento sukrimas. Rodykls P ir G rodo pirmj element

Kit element prijungimas gale. Reikalinga srao pabaigos rodykl G.


Ji rodo element, po kurio reikia padti nauj element.

Papildykite klas tam skirtais metodais FormuotiEile ir


ElementasEile ir juos ibandykite. Atkreipkite dmes naujo
elemento sukrimo ir prijungimo skirtumus steko ir eils atvejais.
18

P
9

118

NULL

7.13 pav. Eils formavimas


void DinSar::FormuotiEile(FILE *F) {
sar *D = NULL, *G;
int k;
if (!feof(F)) {
fscanf(F, "%i", &k);
ElementasEile(&D, k);
G = D; }
while(!feof(F)) {
fscanf(F, "%i", &k);
ElementasEile(&G, k); }
P = D;

// Pirmas elementas
// Galo rodykl G
// Kiti elementai
// Prijungimas gale

}
void DinSar::ElementasEile(sar **P, int Sk) {
sar *R;
R
= new sar;
// Suformuojamas elementas
R->sk
= Sk;
R->next = NULL;
if (*P) {
// Elementas prijungiamas gale
(*P)->next = R;
*P = R; }
else *P = R;
// arba jis dar pirmas srae
}

7.9. Stek tvarkymas


Stekai yra paprasiausi ir lengviausiai tvarkomi tiesiniai dinaminiai
sraai. Juose nauji elementai terpiami srao pradioje, o vartojimui
prieinamas tik pirmas elementas, kuris po to alinamas. Deklaruojant
stekus, pakanka aprayti j element struktras ir rodykles stek
pradias. Darbui su steku reikalingos dvi funkcijos: naujo elemento
prijungimo prie srao pradios ir pirmojo elemento paalinimo i srao
(prie tai tas elementas yra panaudojamas veiksmuose).
7.1 pratimas. Isiaikinkite pavyzdyje aprayt simboli steko tvarkymo
funkcij sudarymo principus ir patikrinkite demonstracins programos
darb. Programoje simboliai yra atrenkami ir siuniami stek i joje
deklaruotos ir inicializuotos simboli eiluts.
119

//
Veiksmai su steku
#include <iostream.h>
struct stack { char d;
// Steko element tipas
struct stack *next; };
class stekas {
public:
stack *first;
// Steko realizacija (rodykl)
stekas() { first = NULL; }
// Konstruktorius
~stekas() {};
// Destruktorius
stack *Get(){ return first; };
void Push(char);
// Steko papildymas
void Ekranas(stack *);
// Steko perira
char Pop();
// Steko skaitymas
};
//
Pagrindin programa
main() {
// Tvarkoma eilut ir rodykl j
char prad[] = "abcdefgh", *p = prad;
stack *d;
// Darbinis kintamasis
stekas A;
// Objekto apraymas
// Tvarkomos eiluts parodymas ekrane
cout << "Siunciami i steka simboliai: " << p << endl;
while(*p) A.Push(*p++);
// Steko upildymas
cout << "Steko patikrinimas:\n";
d = A.Get();
A.Ekranas(d);
// Steko turinio "abcdefgh" parodymas
cout << "Skaitymas po viena simboli:\n";
while(A.first) cout << A.Pop() << endl;
// Steko ivalymo kontrol
if (!A.first) cout << "Tuscias stekas\n";
A.~stekas();

}
//
Steko papildymas
void stekas::Push(char e) {
stack *newe;
newe
= new stack;
// Atminties skyrimas
newe->d = e;
// Naujo elemento reikm
newe->next = first;
// Senos steko dalies prijungimas
first = newe;
// Naujas steko adresas
}

120

//
Rekursyvus steko turinio patikrinimas
void stekas::Ekranas(stack *p) {
if (p) {
// Rekursijos nutraukimo slyga
cout << p->d;
// Reikms parodymas ekrane
Ekranas(p->next);} // Rekursyvus kreipinys tolimesn element
else cout << endl;
}
//
Elemento paalinimas i steko
char stekas::Pop() {
stack *old= first;
// Adreso isaugojimas
char e = first->d;
// Reikms isaugojimas
first = first->next;
// Pirmo elemento alinimas
delete old;
// Atminties ilaisvinimas
return e;
// Paalinto elemento reikm
}

Rekursyvi funkcija Ekranas stekui yra perteklin. Joje demonstruojama,


kad rekursyvaus tipo dinamini struktr element perrinkim galima
glaustai aprayti rekursyviomis funkcijomis. Element perrinkimui taip
pat galima vartoti funkcijos viduje deklaruojam lokali rodykl.
Naudojant i perrinkimo technik, galima sudaryti toki funkcijos
Ekranas modifikacij:
//
Ciklinis steko turinio patikrinimas
void stekas::Ekranas1(stack *p) {
stack *temp = p;
// Pagalbin rodykl
while(temp) {
// Steko perrinkimo ciklas
cout << temp->d;
// Reikms parodymas ekrane
temp = temp->next; } // Rodykl tolimesn element
cout << endl;
}

Standartins stek valdymo procedros yra labai paprastos ir greitos, todl


stekai plaiai vartojami laikinam duomen saugojimui tiek taikomosiose,
tiek sisteminse programose. Stekus galima realizuoti ne tik dinaminmis
struktromis, bet ir kitais bdais: aparatros pagalba, vartojant specialius
indeks registrus. Pavyzdiui, steko registro pagalba tvarkom steko
atminties segment kompiliatoriai vartoja lokaliems kintamiesiems saugoti
ir informaciniams ryiams tarp funkcij palaikyti.

121

7.10. Eils ir dekai


Eils (7.14 pav.) nuo stek skiriasi tuo, kad jas duomenys yra siuniami
ir i j atrenkami prieinguose srao galuose. Pertvarkant stek eil,
galima vien jo tvarkymo procedr, pavyzdiui Pop, palikti, o antrj
reikia perrayti panaudojant rekursyvi srao perir eils pabaigos
paiekai. Suradus pabaig, eil papildoma tokiu pat bdu, kaip ir paprastas
sraas. Taip sudarytos funkcijos Add pavyzdys yra pateiktas 7.2 pratime.
7.2 pratimas. ia pateikta eils papildymo funkcija, kuri pritaikyta eilms
sudarytoms i 7.1 pratime apraytos struktros stack element.
Skaitytojui siloma savarankikai sudaryti ciklin ios funkcijos
variant.
//
Eils papildymas
void stekas::Add(stack *p, char e) {
if (!p) {
// Jeigu eil tuia
p = new stack;
p->next = NULL;
p->d = e;
first = p; }
// Eilje atsiranda 1 elementas
else
if (!p->next) {
// Rekursijos pabaigos slyga
p->next = new stack;
// Naujo elemento prijungimas
p->next->next = NULL;
p->next->d = e; }
else Add(p->next, e);
// Rekursija
}

Norint i eils padaryti dek, reikia sudaryti dar vien funkcij, kuri leist
paalinti galinius eils elementus. Rekursyvios galinio eils elemento
alinimo funkcijos realizacija anksiau apraytai struktrai stack atrodo
taip:
//
alinimas i eils galo
char stekas::Del(stack *p) {
char s;
// alinamasis elementas
if (!p->next) {
// Jeigu eilje tik 1 elementas
s = p->d;
delete first;
// alinamas pirmas eils elementas
first = NULL;
return s; }

122

else
if (!p->next->next){
s = p->next->d;
delete p->next; // alinamas priepaskutinis eils elementas
p->next = NULL;
return s; }
// Jeigu eilje daugiau kaip vienas elementas
else Del(p->next); // Rekursija
}

Eils pabaigos paiekai vartoti rekursyv arba ciklin jos element


perrinkim yra neracionalu. Toks paiekos bdas gali bti pateisinamas
tiktai trumpose eilse. Tvarkant ilgas eiles, j element perrinkimo
patartina vengti. Tai galima padaryti, papildant eil galinio elemento
rodykle, kurios reikm bt vartojama ir keiiama papildant eil naujais
elementais. Tokios eils ioriniam apraymui rekomenduojama sudaryti
dviej rodykli struktr ir j tvarkyti modifikuotomis steko tvarkymo
funkcijomis. Kaip tai yra daroma, iliustruojama 7.3 pratime.
first

last
NULL

7.14 pav. Eil nusako pradios ir pabaigos rodykls

7.3 pratimas. Naudodami pateiktus simboli eils su dviem rodyklm


struktros ir jos tvarkymo funkcij apraymus, sudarykite
demonstracin program, kuri leist patikrinti i funkcij darb.
struct stack {
char d;
struct stack *next; };

// Srao element tipas

struct list {
// Eil su dviem iorinm rodyklm
stack *first;
// Pradios rodykl
stack *last; };
// Pabaigos rodykl
//
Klass apraas
class eile {
public:
list que;
// Eils realizacija
eile() {
// Konstruktorius
que.first = NULL;
que.last = NULL; };

123

// Destruktorius
// Eils papildymas gale
// Pradinio elemento paalinimas

~eile() {};
int Add(char);
char Pop();

};
//
Eils tvarkymo funkcij realizacijos
//
Eils papildymas gale
int eile::Add(char e) {
// F-jos Add reikm 1 pranea, kad papildyta skmingai
stack *newe;
if (!(newe = new stack)) return 0; // Ar yra atmintyje vietos?
newe->d = e;
// Naujas elementas
newe->next = NULL;
// Pabaigos ym
if (!que.last) {
// Jeigu eil tuia
que.last = newe;
// Naujas pabaigos adresas
que.first = newe; }
// Naujas pradios adresas
else {
(que.last)->next = newe; // Elemento prijungimas
que.last = newe; }
// Naujas pabaigos adresas
return 1;
// Praneimas apie skming pabaig
}
//
Pradinio elemento paalinimas
char eile::Pop() {
stack *old= que.first;
// Adreso isaugojimas
if (!(que.first)) return '\0'; // Praneimas apie tui eilut
char e = (que.first)->d;
// Reikms isaugojimas
que.first = (que.first)->next; // Pirmo elemento naikinimas
delete old;
// Atminties ilaisvinimas
return e;
// Reikms grinimas
}

7.11. iediniai sraai


Tiesinio vienkrypio srao galiniame elemente raius pirmojo elemento
adres, gausime iedin sra: last->next = first; (7.15 pav.).
first

7.15 pav. iedin srao struktra

124

last

Toliau veiksmuose patogu turti tik vien iorin rodykl last, kuri
saugos iedo galinio (paskutinio) elemento adres, o galinio elemento
ryio dalyje bus saugoma iedo pradinio elemento adresas (7.16 pav.). T
rodykl (last) toliau vadinsime iedo rodykle. Pavadinimai pradia ir
galas iede yra slyginiai. Naudojant iuos pavadinimus bus lengviau
aikintis veiksmus iede.
Pradia

Pabaiga
1

last

7.16 pav. iedinis sraas

iediniai sraai gali bti vartojami eili realizavimui sprendiant tokius


udavinius, kuriuose reikalinga daugel kart perirti t pat duomen
rinkin. iedams yra taikomos tokios standartins tvarkymo operacijos:
tuio iedo inicializavimas;
naujo elemento terpimas iedo pradioje;
papildymas nauju elementu pabaigoje;
pradinio elemento paalinimas;
paieka ir paalinimas.
Tuio iedo, kuris ymimas tuia rodykle NULL, inicializavimas yra
toks pats, kaip ir tiesinio srao. Tuo tarpu, kit operacij realizavimas
skiriasi. Pavyzdiui, papildant sra naujais elementais, tenka taikyti
skirtingas procedras tuiam ir netuiam sraui.
Paiekos ir paalinimo operacijos metu turi bti randamas ir paalinamas
elementas su duotja rakto reikme. Paieka yra vykdoma nuosekliai
perrenkant iedo elementus. alinant reikia iskirti du atvejus: kai yra
alinamas elementas, kur rodo iedo iorin rodykl, yra paskutinis ir
kai alinamas elementas iede yra vienintelis. Pirmuoju atveju, turi bti
keiiama iedo iorins rodykls reikm, o antruoju atveju, iedo iorins
rodykls reikmei priskiriama NULL. Atvej, kai reikia alinti iede esant
element, kur nerodo iedo rodykl, visuomet galima pakeisti atvej,
kai alinamas elementas, kurio adres saugo iedo rodykl.

125

7.4 pratimas. Sudarykite demonstracin program, kuri leist patikrinti


veiksmus su iediniu srau. Naudokite klas ziedas ir jos tvarkymo
metod apraymus.
struct stack { char d;
// iedo element tipas
struct stack *next; };
class ziedas {
public:
stack *last;
// iedo realizacija (rodykl)
ziedas() { last = NULL; };// Konstruktorius
~ziedas() {};
// Destruktorius
int Ins(char);
// terpimas iedo pradioje
int Add(char);
// terpimas iedo pabaigoje
char Del();
// Pirmojo iedo elemento paalinimas
char DelSerch(char);
// Elemento paieka ir alinimas
};
//
iedo tvarkymo funkcij realizavimas
//
terpimas iedo pradioje
// Funkcijos reikm 1 pranea, kad papildyta skmingai
int ziedas::Ins(char e) {
stack *newe;
if (!(newe = new stack))
// Ar yra atmintyje vietos?
return 0;
newe->d = e;
// Naujas duomen elementas
if (last) {
// Netuio iedo slyga
newe->next = last->next; // Pirmo elem. adreso perdavimas
last->next = newe; }
// Naujas pradios adresas
else last = newe->next = newe; // Tuio iedo papildymas
return 1;
// Praneimas apie skming pabaig
}
//
iedo papildymas pabaigoje
// Funkcijos reikm 1 pranea, kad papildyta skmingai
int ziedas::Add( char e ){
stack *newe;
if (!(newe = new stack))
// Ar yra atmintyje vietos?
return 0;
newe->d = e;
// Naujas duomen elementas
if (last) {
// Netuio iedo slyga
newe->next = last->next; // Pirmo elem. adreso perdavimas
last->next = newe;
// Elemento prijungimas pabaigoje
last = newe; }
// Naujas pradios adresas

126

else last = newe->next = newe; // Tuio iedo papildymas


return 1;
// Praneimas apie skming pabaig

}
//
Pirmojo iedo elemento paalinimas
char ziedas::Del() {
stack *temp;
// Pagalbiniai kintamieji
char e;
if (!last) return '\0';
// Pranesimas apie klaida
if (last == last->next) { // iede vienas elementas
temp = last;
// alinamo elemento adresas
last = NULL;
// Nauja iorin rodykl
}
else {
// iede yra keletas element
temp = last->next;
// alinamo elemento adresas
last->next = last->next->next; // alinimas i iedo
}
e = temp->d;
// Reikms isaugojimas
delete temp;
// Atminties ilaisvinimas
return e;
// Reikms grinimas
}
//
Elemento paieka ir paalinimas iede
char ziedas::DelSerch(char e) {
stack *temp = last;
// Pagalbiniai kintamieji
stack *t;
if (!last) return '\0';
// Praneimas apie klaid
while (((temp->next) != last) &&
((temp->next->d) !=e))
temp = temp->next;
// Element perrinkimas
if ((temp->next->d) == e) // Jeigu elem. buvo surastas
if (last == temp->next) // Galinis elementas
if (temp == last) {
// Jeigu iede 1 elementas
last = NULL;
// Tuias iedas
delete temp; }
else {
temp->next = last->next; // Elemento alinimas
delete last;
last = temp; }
// Nauja iorin rodykl
else {
t = temp->next;
temp->next = temp->next->next;
delete t; }
}

127

7.12. Surikiuoto srao papildymas iede


Tiesini sra element rikiavimo tvark galima vertinti j formavimo
funkcijose ir jas sudaryti taip, kad, papildant sra naujais elementais, j
rikiavimo tvarka ilikt. Tokios funkcijos yra sudaromos i dviej dali.
Pirmojoje dalyje yra iekoma srao vieta, kurioje reikia terpti nauj
element, o antrojoje apraoma terpimo procedra. Jeigu simboli
srao elementai yra saugomi alfabeto tvarka, naujas elementas turi bti
raomas prie pirmj srao element, kurio kodas yra didesnis u
papildanio simbolio kod arba, jei tokio elemento nra, srao gale.
Surikiuoto srao papildymo funkcijos realizacija iede:
void ziedas::Terpti(char e) {
stack *t, *temp;
// Pagalbiniai kintamieji
if (!last) {
// Jeigu iedas tuias
last = new stack;
last->d = e;
last->next = last; }
else
// Jeigu terpiama prie pirm iedo element
if (last->next->d > e) {
t = new stack;
t->d = e;
t->next = last->next;
last->next = t; }
else
// Jeigu terpiama po paskutinio iedo elemento
if (last->d < e) {
t = new stack;
t->d = e;
t->next = last->next;
last->next = t;
last = t; }
else {
// terpimo vietos paieka ir terpimas
temp = last->next;
while ((temp != last) && ((temp->next->d) < e))
temp = temp->next;
t = new stack;
t->d = e;
t->next = temp->next;
temp->next = t; }
}

128

7.13. Sraai su neapibrto tipo elementais


Sraai, kuri elementuose tiesiogiai saugomos j reikms, nra
universals, nes j tvarkymo funkcij realizacijos priklauso nuo element
tipo. Norint sudaryti universalius sraus su vairi tip elementams
tinkaniomis tvarkymo funkcijomis, reikia srae saugoti ne paias
element reikmes, o rodykles jas. Geriausiai iam tikslui tinka
neapibrto (void) tipo rodykls, kurios yra suderinamos su visais kitais
rodykli tipais:
struct stack {
void *d;
struct list *next;

};

Sra su neapibrto tipo duomen element rodyklmis tvarkymo


veiksmus reikia atskirti nuo elementams skiriamos atminties tvarkymo
veiksm ir veiksm, kurie susij su srae saugom duomen analize, j
interpretavimu. Dauguma sra tvarkymo veiksm yra universals ir juos
galima aprayti tokiomis funkcijomis, kurios tinka visiems rodykli
nurodomiems element tipams. Tuo tarpu, su duomen interpretavimu
susij veiksmai paprastai bna specializuoti, priklauso nuo srao
element reikmi tipo.
Rodykli sra formavimas yra labai galinga duomen tvarkymo
priemon, kuri vairioms duomen saugojimo struktroms gali suteikti
naujas savybes. Pavyzdiui, tokio srao sudarymas gali pakeisti masyvo
rikiavim. Be to, vienam masyvui galima sudaryti kelis rodykli sraus,
apraanius skirtingus jame saugom duomen perrinkimo bdus.
Apraant neapibrto tipo rodykli sra nurodom duomen
interpretavimo operacijas, reikia apibrti i rodykli interpretavimo
bd. Interpretavimo bdas yra apibriamas tokia struktra:
(<Duomen tipas>*) <Elemento duomen rodykl>

7.5 pratimas. Patikrinkite pratime pateiktos programos darb. Isiaikinkite


joje aprayto universalaus steko tvarkymo funkcij sudarymo
principus ir i funkcij pritaikym simboli stekui tvarkyti.
Programoje taip pat iliustruojamas specializuotos funkcijos Show
sudarymas, kuri gali perduoti ekran tik simboli steko reikmes.
//
Saraas su neapibrto tipo elementais
#include <iostream.h>
char line[] = "Sula";
// Simboli masyvas

129

struct stack {
// Universalus srao elementas
void *d;
// Duomen rodykl
struct stack *next; };
class stekas {
public:
stack *first;
// Steko realizacija (rodykl)
stekas() { first = NULL; };// Konstruktorius
~stekas() {};
// Destruktorius
stack *Get() { return first; };
//
Universalios tvarkymo funkcijos
void Push(void *);
// Papildymas
void *Pop();
// Elemento paalinimas
void Show(stack *);
// Steko turinio parodymas ekrane
};
//
Pagrindin programa
main() {
stack *d;
// Papildomas kintamasis
stekas A;
// Objekto apraymas
int i = 0;
// Simboli masyvo indeksas
cout << "Tvarkoma eilute: " << line << endl;
while(line[i])
// Simboli masyvo pabaigos slyga
A.Push(&line[i++]);
// Rodykli steko sudarymas
cout << "Steko rodomi simboliai: " << endl;
d = A.Get();
A.Show(d);
cout << "Trinama rodykle i pirma simboli ";
cout << *((char *) A.Pop()) << endl;
cout << "Liko rodykles i siuos simbolius: \n";
d = A.Get();
A.Show( d );
}
//
Srao tvarkymo funkcij realizacijos
//
Steko papildymas
void stekas::Push(void *e) {
stack *newe;
// Papildomas kintamasis
newe = new stack;
// Atminties skyrimas
newe->d = e;
// Naujo elemento duomen rodykl
newe->next = first;
// Senos steko dalies prijungimas
first = newe;
// Naujas steko adresas
}

130

//
Elemento paalinimas i steko
void * stekas::Pop() {
stack *old = first;
// Adreso isaugojimas
void *e = first->d;
// Reikms rodykls isaugojimas
first = first->next; // Pirmo elemento alinimas
delete old;
// Atminties ilaisvinimas
return e;
}
//
Rekursyvus steko patikrinimas
void stekas::Show(stack *p) {
if (p) {
// Interpretavimas ir ivedimas ekran
cout << *(char *)(p->d);
Show(p->next); } // Rekursyvus kreipinys tolimesn element
else cout << endl;
}

7.14. Sra su neapibrto tipo elementais panaudojimo


pavyzdiai
1 pavyzdys. Tekstiniame faile Stud.dat turime student sra: pavard,
vardas, paymi vidurkis. Reikia suformuoti du student sraus: vien
- surikiuot pagal abcl ir antr - surikiuot paymi vidurkio
majimo tvarka.
iai uduoiai atlikti yra daug bd. Paprasiausias yra suformuoti du
nepriklausomus sraus, kurie surikiuojami pagal nurodyt rakt. Kitas
gali bti toks: duomenys suraomi masyv ir suformuojami du
rodykli duomenis sraai pagal nurodyt rakt. Vietoje masyvo
galima panaudoti dinamin sra.
Silome vienu srau saugoti duomenis ir rezultatus. Duomenys
suraomi sra ir sutvarkomi pagal abcl. Srae rezervuojame dar
vien lauk nuorodai duomenis. Tas nuorodas surikiuojame pagal
student mokymosi vidurk.
Failo Stud.dat pavyzdys.
Lapinas
Vilkas
Baisus
Katinas

Baisus
Pilkas
Katinas
Didysis

4.5
6.85
3.6
9.5

131

#include
#include
#include
#include
#include

<iostream.h>
<stdio.h>
<stdlib.h>
<string.h>
<conio.h>

typedef struct studentas { char pavard[10];


char vardas[10];
float vidur; };
typedef struct sar { studentas *st;
studentas *vd;
sar *next; };
//
Klass apraymas
class student {
sar *P;
// Srao pradia
public:
student() { P = NULL; };
// Konstruktorius
void Formuoti(FILE *);
// Formuoja sra
void Spausdinti(int);
// Spausdina sra
void Tvarkymas(int);
// Tvarkymas
};
//
Pagrindin programa
void main() {
FILE *D;
student A;
clrscr();
D = fopen("stud.dat", "r");
if (D == NULL) {
cout << "Failo Stud.dat nepavyko atidaryti!";
exit (1); }
A.Formuoti(D);
fclose(D);
A.Spausdinti(0);
// Nesurikiuotas
A.Tvarkymas(1);
// Rikiavimas pagal abcl
A.Tvarkymas(0);
// Rikiavimas pagal vidurk
A.Spausdinti(1);
// Abclinis sraas
A.Spausdinti(0);
// Sraas pagal vidurk
}
//
Student srao formavimas
void student::Formuoti(FILE *F) {
sar *D = NULL;

132

while (!feof(F)) {
D = new sar;
D->st = new studentas;
D->vd = D->st;
fscanf(F, "%s%s%f", D->st->pavard, D->st->vardas,
&D->st->vidur);
D->next = P;
P = D; }

}
//
Student srao spausdinimas
void student::Spausdinti(int kaip) {
sar *D = P;
while(D) {
if (kaip) cout << D->st->pavard << " "
<< D->st->vardas << " "
<< D->st->vidur << "\n";
else cout << D->vd->pavard << " "
<< D->vd->vardas << " "
<< D->vd->vidur << "\n";
D = D->next; }
cout << "--------------------\n";
}
//
Student srao rikiavimas
void student::Tvarkymas(int kaip) {
// kaip = 1 tvarko pagal abcl st rodykl
// kaip = 0 tvarko pagal vidurk vd rodykl
sar *R = P, *R1;
studentas *k;
while(R != NULL ) {
R1 = R->next;
while(R1 != NULL) {
if (kaip) {
if (strcmp(R1->st->pavard, R->st->pavard) < 0)
{ k = R->st; R->st = R1->st; R1->st = k; }}
else if (R1->vd->vidur > R->vd->vidur)
{ k = R->vd; R->vd = R1->vd; R1->vd = k; }
R1 = R1->next; }
R = R->next; }
}

2 pavyzdys. Tekstiniame faile Stud.dat turime student sra: pavard,


vardas, paymi vidurkis. Yra trys kompiuteri klass, kurias priiri
ir tvarko studentai. Reikia suformuoti student darbo klasse sra
savaitei. Kasdien paskiriami trys studentai srao eils tvarka.
133

iam udaviniui sprsti patogiausias yra


Modifikuojame ankstesnio pavyzdio program.
#include
#include
#include
#include
#include

iedinis

<iostream.h>
<stdio.h>
<stdlib.h>
<string.h>
<conio.h>

typedef struct studentas { char pavard[10];


char vardas[10];
float vidur; };
typedef struct sar { studentas *st;
sar *next; };
//
Klass apraymas
class student {
sar *P;
// Srao pradia
public:
student() { P = NULL; };
// Konstruktorius
void Formuoti(FILE *);
// Formuoja sra
void Spausdinti();
// Spausdina sra
void Darbai(int, int);
// Sraai darbui
};
//
Pagrindin programa
void main() {
FILE *D;
student A;
// Objekto apraymas
clrscr();
D = fopen("stud.dat", "r");
if (D == NULL) {
cout << "Failo Stud.dat nepavyko atidaryti!";
exit(1); }
A.Formuoti(D);
cout << "---------------------\n";
fclose(D);
A.Spausdinti();
cout << "---------------------\n";
A.Darbai(3, 3);
}
//
iedinio student srao formavimas
void student::Formuoti(FILE *F) {
sar *D = NULL;
while(!feof(F)) {
D = new sar;

134

sraas.

D->st = new studentas;


fscanf(F, "%s%s%f", D->st->pavard, D->st->vardas,
&D->st->vidur);
D->next = P;
P = D; }
if (P) {
// Srao pabaigos paieka
D = P;
while(D->next) D = D->next;
D->next = P; }
// iedo sudarymas

}
//
Student srao spausdinimas
void student::Spausdinti() {
sar *D;
if (P) {
// Pirmojo spausdinimas
D = P;
cout << D->st->pavard << " "
<< D->st->vardas << " "
<< D->st->vidur << "\n";
D = D->next;
while(D != P) {
// Kit spausdinimas
cout << D->st->pavard << " "
<< D->st->vardas << " "
<< D->st->vidur << "\n";
D = D->next; }}
}
//
Darb sraas
void student::Darbai(int Dien, int kiek) {
sar *D = P;
int i, k;
if (!D) { cout << "Sraas tuias\n"; exit; }
for(i=1; i<=Dien; i++) {
cout << "Diena: " << i << "\n";
for(k=1; k<=kiek; k++) {
cout << " " << D->st->pavard << " "
<< D->st->vardas << "\n";
D = D->next; }}
}

135

8 skyrius. Dvikrypiai tiesiniai sraai


8.1. Srao struktra
Pagrindinis vienkrypi sra trkumas yra tas, kad juose galimas tik
nuoseklus element perrinkimas. Dl to juose lta duomen paieka,
neefektyvios su paieka susijusios tvarkymo operacijos. Siekiant ivengti
io tiesini sra trkumo, yra sukurtos vairios tiesini sra
modifikacijos. Pavyzdiui, realizuojant tiesiniame srae eil, jis yra
papildomas iorine pabaigos rodykle, kuri leidia greitai papildyti sra
nauju elementu gale. T pat efekt galima pasiekti iedinje tiesinio
srao modifikacijoje. Taiau abi ios modifikacijos nepalengvina
paiekos pagal poym ir galinio elemento alinimo operacij.
Paiekai ir element alinimui geriau tinka dvikrypt tiesini sra
modifikacija, kurios elementuose yra dvi rodykls, rodanios pirmesn ir
tolimesn gretimus elementus, ir viena arba dvi iorins rodykls
(8.1 pav.). Tokiuose srauose galima nuo bet kurio j elemento pasiekti
visus kitus elementus.
P

12

34

56

78

NULL
NULL
8.1 pav. Dvikrypio srao struktra

Dvikrypi sra element struktra:


Struct sar {
int *S;
sar *de;
sar *ka;
}

// Duomen rodykl
// Rodykl tolimesn element (dein)
// Rodykl artimesn element (kair)

Dvikryptis sraas gali bti laikomas dviej vienkrypi sra


kompozicija, todl jo tvarkymo funkcijos yra panaios i sra
tvarkymo funkcijas. Pagrindinis skirtumas yra tas, kad tvarkymo
136

operacijose reikia formuoti dvi rodykles. Be to, galima sudaryti


universalias element terpimo ir alinimo operacijas, kurios tinka visiems
srao elementams, ne tiktai galiniams.
Pradioje sraas tuias. Todl pirmojo elemento rodykls P (pradia) ir
galinio elemento rodykls G (galas) reikms turi bti nulins NULL.
Tuias sraas yra inicializuojamas deklaruojant nulines jo rodykles:
sar *P = NULL,

*G = NULL;

8.2. Srao formavimas ir perira


Dvikryptis sraas tik P arba G rodykli atvilgiu yra analogikas
vienkryiui sraui. Formuojant sra, kai nauji elementai prijungiami
srao pradioje (rodykl P ), rodykls G atvilgiu nauji elementai bus
jungiami srao gale. Ir atvirkiai. Darome ivad, kad io srao
formavimui tinka veiksmai, kurie vykdomi vienkrypiame srae
formuojant sra steko ir eils bdais.
//
#include
#include
#include
#include

Dvikryptis sraas
<iostream.h>
<stdio.h>
<stdlib.h>
<conio.h>

typedef struct sar { int *S;


//
sar *de;
//
sar *ka; };
//
//
Klass apraymas
class DviKryptys {
sar *P;
//
sar *G;
//
public:
DviKryptys() { P = NULL; G = NULL;
~DviKryptys();
sar *GetP() { return P; };
sar *GetG() { return G; };
void Formuoti(FILE *);
//
void Spausdinti();
//
void SpausdintiAtv();
//
};

Rodykl element
Rodykl dein
Rodykl kair
Srao pradia
Srao galas
};

// Konstruktorius
// Destruktorius

Formuoja sra
Spausdina sra
Spausdina sra atvirkiai

137

//
Pagrindin programa
void main() {
FILE *D;
DviKryptys A;
// Klass DviKryptys objektas
clrscr();
D = fopen("Duom.dat", "r");
if (D == NULL) {
cout << "Failo Duom.dat nepavyko atidaryti";
exit(1); }
A.Formuoti(D);
fclose(D);
A.Spausdinti();
cout << "***********\n";
A.SpausdintiAtv();
A.~DviKryptys();

}
//
Srao formavimas, raant pradi
void DviKryptys::Formuoti(FILE *F) {
sar *R;
// Darbinis kintamasis
if (!feof(F)) {
// Pirmojo elemento prijungimas
G = new sar;
P = G;
P->S = new int;
fscanf(F, "%i", P->S);
P->ka = NULL;
P->de = NULL; }
while (!feof(F)) {
// Likusi element prijungimas
R = new sar;
R->S = new int;
fscanf(F, "%i", R->S);
R->ka = NULL;
R->de = P;
P->ka = R;
P = R; }
}
//
Spausdina sra nuo pradios
void DviKryptys::Spausdinti() {
sar *D = P;
while(D != NULL) {
cout << *D->S << "\n";
D = D->de; }
}

138

//
Spausdina sra nuo galo
void DviKryptys::SpausdintiAtv() {
sar *D = G;
while(D != NULL) {
cout << *D->S << "\n";
D = D->ka; }
}
//
Destruktorius
DviKryptys::~DviKryptys() {
sar *D = P;
while(P != NULL) {
D = P;
P = P->ka;
delete(D->S);
delete(D); }
}

Rodykl P rodo sra, kuriame duomenys saugomi atvirktine tvarka, o


rodykl G rodo sra tiesiogine tvarka. Norint sukeisti rodykli reikmes
srao tvarkos poiriu, reikia modifikuoti funkcij Formuoti. Silome
tai padaryti patiems ir patikrinti.
Srao perirai tinka vienkrypio srao periros algoritmas. Sraas
nagrinjamas panaudojant vien rodykl: P ir de lauko reikmes arba G ir
ka lauko reikmes. Turime galimyb sra perirti tiesiogine ir
atvirktine tvarka. Tai demonstruoja spausdinimui skirtos funkcijos.

8.3. Srao papildymas


Galimos trys situacijos:

naujo elemento prijungimas srao pradioje (P rodykls atvilgiu),


srao gale (G rodykls atvilgiu),
bet kurioje srao vietoje (rodykls P ir G nekinta).

Pirmos dvi situacijos atitinka vieno elemento prijungimo veiksmams


srao formavimo procese, todl atskirai j neaptarsime. Kuriant funkcij,
skirt naujo elemento terpimui, reikia patikrinti situacij ir atlikti jai
skirtus veiksmus (prie pirm element, po paskutinio elemento arba
srao viduje). Elemento terpimas srao viduje po elemento R yra tapatus
veiksmams prie element R.
D->de = R;

// Naujas elementas pamato savo naujus kaimynus

139

D->ka = R->ka;
(R->ka)->de = D;
R->ka = D;

// Elementas D jungiamas sra

terpiant nauj element D prie rodykls R nurodom srao element,


reikia suformuoti keturias naujas, punktyrinmis linijomis parodytas,
rodykles (8.2 pav.), kurios turi pakeisti dvi element ryius apraanias
rodykles. Pradioje reikia sutvarkyti naujo elemento ryius su bsimais
kaimynais srae, o po to pakeisti srao element ryius naujj
element.
P

<12>

<34>

<56>

<78>

NULL
NULL
<999>

8.2 pav. Naujo elemento D terpimas prie element R

Universalios dvikrypio srao papildymo funkcijos Terpti realizacija ir


panaudojimo pavyzdiai:
void Terpti(sar *, int *);
int x = 0, y = 100;

// Metodo prototipas
// terpiamos reikms

T = A.GetP();
A.Terpti(T, &x);
// terpimas srao pradioje
A.Terpti(T->de, &x); // terpimas prie antraj element. Jis privalo bti
T = A.GetG();
Terpti(T, &y);
// terpimas prie paskutin element
//
terpimas "prie" R element
void DviKryptys::Terpti(sar *R, int *sk) {
sar *D;
D = new sar;
// Naujas elementas
D->S = sk;
// Rodykl reikm

140

if (R == P) {
D->de = P;
D->ka = NULL;
P->ka = D;
P = D; }
else {
D->de = R;
D->ka = R->ka;
(R->ka)->de = D;
R->ka = D; }

// Kai R rodo pirm: padti pradioje

// Padti srae prie nurodyt R

8.4. Element alinimas


Universali element alinimo funkcija yra paprastesn, nes jai reikia
suformuoti tik dvi naujas srao rodykles. ioje funkcijoje reikia
atsivelgti atvejus, kai alinamas pradinis elementas, paskutinis
elementas ir kai alinamas elementas i srao vidaus (8.3 pav.). Funkcija
grina rodykl paalinto elemento duomen saugojimo viet (arba
NULL). Tai reikalinga, nes yra alinama nuoroda srae duomenis, bet ne
patys duomenys. Kaip elgtis su duomenimis sprendia duomen
apdorojimo paprograms. alinimo funkcija skirta nurodyto elemento
paalinimui. Tai reikia, kad prie tai buvo atlikta to elemento paieka.
Jeigu elementas nebuvo surastas, tai ir nebus panaudota alinimo funkcija.
P

<12>

<34>

<56>

<78>

NULL
NULL
R
8.3 pav. Elemento R paalinimas

Elemento alinimo funkcijoje atsimenama ir grinama rodykl


duomenis, kuriuos buvo nuoroda alinamame elemente. is veiksmas iai
funkcijai yra perteklinis (nebtinas), nes atliekant alinamo elemento
paiek yra nagrinjami duomenys, o tai reikia, kad juos jau turime.
R>de>ka = R>ka;
R>ka>de = R>de;

141

alinimo funkcijos Mesti pavyzdyje nagrinjamos visos trys situacijos,


bet nenagrinjama situacija, kai sraas tuias ir ar alinamo elemento
rodykl netuia. To daryti nebtina, nes programos dalyje, kurioje
nagrinjami paalinimo i srao kandidatai, btina patikrinti, ar toks
elementas egzistuoja. Silome papildyti pavyzdio program ia funkcija
ir patikrinti jos darb.
int *Mesti(sar *);

// Metodo prototipas

T = A.GetP();
A.Mesti(T);
// alinamas pirmas elementas
T = A.GetG();
A.Mesti(T);
// alinamas paskutinis elementas
T = A.GetP();
A.Mesti(T->de);
// alinamas antras elementas
//
alinti R element
int *DviKryptys::Mesti(sar *R) {
int *sk = R->S;
if (R == P) {
// Jeigu srao pradioje
P = P->de;
if (P != NULL) P->ka = NULL; }
else
if (R == G) {
// Jeigu srao pabaigoje
G = G->ka;
if (G != NULL) G->de = NULL; }
else {
// Jeigu srao viduje
R->de->ka = R->ka;
R->ka->de = R->de; }
delete(R);
return sk;
}

8.5. Tvarkymo veiksmai


Srao element tvarkymo veiksmams priskiriamos paiekos, atrankos ir
rikiavimo operacijos.
Paiekos veiksmams negalima sudaryti universali paprogrami, nes tai
susieta su konkreiu udaviniu, duomenim struktra ir konkreiu
paiekos raktu. Paiekoje galima skirti du bdus:

Srae duomenys rakto atvilgiu yra nesutvarkyti. Paieka atliekama


nuosekliai perirint visus srao elementus. Paieka nutraukiama, kai

142

surandamas reikalingas elementas. Tik vis sra perirjus galima


suinoti, kad neradome reikalingo elemento.
Srao duomenys rakto atvilgiu yra sutvarkyti. Paieka vykdoma
nuosekliai perirint elementus. Paieka nutraukiama suradus tinkam
element arba susidarius situacijai, kai tolesnis srao nagrinjimas yra
beprasmis: jau tikrai toliau srae negali bti iekomas elementas.
Pavyzdiui, telefon knygoje, iekant abonento pagal pavard,
nebtina perskaityti viso srao iki galo.

Duomen atrankos veiksmai priskirtini naujo srao formavimui, nes yra


sudaromas naujas nuorod jau turimus duomenis sraas. Pavyzdiui,
turime student sra. Galima sudaryti nuorod sra tik pirmo kurso
studentus.
Rikiavimo pagal duot rakt funkcijos yra analogikos funkcijoms,
skirtoms darbui su vienkrypiu srau. ia reikia nepamirti, kad sraas
dvikryptis ir reikia koreguoti dvi rodykles elementui. io tipo srauose
veiksm su rodyklmis padvigubja, taiau paiekai skirt rodykli
sumaja. Jeigu rikiavime leidiama keisti vietomis duomenis, tuomet
naudojamos tik vienos krypties rodykls (pradios arba pabaigos). Jeigu
reikia tvarkyti nuorodas, tuomet veiksmai tampa komplikuoti. Problema
isprendiama, kuomet srae saugomi ne duomenys, o nuorodos juos.
Rikiavimo metu keiiame vietomis tas nuorodas. Duomenys savo padties
nekeiia. Tai leidia formuoti atskirus nuorod, tvarkingus pagal vairius
poymius, sraus. Pavyzdiui, turime telefon abonent sra. Galima
sudaryti nuorod sra pagal pavardes, abcls tvarka. Galima sudaryti
sra, kuriame bt nuorodos t pat abonent sra, tik telefon
numeri didjimo seka.
Dvikryptis sraas gali bti naudojamas su tam tikrais apribojimais. Tai
dvigubo steko bei eils tipo sraai. Vartotinas dvigubo iedo sraas, nes
jame terpimo bei alinimo veiksmai nesudtingi, be to paprastas srao
skenavimas pirmyn-atgal.
Dirbant su srainmis struktromis, visuomet btina tikrinti nagrinjamo
elemento padt srae: kratinis ar viduje. To galima ivengti, jeigu srao
kratinius elementus tursime fiktyvius, t.y. jie nebus susieti su
duomenimis, atliks buferini element funkcij. Tuias sraas bus tuo
atveju, kai bus tik tie elementai. Vienkrypiame srae paprastai toks
elementas formuojamas pradioje, taiau eils atveju j naudinga turti ir
gale. Dvikryptis sraas paprastai turi du kratinius tuius elementus,
143

nors pakanka ir vieno. Tie elementai gali bti pastovs arba formuojami
laikinai, kol bus atlikti atitinkami veiksmai, po to jie alinami.

8.6. Panaudojimo pavyzdys


Tekstiniame faile Stud.dat turime student sra: pavard, vardas,
mokymosi vidurkis. Reikia paalinti nepaangius studentus.
Formuosime dvikrypt sra. Element alinimo veiksmuose sra
papildysime pradioje ir gale tuiais elementais. Gausime situacij, kai
visi duomen elementai yra srao viduje pradios ir galo atvilgiu.
Element alinimas supaprastja.
//
#include
#include
#include
#include
#include

Panaudojimo pavyzdys
<iostream.h>
<stdio.h>
<stdlib.h>
<string.h>
<conio.h>

typedef struct studentas { char pavard[10];


char vardas[10];
float vidur; };
typedef struct sar { studentas *st;
sar *de;
sar *ka; };
//
Klass Studentai apibrimas
class Studentai {
sar *P;
//
sar *G;
//
public:
//
Studentai() { P = NULL; G = NULL; }
void Formuoti(FILE *);
//
void Spausdinti();
//
void Tvarkymas(float);
//
};
//
Pagrindin programa
void main() {
FILE *D;
Studentai A;
// Klass
clrscr();

144

Srao pradia
Srao galas
Konstruktorius
Formuoja sra
Spausdina sra
Tvarkymas

Studentai objektas

D = fopen("stud.dat", "r");
if (D == NULL) {
cout << "Failo Stud.dat nepavyko atidaryti ";
exit(1); }
A.Formuoti(D);
fclose(D);
A.Spausdinti();
cout << "---------------------\n";
A.Tvarkymas(4.5);
A.Spausdinti();

}
//
Student srao formavimas
void Studentai::Formuoti(FILE *F) {
sar *R;
if (!feof(F)) {
R = new sar;
R->st = new studentas;
fscanf(F, "%s%s%f", R->st->pavard, R->st->vardas,
&R->st->vidur );
R->de = NULL;
R->ka = NULL;
P = R;
G = R; }
while(!feof(F)) {
R = new sar;
R->st = new studentas;
fscanf(F, "%s%s%f", R->st->pavard, R->st->vardas,
&R->st->vidur);
R->ka = G; G->de = R; R->de = NULL; G = R;
}
}
//
Srao spausdinimas
void Studentai::Spausdinti(){
sar *D = P;
while(D != NULL) {
cout << D->st->pavard << " "
<< D->st->vardas << " "
<< D->st->vidur << "\n";
D = D->de;
}
}
//
alinimas i srao
void Studentai::Tvarkymas(float vd) {
sar *R, *D;
R = new sar;
// "Tuias" elementas srao pradioje

145

R->ka = NULL;
R->de = P;
R->st = NULL;
P->ka = R;
P = R;
R = new sar;
// "Tuias" elementas srao gale
R->de = NULL;
R->ka = G;
R->st = NULL;
G->de = R;
G = R;
R = P->de;
while(R->de != NULL) {
// alinimo ciklas
if (R->st->vidur < vd) {
R->de->ka = R->ka;
R->ka->de = R->de;
D = R;
R = R->ka;
delete(D->st);
// alinimas rodykls student
delete(D); }
// alinimas srao elementas
R = R->de; }
R = P;
// "Tuio" elemento alinimas i srao pradios
P = R->de;
P->ka = NULL;
delete(R);
// "Tuio" elemento alinimas i srao galo
R = G;
G = R->ka;
if(G) G->de = NULL;
else P = NULL;
// Sraas tuias
delete(R);
}

146

9 skyrius. Tiesini sra rinkiniai


9.1. Sra struktra
Apdorojant duomenis, ne visuomet patogu turti vien duomen sra,
ypa kai t duomen daug. Patogu turti kelet atskir tiesini sra.
Pavyzdiui, turime universiteto kiekvieno fakulteto student sraus.
Galima sudaryti tiek sra, kiek yra fakultet. Taiau prireikus papildyti
duomenis naujo fakulteto srau, reikia modifikuoti program. Tai
nepatogu. Galima suformuoti rodykli fakultetus masyv, paliekant
rezerv naujiems sraams registruoti. Tokio srao schema parodyta
9.1 pav.
Masyvas

Sraai
NULL

IF
NULL

AP

NULL

HM
NULL
NULL

9.1 pav. Daugiasrain struktra, organizuojama masyvu.


Sra raktiniai odiai ir rodykls sraus saugomos masyve

Lankstesn struktra gaunama, kai vietoje masyvo yra formuojamas


nuoseklus sraas, vienkryptis arba dvikryptis (9.2 pav.). Tokio srao
elementas turi rodykl duomen tiesin sra ir srao pavadinimo lauk
(arba rodykl t pavadinim). Gauname akot sra, kurio struktra
universali duomen atvilgiu: nereikia modifikuoti program papildant
nauju duomen srau. Tinka visi veiksmai, aptarti tiesiniams sraams.
Priklausomai nuo pradini duomen funkcins tarpusavio priklausomybs
ir planuojam apdorojimo veiksm yra projektuojama srain struktra.
J tikslinga parinkti toki, kad veiksmai bt kuo paprastesni. Kurdami
akot struktr mes i anksto numatome tam tikr duomen suskirstym,
klasifikavim. Gerai suprojektuota struktra supaprastina veiksmus.
147

P
NULL
IF

FM

TT

HM

NULL
NULL

NULL

NULL

9.2 pav. Tiesini sra rinkinys

9.2. Srao panaudojimo pavyzdys


Tekstiniame duomen faile yra student sraas: pavard, vardas,
fakultetas. Reikia suformuoti duomen sra pagal fakultetus.
Panaudosime sra, kurio schema parodyta 9.2 pav. Duomen skaitymo
metu iekosime akos su studento fakulteto pavadinimu. Jeigu nebus,
sukursime nauj element pagrindiniame srae su naujo fakulteto
pavadinimu ir atidarysime ak su to studento pavarde ir vardu. Jeigu
rasime element su tuo fakultetu, tai akoje sukursime nauj element su
naujo studento pavarde ir vardu. Baigus skaityti duomen fail tursime
akot sra, kuriame studentai bus suskirstyti fakultetais.
Srao papildymas naujais duomenimis yra tapatus formavimui. alinant
studentus i srao gali susidaryti situacija, kai fakultete neliks nei vieno
studento. Tuo atveju tikslinga paalinti i pagrindinio srao element su
fakulteto pavadinimu. Galimas atvejis, kai nealiname fakulteto elemento,
bet nuorodoje student sra paraome tuio adreso reikm NULL.
Duomen failas: Studf.dat
Petraitis
Jurgelis
Batuotas
Lapinas
Medinis
Ramusis

148

Petras
Jurgis
Katinas
Rudas
Jurgis
Petras

IF
HM
EK
IF
IF
HM

8.9
5.6
7.8
10
8
6.3

//
#include
#include
#include
#include
#include

Srao panaudojimo pavyzdys


<iostream.h>
<stdio.h>
<stdlib.h>
<string.h>
<conio.h>

typedef struct studentas { char pavard[10];


char vardas[10];
char fakult[10];
float vidur; };
typedef struct sar { studentas st;
sar *kitas; };
typedef struct fakultetas { char fak[10];
fakultetas *sek;
sar *stud; };
//
Klass Uni apraymas
class Uni {
fakultetas *P;
// Dinaminio srao pradia
public:
Uni() { P = NULL; };
// Konstruktorius
void Formuoti(FILE *);
// Formuoja sra
void Spausdinti(sar *);
// Spausdina sra
void Visi_stud();
void Pasirink();
};
//
Pagrindin programa
void main() {
FILE *D;
Uni A;
// Klass Uni objektas
clrscr();
D = fopen("studf.dat", "r");
if (D == NULL) {
cout << "Failo Studf.dat nepavyko atidaryti ";
exit(1); }
A.Formuoti(D);
fclose(D);

A.Visi_stud();
A.Pasirink();

149

//
Srao formavimas
void Uni::Formuoti(FILE *F) {
fakultetas *R;
sar *A;
int yra;
while(!feof(F)) {
A = new sar;
fscanf(F, "%s%s%s%f", A->st.pavard, A->st.vardas,
A->st.fakult, &A->st.vidur);
yra = 0;
R = P;
while(!yra && R)
if (strcmp(A->st.fakult, R->fak) == 0)
else R = R->sek;

yra = 1;

if (!yra) {
R = new fakultetas;
R->stud = NULL;
strcpy(R->fak, A->st.fakult);
R->sek = P;
P = R; }
A->kitas = R->stud;
R->stud = A;
}

}
//
Spausdina vieno fakulteto student sra
void Uni::Spausdinti(sar *R) {
while(R) {
cout << R->st.pavard << " "
<< R->st.vardas << " "
<< R->st.vidur << "\n";
R = R->kitas; }
cout << "------------------------\n";
}
//
Spausdina vis fakultet student sraus
void Uni::Visi_stud() {
fakultetas *R = P;
cout << "=== Fakultet ir student sraai ===\n\n";
while(R) {
cout << "Fakultetas " << R->fak << ":\n";
Spausdinti(R->stud);

150

R = R->sek;

}
//
Pageidaujamo fakulteto student srao spausdinimas
void Uni::Pasirink() {
fakultetas *R;
char fk[10], s;
int yra, rinkti = 1;
while(rinkti) {
cout << "Fakultetas= ";
cin >> fk;
yra = 0;
R = P;
while(!yra && R)
if (strcmp(fk, R->fak) == 0)
else R = R->sek;

yra = 1;

if (yra) {
cout << R->fak << ":\n";
Spausdinti( R->stud ); }
else cout << fk << " srae nerastas\n";

cout << "------------------------\n";


cout << "Ar dar renkate fakultet(T)?";
cin >> s;
if ((s != 'T') && (s != 't')) rinkti = 0;

151

10 skyrius. Netiesiniai sraai


10.1. Srao struktra
Sraas, kurio elementus ryio tvarka negalima idstyti vien grandin,
vadinamas netiesiniu. Tai grafus vaizduojantys sraai. ia virns
atitinka srao element reikmes, o virnes jungiantys lankai atitinka
rodyklmis apraomus ryius tarp j. Nuo grafo virni sujungim bd
priklauso jo savybs, grafo virni perrinkimo bdai. Veiksm su
sraais sudtingumas priklauso nuo graf struktros ir duomen
apdorojimo algoritm.
Patys paprasiausi ir daniausiai vartojami yra medio tipo netiesiniai
sraai (10.1 pav.), kuri elementus galima idstyti kelis hierarchijos
(pavaldumo) lygius taip, kad pradiniame, nuliniame, lygyje bt tik vienas
elementas, o kiekvien emesnio hierarchijos lygio element vest tiktai
viena nuoroda ir tik i auktesnio hierarchijos lygio elemento.
Pradia

0-is lygis

D0

D11

D21

D22

1-sis lygis

D13

D12

D23

D24

D25

emesnius hierarchinius lygius

10.1 pav. Medio tipo srao grafinis vaizdas

152

2-sis lygis

Apraant programose medio tipo struktras, yra paprastai ribojamas


nuorod emesnius hierarchijos lygius (rodykli) skaiius. Jei jis
apribojamas dviem, tai toks medis yra vadinamas binariniu.
Binarini medi elementai yra apraomi taip pat, kaip ir dvikrypi
sra elementai, ryio dalyje formuojant dvi nuorodas. Tiktai priimta ias
nuorodas ymti kitokiais vardais, pabriant, kad medio akos yra
nukreiptos dein arba kair pus (de, ka):
struct medis {
void *data;
medis *ka;
medis *de; }

// Duomen rodykl
// Kairs medio akos rodykl
// Deins medio akos rodykl

Binariniai mediai labai gerai tinka organizuoti tokioms saugojimo


struktroms, i kuri danai tenka pagal poymius atrinkinti pavienius
elementus arba nedideles j grupes. Apraant medio tipo struktras, taip
pat reikia apibrti j formavimo, tvarkymo bei apdorojimo procedras.

10.2. Formavimas
Formavimo veiksmai priklauso nuo srao struktros ir duomen
tarpusavio priklausomybs. Universali paprogrami negalima sudaryti.
Duomen rinkinys:
5

5 8 3 1 4 6 3 7

8
NULL

1
NULL

4
NULL

6
NULL

NULL

3
NULL

7
NULL

NULL

NULL

10.2 pav. Binarinis medis

153

Medio formavim iliustruosime tokiu pavyzdiu. Tarkime, kad reikia


sudaryti med, kuriame bt saugomi elementai, turintys sveik skaii
reikmes. Skaiiai gaunami i failo, kuriame jie surayti atsitiktine tvarka.
Medyje juos reikia patalpinti didjimo tvarka (10.2 pav.).
Formuosime binarin med. Tai bus padaryta taip. Pirmas medio
elementas turs pirmojo skaiiaus reikm. Kitiems skaiiams bus
sukuriami elementai, kuri vieta medyje bus randama tokiu dsniu: jeigu
nauja reikm yra maesn u nagrinjamo medio elemento saugom
reikm, tai pereiname prie kairiojo elemento, kitaip prie deiniojo. Naujas
elementas pakabinamas medyje toje vietoje, kur randamas akos galas,
t.y. elementas su rodykls reikme NULL. Naujas elementas su nauja
reikme turi turti ka ir de reikmes NULL.
//
#include
#include
#include
#include

Medio sudarymo pavyzdys


<iostream.h>
<stdio.h>
<stdlib.h>
<conio.h>

typedef struct medis { int sk;


medis *de;
medis *ka; };
//
Klass Binmedis apraymas
class Binmedis {
medis *P;
// Medio virn
public:
Binmedis() { P = NULL; }; // Konstruktorius
void Formuoti(FILE *);
// Formuoja med
medis *Get() { return P; };
void Padeti(medis *);
// Naujo elemento vieta medyje
void Spausdinti();
// Spausdina reikmes didjimo tvarka
// Spausdina reikmes majimo tvarka
void SpausdintiRek(medis *);
medis *Rasti(int);
// Duotos reikms paieka medyje
};
//
Pagrindin programa
void main() {
FILE *D;
medis *R;
Binmedis A;
// Objekto apraymas
clrscr();
D = fopen("duom.dat", "r");

154

if (D == NULL) {
cout << "Failo Duom.dat nepavyko atidaryti ";
exit(1); }
A.Formuoti(D);
fclose(D);
A.Spausdinti();
// Didjimo tvarka
cout << "\n" << "======================\n";
R = A.Get();
A.SpausdintiRek(R);
// Majimo tvarka
cout << "\n" << "======================\n";
for(int i=0; i<=10; i++) {
// Paiekos iliustracija
R = A.Rasti(i);
if (R) cout << i << " Radau!\n";
else cout << i << "* neradau\n"; }

}
//
Medio formavimas
void Binmedis::Formuoti(FILE *F) {
medis *R;
while(!feof(F)) {
// Naujas elementas
R = new medis;
R->ka = NULL;
R->de = NULL;
fscanf(F, "%i", &R->sk);
if (!P) P = R;
// Elementas dedamas med
else Padeti(R); }
}
//
Padti element medyje
void Binmedis::Padeti(medis *R) {
medis *D = P, *T;
while(D) {
T = D;
// Tuios akos paieka
if (R->sk < D->sk) D = D->ka;
else D = D->de; }
if (R->sk < T->sk) T->ka = R; // Elemento prijungimas
else T->de = R;
}
//
Spausdinimas didjimo tvarka
void Binmedis::Spausdinti() {
medis *R = P;
struct stekas {medis *S;
// Stekas medio trasavimui
stekas *sek; } *A = NULL, *D;

155

while(R || A) {
if (R) {
D = new stekas;
D->sek = A;
A = D;
A->S = R;
R = R->ka; }
else {
R = A->S;
D = A;
A = A->sek;
delete(D);
cout << R->sk << "
R = R->de; }
}

// Virns adreso uraymas stek

// Perjimas kair
// Kratinio elemento adresas imamas i steko

";

// Spausdinama reikm
// Perjimas dein

}
//
Spausdinimas majimo tvarka (su rekursija)
void Binmedis::SpausdintiRek(medis *R) {
if (R) {
SpausdintiRek(R->de);
cout << R->sk << " ";
SpausdintiRek(R->ka); }
}
//
Elemento, turinio nurodyt reikm paieka
medis *Binmedis::Rasti(int Sk) {
medis *R = P;
while(R && (R->sk != Sk))
if (Sk < R->sk) R = R->ka;
else R = R->de;
return R;
// Neradus grinama reikm NULL
}

10.3. Perira
Perrenkant medyje esanias reikmes yra vadovaujamasi mediui sukurti
naudotais principais. Pavyzdio med galima perirti skaii didjimo
arba majimo tvarka. Perira pradedama nuo medio virns ir
iekome toliausiai kairje esanios akos virns, kurios reikm bus
maiausia. J spausdiname ir pasukame artimiausi dein ak, nuo
kurios vl iekome toliausiai kair pus esanios virns. T.y. kartojame
medio formavimo proces. Kadangi mediu galime judti tik viena
kryptimi (nra nuorod auktesn lyg), tai btina atsiminti virnes, per
156

kurias buvo nusileidiama iki atitinkamos virns. Tam naudojamas


stekas, kur galima organizuoti masyve, tiesiniu srau arba ireikti
netiesiogiai panaudojant rekursin paiekos bd. Pavyzdio programoje
yra funkcija Spausdinti, kuri skirta spausdinti medio reikmes
didjimo tvarka ir kuri stekui naudoja tiesin sra. Funkcija
SpausdintiRek skirta spausdinti medio saugomas reikmes majimo
tvarka ir yra rekursin.
Iekant medyje duotos reikms yra vadovaujamasi vienu i medio
periros bd: kairiniu arba deininiu. Pavyzdio programoje funkcija
Rasti demonstruoja paiek kairiniu bdu. i funkcij galima
patobulinti: duomenys yra tvarkingai sudti, todl paiek galima
nutraukti, kuomet tolesn perira tampa beprasm (iekoma reikm
tampa maesne u aktyvaus elemento saugom reikm).
Binarini medi skleidimu yra vadinamas vis j element perrinkimas.
Nuo perrinkimo bdo priklauso, kokia tvarka medyje saugomi duomenys
yra perduodami juos apdorojanioms funkcijoms. Naudojami trys
pagrindiniai skleidimo bdai: kairysis, deinysis ir centrinis.
Naudojant kairj skleidimo bd, kiekviename elemente i pradi yra
perrenkama kairiosios rodykls rodoma medio aka. Po to apdorojami
elemento saugomi duomenys ir perrenkama deinioji aka. Skleidimas yra
pradedamas nuo medio kamieno.
Deinysis skleidimas vykdomas prieinga kairiajam skleidimui tvarka, o
centrinio skleidimo atveju, i pradi apdorojamas duomen elementas ir
tik po to perrenkamos kairioji ir deinioji akos.
Visi aptarti skleidimo bdai yra labai glaustai apraomi rekursinmis
funkcijomis. Pavyzdiu gali bti pavyzdyje pateiktos medyje saugom
reikmi spausdinimas.

157

11 skyrius. Savarankikas darbas


11.1. Programos pavyzdys
Darbo su srainmis struktromis gdiai susidaro savarankikai raant
programas. Silome pabandyti visas nagrintas dinamines struktras
sudtingumo seka. Tai galite padaryti su tuo paiu vienu udaviniu,
modifikuojant padarytas programas. Js galsite palyginti sra taikymo
galimybes, j efektyvum. Imdami kiekvienai struktrai skirtingas
uduotis, tursite galimyb ibandyti ne tik sraines struktras, bet ir
pagilinti inias program struktros krime.
Sraini struktr studijas silome baigti atskiro udavinio programos
padarymu. ia reikt suprojektuoti toki savo dinamin duomen
struktr, kuri bt racionaliausia pasirinktam udaviniui.
Pavyzdio uduotis. Kelioni agentra turi silom turistini kelioni sra.
inomas kelions tipas, trukm, vieta ir kaina. Keliautojas renkasi
kelion pagal du kriterijus: trukm ir kain. Reikia sudaryti sra
kelioni, nevirijani bsimo keliautojo galimybi.
Duomen srao pavyzdys. Duomenys saugomi tekstiniame faile
Kelione.sar (11.1 pav.). Vienoje eilutje yra vienos kelions
duomenys, surayti tokia tvarka: pirmose 10 pozicij kelions tipas,
toliau trukm dienomis, 10 pozicij skiriama vietovs pavadinimui ir
eiluts gale kaina litais. Duomen faile tui eilui negalima
palikti.
Dviratis
Eiti
Traukinys
Laivas
Joti
Valtis

15
10
15
25
5
12

Lietuva
Dzukija
Turkija
Afrika
Utena
Neris

200
100
1200
2500
230
345

11.1 pav. Kelioni srao pavyzdys

158

Rezultat pavyzdys. Rezultatai lenteli formoje kaupiami tekstiniame


faile vardu Kelione.rez (11.2 pav.). Pavyzdyje yra duomen ir
pasirinkimui tinkam kelioni lentels. Pasirinkimo sraas yra
surikiuojamas pagal trukm ir kain.
Siulomu kelioniu sarasas
+----+------------+--------+------------+---------+
| Nr.| Keliones t.+ Trukme +
Vieta
+ Kaina +
+----+------------+--------+------------+---------+
| 1 |
Valtis |
12 |
Neris |
345 |
| 2 |
Joti |
5 |
Utena |
230 |
| 3 |
Laivas |
25 |
Afrika |
2500 |
| 4 | Traukinys |
15 |
Turkija |
1200 |
| 5 |
Eiti |
10 |
Dzukija |
100 |
| 6 |
Dviratis |
15 |
Lietuva |
200 |
+----+------------+--------+------------+---------+
Atrinktu kelioniu sarasas
+----+------------+--------+------------+---------+
| Nr.| Keliones t.+ Trukme +
Vieta
+ Kaina +
+----+------------+--------+------------+---------+
| 1 |
Joti |
5 |
Utena |
230 |
| 2 |
Eiti |
10 |
Dzukija |
100 |
| 3 |
Valtis |
12 |
Neris |
345 |
| 4 |
Dviratis |
15 |
Lietuva |
200 |
| 5 | Traukinys |
15 |
Turkija |
1200 |
+----+------------+--------+------------+---------+
11.2 pav. Rezultat failo pavyzdys

Programos duomen struktra. Kelions duomenims aprayti skirta


struktra:
struct kelione { char
char
int
int

tipas[10];
vieta[10];
trukme;
kaina; };

Duomenys bus saugomi tiesiniu vienkrypiu srau:


typedef struct sar { kelione S;
sar *sek; };

Programoje sukurta klas Kelions. Duomen srao rodykl P,


atrinkt kelioni srao rodykl K.
159

Klass metod apraymas

Pagrindin funkcija.
P duomen srao rodykl.
K rezultat srao rodykl.
F failinis kintamasis.
ia atidaromi ir udaromi failai, formuojamas duomen sraas P ir
rezultat sraas K, rikuojamas sraas K, spausdinami sra
duomenys lentelmis. Veiksmams atlikti naudojami padaryti metodai.

void Keliones::Formuoti(FILE *F);


Funkcijai perduodamas atidarytas duomen failas F. ia skaitomi
duomenys po vien eilut ir formuojamas duomen sraas. Srao
pradia P. Sraas formuojamas steko principu. Panaudojama funkcija
Padeti

void Keliones::Padeti(sar **P, kelione N);


Sukuria nauj element su duotos kelions N duomenimis ir prijungia
prie srao P pradios.

void Keliones::Spausdinti(sar *P, FILE *F);


Srao P saugomus duomenis lentels forma surao tekstin fail F.

void Keliones::Rikiuoti(sar *P);


Srao P duomenis surikiuoja pagal nurodyt rakt, aprayt funkcijoje
Raktas. Sraas rikiuojamas daliniu Minmax bdu. Rikiavimo metu
duomenys keiiami vietomis.

int Keliones::Raktas(kelione A, kelione B);


Palyginami dviej kelioni A ir B duomenys. Jeigu B kelions trukm
maesn u A arba, kai trukms vienodos, B kelions kaina yra didesn
u A kelions kain, tai grinama reikm 1 (reikia sukeisti vietomis
A su B), kitaip grinama reikm 0.

void Keliones::Rinkti();
ia keliautojo paklausiama didiausia galima kelions kaina ir
ilgiausia galima trukm. I srao P atrenkami tinkami duomenys ir
suformuojamas naujas sraas K. Sraas formuojamas steko principu.
Naudojama funkcija Padeti.

void Keliones::Naikinti(sar *P);


Funkcija paalina sra P i atminties.

160

sar *Keliones::GetP() { return P; };


Grina vis duomen srao pradios rodykl P.

sar *Keliones::GetK() { return K; };


Grina atrinkt duomen srao pradios rodykl K.
Programos tekstas

#include
#include
#include
#include
#include

<iostream.h>
<stdio.h>
<stdlib.h>
<conio.h>
<string.h>

struct kelione { char tipas[10];


char vieta[10];
int trukme;
int kaina; };
typedef struct sar { kelione S;
sar *sek; };
//
Klass Keliones apraas
class Keliones {
sar *P;
// Vis kelioni srao pradia
sar *K;
// Atrinkt kelioni sraas
public:
Keliones() { P= NULL; K= NULL; };// Konstruktorius
void Formuoti(FILE *);
// Formuoja sra
void Padeti(sar **, kelione);
sar *GetP() { return P; };
sar *GetK() { return K; };
void Spausdinti(sar *, FILE *); // Spausdina sra
void Rikiuoti(sar *);
// Rikiuoja
int Raktas(kelione, kelione);
// Rikiavimo raktas
void Rinkti();
// Atrenkami duomenys
void Naikinti(sar *);
// Srao alinimas
};
//
Pagrindin programa
void main() {
FILE *F;
Keliones A;
// Klass Keliones objektas
sar *T;
// Pagalbinis kintamasis
clrscr();
cout << "Programa darba pradejo\n\n";

161

F = fopen("Kelione.sar", "r");
if (F == NULL) {
cout << "Failo 'Kelione.dat' nepavyko atidaryti ";
exit(1); }
A.Formuoti(F);
fclose(F);
F = fopen("Kelione.rez", "w");
if (F == NULL) {
cout << "Failo 'Kelione.rez' nepavyko sukurti";
exit(1); }
fprintf(F, "Siulomu kelioniu sarasas\n\n");
T = A.GetP();
A.Spausdinti(T, F);
A.Rinkti();
T = A.GetK();
A.Rikiuoti(T);
fprintf(F, "Atrinktu kelioniu sarasas\n\n");
T = A.GetK();
A.Spausdinti(T, F);
fclose(F);
T = A.GetP();
A.Naikinti(T);
T = A.GetK();
A.Naikinti(T);
cout << "Pabaiga. Rezultatai faile 'Kelione.rez'";

}
//
Elemento raymas
void Keliones::Padeti(sar **P, kelione N) {
sar *D = new sar;
D->S
= N;
D->sek = *P;
*P
= D;
}
//
Srao formavimas
void Keliones::Formuoti(FILE *F) {
kelione S;
do {
fscanf(F, "%s%i%10s%i", S.tipas, &S.trukme, S.vieta,
&S.kaina);
Padeti(&P, S); }

162

while(!feof(F));
}
//
Srao spausdinimas
void Keliones::Spausdinti(sar *P, FILE *F) {
sar *D = P;
int i = 1;
fprintf( F,"+----+------------+--------+------------");
fprintf( F,"+---------+\n" );
fprintf( F,"| Nr.| Keliones t.+ Trukme +
Vieta
");
fprintf( F,"+ Kaina +\n" );
fprintf( F,"+----+------------+--------+------------");
fprintf( F,"+---------+\n" );
while(D) {
fprintf( F,"| %2d | %10s | %6d | %10s | %6d |\n",
i++, D->S.tipas, D->S.trukme, D->S.vieta, D->S.kaina);
D = D->sek; }
fprintf( F,"+----+------------+--------+------------");
fprintf( F,"+---------+\n" );
fprintf( F, "\n\n\n");
}
//
Rikiavimo raktas
int Keliones::Raktas(kelione A, kelione B) {
return(B.trukme < A.trukme) ||
((B.trukme == A.trukme ) && (B.kaina > B.kaina));
}
//
Rikiavimas
void Keliones::Rikiuoti(sar *P) {
sar *R = P, *D;
kelione K;
while(R) {
D = R->sek;
while(D) {
if (Raktas(R->S, D->S))
{ K = R->S; R->S = D->S; D->S = K; }
D = D->sek; }
R = R->sek; }
}
//
Duomen atrinkimas
void Keliones::Rinkti() {
sar *D = P;
int Sk1, Sk2;
cout << "Kokia maksimali kaina ? ";
cin >> Sk1; cout << "\n";
cout << "Kokia maksimali trukme? ";

163

cin >> Sk2; cout << "\n";


while(D) {
if ((D->S.trukme <= Sk2) && (D->S.kaina <= Sk1))
Padeti(&K, D->S);
D = D->sek; }

}
//
Srao paalinimas
void Keliones::Naikinti(sar *P) {
sar *R = P, *D;
while(R) {
D = R;
R = R->sek;
delete(D); }
}

11.2. Uduotys
U1. Turime tekstiniame faile meteorologini stebjim rezultatus:
data, krituli pobdis, krituli kiekis.
Suformuoti sra:
krituli pobdis, bendras kiekis, vidurkis.
Sutvarkyti duomenis pagal krituli pobd ir krituli kiek. Ivesti tris
lenteles: duomen, sutvarkyt duomen ir skaiiavim rezultat.
U2. Turime tekstiniame faile darbuotoj iniarat:
pavard, adresas, darbo pavadinimas, data, dirbta valand.
Kitame tekstiniame faile turime darb vertinimo normatyvus:
darbo pavadinimas, valandos kainis.
Suformuoti atlyginim sra ir j sutvarkyti pagal atlyginimo dyd ir
pavard:
pavard, adresas, dirbtas valand kiekis, atlyginimas.
Ivesti tris lenteles: dvi duomen ir skaiiavim rezultat.
U3. Turime tekstiniame faile bibliotekos lankytoj sra:
pavard, vardas, skaitytojo bilieto numeris, knyg pamimo data,
paimt knyg kiekis, leistinas skaityti dien skaiius.
Suformuoti skaitytoj, kurie vluoja grinti knygas, sra, ir j sutvarkyti
pagal vlavim ir pavard:
pavard, vardas, skaitytojo bilieto numeris,
vluojamas dien skaiius, knyg kiekis.
Ivesti dvi lenteles: duomen ir skaiiavim rezultat.
164

U4. Turime tekstiniame faile student sra:


pavard, vardas, grups ifras, egzamin pavadinimai ir paymiai.
Suformuoti pirmn, kuri paymi vidurkis yra duotame intervale [a, b],
sra ir j sutvarkyti pagal grupes ir pavardes:
pavard, vardas, grups ifras, paymi vidurkis.
Ivesti dvi lenteles: duomen ir skaiiavim rezultat.
U5. Turime tekstiniame faile student sra:
pavard, vardas, grups ifras, vis egzamin paymiai.
Suformuoti sra:
pavard, vardas, grups ifras, paymi vidurkis.
J sutvarkyti pagal grups ifr ir paymi vidurk. Ivesti dvi lenteles:
duomen ir skaiiavim rezultat.
U6. Turime tekstiniame faile student sra:
pavard, vardas, grups ifras, vis egzamin paymiai.
Suformuoti sra:
pavard, vardas, grups ifras, kiek koki paymi turi.
J sutvarkyti pagal grups ifr ir paymi vidurk. Ivesti dvi lenteles:
duomen ir skaiiavim rezultat.
U7. Turime tekstiniame faile student sra:
pavard, vardas, grups ifras, vis egzamin paymiai.
Suformuoti sra:
pavard, vardas, grups ifras, mokymosi vidurkis.
J sutvarkyti pagal grups ifr ir mokymosi vidurk. Ivesti lenteles:
duomen ir skaiiavim rezultat, pirmn (mokosi vidurkiu >8) ir
atsiliekani (mokosi vidurkiu <6).
U8. Turime tekstiniame faile student sra:
pavard, vardas, grups ifras, vis egzamin paymiai.
Suformuoti sra:
pavard, vardas, grups ifras, atuntuk,devintuk ir deimtuk kiekiai.
J sutvarkyti pagal atuntuk, devintuk, deimtuk kiek. Ivesti lenteles:
duomen ir skaiiavim rezultat.
U9. Turime tekstiniame faile student darbo prie kompiuteri apskaitos
sra:
pavard, vardas, grups ifras, kompiuterio registracijos numeris,
data, darbo pradios laikas, darbo pabaigos laikas.

165

Suformuoti sra:
pavard, vardas, grups ifras, kompiuterio registracijos numeris,
data, darbo laikas minutmis.
J sutvarkyti pagal dirbt laik ir pavard. Ivesti dvi lenteles: duomen ir
skaiiavim rezultat.
U10. Turime tekstiniame faile student apskaitos sra:
pavard, vardas, stojimo Universitet data, vis egzamin paymiai.
Suformuoti sra:
pavard, vardas, kursas, atuntuk, devintuk, deimtuk kiekiai.
J sutvarkyti pagal deimtukus, devintukus, atuntukus. Ivesti dvi
lenteles: duomen ir skaiiavim rezultat.
U11. Turime tekstiniame faile student sra:
pavard, vardas, grups ifras, gimimo data, vis egzamin paymiai.
Suformuoti sra:
pavard, vardas, amius, kiek koki paymi turi.
J sutvarkyti pagal ami ir mokymosi vidurk. Ivesti dvi lenteles:
duomen ir skaiiavim rezultat.
U12. Turime tekstiniame faile viebuio gyventoj sra:
pavard, vardas, atvykimo data, ivykimo data, kaina u par.
Suformuoti sra:
pavard, vardas, atvykimo data, ivykimo data, mokestis.
Duomenis ir rezultatus sutvarkyti pagal atvykimo dat. Ivesti dvi lenteles:
duomen ir skaiiavim rezultat.
U13. Turime tekstiniame faile viebuio gyventoj sra:
pavard, vardas, atvykimo data, ivykimo data, paros kaina.
Suformuoti sra:
pavard, vardas, atvykimo data, gyventa par, mokestis
J sutvarkyti pagal gyvenimo trukm ir mokest. Ivesti dvi lenteles:
duomen ir skaiiavim rezultat.
U14. Turime tekstiniame faile viebuio gyventoj sra:
pavard, vardas, atvykimo data, gyventa par, paros kaina.
Suformuoti sra:
pavard, vardas, atvykimo data, ivykimo data, mokestis.
J sutvarkyti pagal pavardes ir vardus. Ivesti dvi lenteles: duomen ir
skaiiavim rezultat.
U15. Turime tekstiniame faile viebuio gyventoj sra:
pavard, vardas, atvykimo data, gyventa par, kambario tipas.
166

Kitame tekstiniame faile turime kainorat:


kambario tipas, paros kaina.
Suformuoti sra:
pavard, vardas, atvykimo data, ivykimo data, mokestis.
J sutvarkyti pagal mokest. Ivesti dvi lenteles: duomen ir skaiiavim
rezultat.
U16. Turime knyg sra:
autorius, pavadinimas, ileidimo metai, tiraas, kaina.
Suformuoti sra:
autorius, pavadinimas, ileidimo metai, tirao pinigin vert.
Sra sutvarkyti pagal ileidimo dat. Ivesti lenteles: duomen ir
skaiiavim rezultat.
U17. Turime tekstiniame faile viebuio gyventoj sra:
pavard, vardas, atvykimo data, gyventa par, kambario tipas.
Kitame tekstiniame faile turime kainorat:
kambario tipas, kaina, gyvenimo kaina,
buitini paslaug kaina, pelno procentas.
Suformuoti sra:
pavard, vardas, atvykimo data, gyventa par, mokestis.
J sutvarkyti pagal atvykimo dat. Ivesti dvi lenteles: duomen ir
skaiiavim rezultat.
U18. Turime sra:
detal, pagaminimo data, kiekis.
Kitame tekstiniame faile turime kainorat:
detal, gamybos ilaid kaina, pelno procentas.
Suformuoti sra:
detal, pardavimo kaina, kiekis.
J sutvarkyti pagal kain ir kiek. Ivesti dvi lenteles: duomen ir
skaiiavim rezultat.
U19. Turime sra:
detal, pagaminimo data, kiekis.
Kitame tekstiniame faile turime kainorat:
detal, mediag kaina vienete, darbo snaudos vienetui,
kitos papildomos ilaidos vienos detals gamybai.
Suformuoti sra:
detal, kiekis, pardavimo kaina, priskaiiuotas atlyginimas.
J sutvarkyti pagal kiek ir atlyginim. Ivesti dvi lenteles: duomen ir
skaiiavim rezultat.
167

U20. Turime sra:


detal, parduotas kiekis, pardavimo data.
Kitame tekstiniame faile turime kainorat:
detal, kaina.
Suformuoti sra:
detal, pardavimo data, pardavimo kaina, suma.
J sutvarkyti pagal dat ir kain. Ivesti dvi lenteles: duomen ir
skaiiavim rezultat.
U21. Turime sra:
prek, gautas kiekis, parduotas kiekis, pardavimo data.
Kitame tekstiniame faile turime kainorat:
prek, kaina.
Suformuoti sra:
prek, likutis, pardavimo kaina, pajamos.
J sutvarkyti pagal kain ir pajamas. Ivesti dvi lenteles: duomen ir
skaiiavim rezultat.
U22. Turime sra:
prek, pagaminimo data, vartojimo laikas.
Suformuoti sra:
prek, pagaminimo data, vartojimo laikas, vartojimo pabaigos data.
J sutvarkyti pagal pagaminimo dat ir pavadinim. Ivesti dvi lenteles:
duomen ir skaiiavim rezultat.

168

169

You might also like