60
- 1 - Vilniaus kolegija Elektronikos ir informatikos fakultetas Programavimas C kalba Parengė: lekt. Mindaugas Liogys

Programavimas C kalba

Embed Size (px)

Citation preview

Page 1: Programavimas C kalba

- 1 -

Vilniaus kolegija

Elektronikos ir informatikos fakultetas

Programavimas C kalba

Parengė: lekt. Mindaugas Liogys

Page 2: Programavimas C kalba

- 2 -

Page 3: Programavimas C kalba

- 3 -

1. I-OJI PASKAITA: Pradinės sąvokos

1.1. C programavimo kalbos ypatybės

• Gerai išvystyta aukšto lygio programavimo kalba.

• Dauguma (vos ne visos) komercinės programos parašytos būtent C arba C++ kalba. De facto tai pramoninių

programų rašymo standartas

• Kada atsirado C kalba? 1969 metais išleista C kalbos pirma versija. Sukurta kaip sudėtinė UNIX operacinės sistemos

dalis. Vėlesnės UNIX versijos parašytos C kalba

• Kodėl pavadinta C? Buvo dvi ankstesnės versijos – A ir B, bet jos buvo nevykusios. Iš trečio karto pasisekė sukurti

pasisekusią programavimo kalbą. Todėl ir pavadinimas C.

• C – tai nepriklausoma nuo mašinos tipo procedūrinė programavimo kalba

• Koks skirtumas tarp C ir C++? C++ – tai objektinis procedūrinės programavimo kalbos C poaibis

• Kokias programas galima parašyti naudojant C/C++?

1.2. Programavimo kalbų klasifikacija

• Kas yra kalba ? Ar pvz. matematika kalba ?

• Kokios kalbos yra natūralios ir kokios dirbtinės ?

• Kodėl programos nerašomos natūralia kalba ? Kas nulėmė tokią programavimo kalbų struktūrą kokia yra dabar ?

• Ţemo lygio programavimo kalbos:

• - mašininiai kodai

• - asembleriai (ypatybės ?)

• Aukšto lygio programavimo kalbos:

• -procedūrinės: Fortran, Pascal, C

• -interpretatoriai: Basic

• objektinės: C++, Java, Delphi (ypatybės ?)

1.3. Programavimo priemonių rinkinys

• Ką reikia turėti norint parašyti veikiančią programą ?

Trys pagrindiniai komponentai:

Redaktorius – tam, kad parašyti programos išeities kodą. Tinka bet koks redaktorius (pvz. Notepad), bet daţniausiai

naudojami specializuoti

Kompiliatorius – tam, kad parašytą programos kodą paversti į mašininius kodus, taip vadinamą objektinį modulį

Linkeris – kad prie objektinio modulio prijungti kitus objektinius modulius, bibliotekose surinktą kodą ir gauti

vykdomąją programą.

• Šiuolaikinėse sistemose daţniausiai naudojamos integruotos sistemos, apjungiančios visus tris komponentus

• Vis daţniau naudojamas vizualinis programavimas. Tačiau sunkiausią dalį programuotojas vis tiek turi padaryti pats

1.4. C kalbos programavimo priemonės

Yra sukurta daug programavimo priemonių rašyti programas C kalba:

Nemokamos: gcc kompiliatorius, Mars C, lcc ir t.t.

Komercinės: Microsoft C, Borland C, Symantec C ir t.t.

Įprastinės: Turbo C, Borland C, Symantec C

Vizualinio programavimo: Microsoft Visual C, Borland C Builder

• Kurios geriausios ? Tos, prie kurių labiausiai esi pripratęs ir gali greičiausiai pasiekti reikiamą tikslą.

1.5. Programos leksika ir sintaksė

• Programą, parašytą C kalba, sudaro vienas arba keli failai

• Kiekvieną failą sudaro funkcijų ir kintamųjų bei veiksmų su jais aprašymas

• Leksiškai programa susideda iš bazinių arba raktinių ţodţių (angl. keywords) specialių ţenklų, identifikatorių,

konstantų ir komentarų

• C kalboje naudojamos tiek didţiosios, tiek maţosios raidės, tačiau yra priimta eilė neoficialių susitarimų, kurių

pravartu laikytis

Page 4: Programavimas C kalba

- 4 -

1.6. Kintamieji ir konstantos

• Duomenys, kuriuos apdoroja kompiuteris – tai konstantos ir kintamieji

• C kalboje visi kintamieji turi būti aiškiai aprašyti

• Kintamojo aprašymas – tai jo tipo specifikavimas, kintamojo vardo uţdavimas, eilė neprivalomų modifikatorių, kurie

apibrėţia vidines kintamojo vaizdavimo ypatybes arba jo saugojimo klasę.

• Aprašant kintamąjį galima nurodyti jo pradinę reikšmę

• Identifikatorius – tai seka raidţių arba skaičių, kurie prasideda raide arba pabraukimo ţenklu _

• Kintamojo vardas – tai identifikatorius . Vardas gali būti bet kokio ilgio, bet tik pirmi 32 simboliai bus reikšminiai

1.7. Kintamųjų tipai

• Tipas – bet kuriai programavimo kalbai fundamentali sąvoka

• C kalboje skiriami 4 kategorijų tipai

• Tuščias tipas (void)

• Skaliarinis tipas:

– aritmetiniai tipai

– išvardijimai (enumerations)

– rodikliai (pointers)

– nuorodos (references)

• Tipas funkcija

• Agreguotas tipas:

– masyvai (arrays)

– struktūros ir sąjungos

– klasės (tik C++ poaibyje)

• Kitaip kintamieji gali būti skirstomi į :

– pagrindinius

– išvestinius

• Pagrindiniai tipai C kalboje yra:

void char int float double

ir jų variantai su raktiniais žodžiais

short long signed unsigned

• Išvestiniai tipai:

– rodikliai ir nuorodos į kitus duomenų tipus

– funkcijos

– struktūros ir sąjungos

– klasės

1.8. Duomenų tipas int

• C kalboje duomenų tipas int (integer, integral ?) savyje apjungia duomenų tipus char, short, long

• Pats duomenų tipas int yra bazinis ir priklauso nuo operacinės sistemos skiltiškumo: jo dydis lygus operacinės

sistemos adresavimo skiltiškumui (16 bitų Win16, 32 bitai Win32, ateityje 64 bitai ?)

bitai min max

Char 8 -128 127

unsigned char 8 0 255

short int 16 -32768 32767

Int 16 -32768 32767

unsigned int 16 0 65535

Long 32 -2147413648 2147483647

unsigned long 32 0 4294967295

Page 5: Programavimas C kalba

- 5 -

1.9. Sveiko tipo konstantos

• Sveiko tipo (int) konstantos gali būti uţrašomos dešimtaine, aštuntaine arba šešioliktaine sistema:

• 15,5,65,156,253

• 015,05,065,0156,0253

• 0x15,0x5,0x65,0x156,0x25af

• Dešimtainės konstantos paprastoje formoje suprantamos kaip short int kintamieji.

• Jeigu reikia uţrašyti didesnius kintamuosius, reikia naudoti tipo modifikatorius U(u) – unsigned arba L(l) – long

• Pvz.: negalima rašyti 40156 , 1256789, -35674 ir t.t.

• Reikia rašyti 40156u, 1256789l, -35674l ir t.t.

• Galima naudoti tiek U ir L, tiek u ir l

1.10. Slankaus kablelio konstantos

• Sveikais tipais negalima aprašyti trupmeninių skaičių: reikia naudoti slankaus kablelio tipus

• C kalboje naudojami trys slankaus kablelio duomenų tipai: float, double, long double

bitai min max tikslumas

float 32 3,4*10-38 3.4*1038 7

double 64 1.7*10-308 1.7*10308 15

long double 80 3.4*10-4932 3.4*104932 19

1.11. Kintamųjų aprašymo pavyzdžiai

Keli kintamųjų aprašymo pavyzdžiai:

• int i;

• signed short a; unsigned short k;

• short a, b=125, abcd=0xabcd;

• unsigned char b1=156;

• float bb, c=0.0,z=1.e-5;

• double pi=3.1415928;

• long double c1; double _z1erw=123.4561;

1.12. Priėjimo modifikatoriai const ir volatile

• Neprivalomi modifikatoriai padeda apibrėţti kintamuosius, kurie programos vykdymo metu gali arba negali pakeisti

savo reikšmes

• const – negali

• volatile – gali (naudojamas pagal nutylėjimą)

• Pvz: const int max_const=32767;

• Naudojama, kuomet norima apsidrausti, kad programos vykdymo metu netyčia nebūtų pakeista reikalinga kintamojo

reikšmė

1.13. Komentarai

• C/ C++ kalboje komentarus galima įterpti dviem būdais:

1) /* ..... */ - komentarai rašomi tarp slešo ir ţvaigţdės ir ţvaigţdės ir slešo. Komentarų kiekis neribojamas

2) // po dviejų slešų visa eilutė iki galo traktuojama kaip komentarai

Pvz. /* aš čia dabar rašau komentarus

kiek noriu tiek rašau. ir čia komentaras int a/c;

dabar baigiu */

int a; // o dabar komentarai , int a – čia irgi komentaras

Page 6: Programavimas C kalba

- 6 -

1.14. Gero stiliaus reikalavimai

Naudoti prasmingus pavadinimus globaliniams kintamiesiems ir trumpus pavadinimus – lokaliniams

Patartina globalinių kintamųjų aprašymus paydėti trumpu komentaru

• Pvz: int npending=0; // ivedimo srauto einamas ilgis

• Pvz: numberOfPoints – globalinis kintamasis

• nPoints – tiek globalinis, tiek lokalinis

• n –lokalinis kintamasis

Egzistuoja daug susitarimų ir vietinių tradicijų kaip reikėtų parinkti pavadinimus kintamiesiems įvairiose sistemose ir

uţdaviniuose

Būkite nuoseklūs: panašios kilmės objektams reikėtų parinkti atitinkamus pavadinimus, parodančius jų

panašumus ir skirtumus

Būkite tikslūs: vardas reiškia ne tik objektą, bet ir jo prasmę !!!

1.15. Operacijos ir išraiškos

Išraiška – tai seka operandų, operacijų ir skiriamųjų ţenklų.

Skiriamieji simboliai: [ ] { } , ; : ... * = #

Išraiškas kompiliatorius interpretuoja grieţtai besilaikydamas vyresniškumo taisyklių

Vyresniškumo taisyklės kaip matematikoje priimtos

1.16. Pagrindinės operacijos: aritmetinės operacijos

Tipinės operacijos:

• Sumavimo operacija +

• Atėmimo operacija –

• Daugybos operacija *

• Dalybos operacija /

C kalbos specifinės operacijos:

• Liekanos nustatymo operacija %

• Inkremento operacija ++

• Dekremento operacija --

1.17. Pagrindinės operacijos: poskiltinės loginės operacijos

• Vadinamos poskiltinėmis todėl, kad loginiai veiksmai atliekami su kiekviena kintamojo arba konstantos skiltimi atskirai

• Yra keturios:

• & - loginis IR (AND operacija)

• ^ - poskiltinis sumavimas moduliu 2 (XOR operacija)

• | - loginis ARBA (OR operacija)

• ~ poskiltinė inversija

1 operandas 2 operandas AND OR XOR

0 0 0 0 0

1 0 0 1 1

0 1 0 1 1

1 1 1 1 0

1.18. Pagrindinės operacijos: postūmio operacijos

• Poskiltinio postūmio operacijos:

>> - postūmis dešinėn

<< - postūmis kairėn

Pvz: half = addr>>1;

double = addr<<1;

Pvz: 5 - > 101 <<1 -> 1010 -> 10

12 -> 1100>>1 -> 110 -> 6

3 -> 11 <<3 -> 11000 -> 24

Priskyrimo operacija =. Pvz. a=b;

Page 7: Programavimas C kalba

- 7 -

1.19. Pagrindinės operacijos: loginės operacijos ir santykio operacijos

Santykio operacijos:

• > - daugiau

• < - maţiau

• == - tapačiai lygu

• >= - daugiau arba lygu

• <= - maţiau arba lygu

• != - nelygu

• Teisinga, jei operandas iš kairės tenkina sąlygą

Loginės operacijos:

• && - loginis IR

• || - loginis ARBA

• ! – loginis NE

• Šios operacijos naudojamos sudarant logines išraiškas, turinčias tik dvi reikšmes: 1, jei išraiška teisinga ir 0, jei

išraiška neteisinga

1.20. Sąlygos operacija ? :

• Sąlygos operacija ? : apibrėţiama kaip:

cond ? TRUE_statement : FALSE_statement

• Pvz:

int a=4, b=3;

int i;

i=a>b ? a: b;

1.21. Duomenų tipų nurodymo operacija (kastingavimas)

• C kalboje duomenų tipus (operandų tipus) galima nurodyti aiškiai

• Toje operacijoje kintamasis bus traktuojamas kaip nurodyta privedimo operacijoje

• C++ operuojant su skirtingo tipo operandais duomenų tipus būtina kastinguoti

• Kintamasis įgis nurodytą tipą tik duotoje operacijoje;

pvz.: int a=8,b=5;

float var1,var2;

var1=a/b; // var1=1.0;

var2=(float)a/b; // var2=1.6;

var2=(float)a/(float)b; // var2=1.6;

1.22. Minimali programa C kalba

• int main() { }

• int main()

{

}

• int main(

)

{}

Pastabos: failo pavadinimas baigiasi plėtiniu .c arba .cpp

Tarpus kompiliatorius ignoruoja

Orientuotas į leksemas, o ne pozicijas faile

1.23. Pirmos programos pavyzdys

#include <stdio.h>

int main() {

unsigned int count;

count=1;

printf(―Hello world !!! \n count=%d‖,count ); }

Rezultatas: Hello world !!! count=1

Page 8: Programavimas C kalba

- 8 -

2. II-OJI PASKAITA

2.1. Bazinio įvedimo/ išvedimo metodai

• Skirtingi metodai naudojami konsoliniame įvedime/išvedime ir programose su langais

• Čia kalbame apie konsolinį I/O

• C++ turi savus operatorius, C specialių operatorių neturi

• Naudojamos bibliotekinės funkcijos

• Kas yra biblioteka, kas yra funkcija ?

• Standartinė įvedimo / išvedimo biblioteka:

• #include <stdio.h>

• Konsolinio įvedimo / išvedimo biblioteka

• # include <conio.h>

2.2. Formatuotas išvedimas

• Pavadinimas: printf()

• Sinopsė:

• #include <stdio.h>

• int printf(const format[,arg]…)

• Aprašymas: į standartinį išvedimo įrenginį (koks įrenginys yra standartinis ?) išveda nurodytą duomenų srautą,

sutinkamai su nurodytu formatu format: tai gali būti literaliniai simboliai ir transformavimo specifikatoriai:

• %d – dešimtainis sveikas skaičius

• %f - slankaus kablelio skaičius

• %o - aštuntainis skaičius be ţenklo

• %x - šešioliktainis skaičius be ţenklo

2.3. Formatuotas išvedimas

• Pavadinimas: printf()

• Sinopsė:

• #include <stdio.h>

• int printf(const format[,arg]…)

• Aprašymas: į standartinį išvedimo įrenginį (koks įrenginys yra standartinis ?) išveda nurodytą duomenų srautą,

sutinkamai su nurodytu formatu format: tai gali būti literaliniai simboliai ir transformavimo specifikatoriai:

• %d – dešimtainis sveikas skaičius

• %f - slankaus kablelio skaičius

• %o - aštuntainis skaičius be ţenklo

• %x - šešioliktainis skaičius be ţenklo

Pavyzdţiai:

• printf(―iveskite varda:‖);

• printf(―turimas akciju skaicius %d\n‖,num);

• printf(―\n sio menesio %2d diena nupirkta %3d akciju\n‖,diena, num);

• printf(―vieneto kaina %f‖, kaina);

• printf(―vieneto kaina %4.2f bendra kaina %6.2f\n‖,kaina, total);

• printf(―vienetu skaicius %d vieneto kaina %4.2d bendra kaina %6.2f\n‖,kiekis, kaina, total);

• printf(― | vienetu skaicius %d vieneto kaina %4.2d bendra kaina %6.2f | \n‖,kiekis, kaina, total);

2.4. Konsolinis įvedimas

• Pavadinimas: scanf()

• Sinopsė:

• #include <stdio.h>

• int scanf(const format[,arg]…)

• Aprašymas: iš standartinio įvedimo įrenginio (koks įrenginys yra standartinis ?) nuskaito nurodytą duomenų

srautą, sutinkamai su nurodytu formatu format:

• %d – dešimtainis sveikas skaičius

• %f - slankaus kablelio skaičius

• %o - aštuntainis skaičius be ţenklo

Page 9: Programavimas C kalba

- 9 -

• %x - šešioliktainis skaičius be ţenklo

• %c - simbolis

• scanf(―%d‖, &num);

• scanf(―%f‖,&price);

• scanf(―%d %d‖,&diena, &num);

• scanf(―%4.2f %6.2f‖,&kaina, &total);

• scanf(―%d %f %f‖,&kiekis, &kaina, &total);

• scanf(―%c‖,&raide);

• scanf(―%d‖,a[i]);

• scanf(―%s‖ pavadin);

2.5. Simbolinis įvedimas/ išvedimas

• Pavadinimas: getchar – įvedimo funkcija

• Sinopsė:

• #include <stdio.h>

• int getchar(void)

Aprašymas: nuskaito ir graţina eilinį simbolį iš standartinio nuskaitymo įrenginio

Diagnostika: graţina EOF simbolį, jeigu pasiektas failo galas arba klaidos simbolį, įvykus įvedimo klaidai. Visais kitais

atvejais graţina nuskaitytą simbolį

• Pavadinimas: putchar – išvedimo funkcija

• Sinopsė:

• #include <stdio.h>

• int putchar(int c)

Aprašymas: išveda eilinį simbolį į standartinį išvedimo įrenginį

Diagnostika: graţina išvestą simbolį, jeigu išvedimas atliktas sėkmingai, priešingu atveju graţina EOF simbolį.

• Pavyzdţiai

#include <stdio.h>

int main() {

int c;

c=getchar(); /* nuskaito simboli ir priskiria ji kintamajam c */

putchar(c);

putchar(‗m‘);

putchar(‗\t‘);

putchar(‗\007‘);

}

2.6. Skaičiavimo proceso valdymo operatoriai

• Skaičiavimo procesas – tai programos operatorių vykdymo seka

• Paprastai programos operatoriai vykdomi elės tvarka: iš viršaus į apačią, iš kairės į dešinę

• Kartais normalią veiksmų vykdymo seką reikia pakeisti

• Kam reikia pakeisti valdymo seką ? Uţdavinio sprendimas reikalauja

• Naudojami specialūs operatoriai – skaičiavimo proceso valdymo operatoriai

• Šakojimosi operatoriai, sąlygos operatoriai, ciklo operatoriai

• if, if-else, while, do while, switch – case - break, for, break, continue, goto, return

2.7. Operatorius if

• Šakojimosi operatoriai išrenka programoje galimą proceso tąsą iš eilės alternatyvų

• C kalboje yra du šakojimosi operatoriai – if ir switch

• if – paprasčiausias sąlygos operatorius

• if operatoriaus apibrėţimas:

if(cond_expression) TRUE_statement;

• cond_expession – sąlygos išraiška

• TRUE_statement – išraiška, kuri vykdoma jei sąlyga teisinga

Page 10: Programavimas C kalba

- 10 -

• Pavyzdţiai:

• if(x>largest) largest=x;

• if( val<min || val>max) {

printf(“reiksme %d iseina uz leidziamo diapazono ribu\n”,val);

printf(“leidziamas diapazonas %d %d\n”, min, max); }

• if(num<0) num=-num;

• c=getchar();

if(c==„\n‟) lines+=1;

• ekvivalentinis if((c=getchar()) ==„\n‟) lines+=1;

• neekvivaletinis if(c=getchar()==„\n‟) lines+=1;

2.8. Operatorius if-else

if ir else – raktiniai žodžiai

• Jeigu išraiška teisinga – vykdoma pirmoji išraiška, jeigu išraiška neteisinga – pirmoji išraiška praleidţiama ir

vykdoma antroji išraiška

• Tiek pirmoji, tiek antroji išraiškos gali būti paprastos arba blokinės

• Apibrėţimas:

• if(cond_expression) True_statement;

else False_statement;

• cond_expession – sąlygos išraiška

• TRUE_statement – išraiška, kuri vykdoma jei sąlyga teisinga

• FALSE_statement – išraiška, kuri vykdoma, jei sąlyga neteisinga

Pavyzdžiai

• if(kiekis<100) printf(―atsargu kiekis mazas‖);

else printf(―atsargu kiekis pakankamas‖);

• if(x!=0)

y=y/x;

else {

printf(―klaida: dalyba is nulio‖);

y=0; }

• if(hour>=3 && hour<17)

rate*=1.02;

else if(hour>=17 && hour<23)

rate*=1.01;

else rate*=0.99;

Pastaba: operatoriai if-else yra inkliuzyviniai: į vieną if-else operatorių galima įstatyti kitą.

Inkliuzyvų kiekis neribojamas

2.9. Else atskyrimo problemos: klaidų šaltinis

• if(c>‘ ‗)

if(c>=‗0‘ && c<=‗9‘)

digits+=1;

else

count+=1;

• Kuriam if priskiriamas else ?

• if(c>‘ ‗)

{

if(c>=‗0‘ && c<=‗9‘)

digits+=1;

}

else

count+=1;

Page 11: Programavimas C kalba

- 11 -

2.10. Operatoriai switch-case- break

• Daţnai pasitaikantis programavimo uţdavinys: išrinkti vieną alternatyvą iš daugelio galimų variantų

• Tai patogu atlikti naudojant switch-case operatorių

• Operatoriaus sintaksė:

switch(switch_expression) {

case const1: statement1; [break;]

case const2: statement2; [break;]

....

case constn: statementn; [break;]

[default: statemnt n+1;]

}

• Iliustracija

• input=getchar();

switch(input) {

case „d‟: z=z*5;

case „a‟:

case „A‟: z-=1; break;

case „p‟:

case „P‟: z+=1; break;

default: printf(“neteisingas pasirinkimas\n”);

break;

}

2.11. Ciklo operatoriai

• Ciklas – tai tų pačių veiksmų pakartojimas nurodytą skaičių kartų

• C kalba turi tris ciklo uţrašymo formas:

• while(cond_expression) operators;

• do operators while(cond_expression);

• for(init_expr; cond_expr; incr_expr) operators;

• Kuri uţrašymo forma geriausia ? Priklauso nuo konkrečių sąlygų

• Visomis uţrašymo formomis galima uţrašyti bet kurį ciklą

2.12. Besąlyginio perėjimo operatoriai

• Yra keturi besąlyginio perėjimo operatoriai C kalboje: break, continue, goto, return

• Besąlyginio perėjimo operatoriai – sutikus tokį operatorių programos valdymas automatiškai perduodamas į apibrėţtą

vietą

• break – išeina iš duoto bloko ir tęsia vykdymą iš karto nuo sekančio operatoriaus uţ bloko

• continue – naudojamas cikle, automatiškai pereina prie sekančios ciklo iteracijos

• return – grįţta iš funkcijos. valdymas perduodamas į funkcijos iškvietimo tašką

• goto label – valdymas automatiškai perduodamas į programos tašką, kurį ţymi markeris label

2.13. Gero stiliaus reikalavimai

1) Formatuokite kodą taip, kad pabrėžti jo struktūrą

• Blogas formatavimas:

for(n++;n<100;n++) field[n++]=„\0‟;

*i=„\0‟; return(„\n‟);

• Geras formatavimas:

for(n++;n<100;n++)

field[n++]=„\0‟;

*i=„\0‟;

return „\n‟;

2) rašykite išraiškas natūralia forma: rašykite taip, kaip skaitytumėte

Blogai:

if(!(block_id<actblk) || !(block_id>=unblock))

Page 12: Programavimas C kalba

- 12 -

Gerai:

if((block_id>=actblk) || (block_id<unblock))

3) Naudokite skliaustelius, kad panaikinti neaIŠKUMUS

• Pavyzdys su kelintiniais metais

• leap_year= y%4==0 && y%100!=0 ||y%400==0;

• leap_year= ((y%4==0) && (y%100!=0)) ||(y%400==0);

4) Skaidykite sudėtingas išraiškas:

• Blogai: x+=(xp=(2*k<(n-m) ? c[k+1] : d[k--]));

• Gerai: if(2*k<n-m)

xp=c[k+1];

else

xp=d[k--];

x+=xp;

5) Būkite paprastesni: nereikia persistengti rašant labai įmantrias išraiškas:

• Blogai: subkey=subkey>>(bitoff>>3)<<3));

• Gerai: subkey=subkey>>(bitoff&0x7));

subkey>>=bitoff&0x7;

Absoliučiai mįslinga konstrukcija:

child=(!LC&&!RC)?0:!(LC?RC:LC);

Paprastai: if(LC==0 && RC==0)

child=0;

else if(LC==0)

child=RC;

else

child=LC;

6) Būkite atsargūs u pašaliniais efektais: ++ tipo operacijos turi pašalinius efektus: jos ne tik gražina reikšmę, bet ir

pakeičia operando reikšmę

• Blogai: str[i++]=str[i++]=„A‟;

(blogai, nes nėra apibrėţta ++ operacijos vykdymo tvarka)

• Gerai: str[i++]=„A‟;

• str[i++]=„A‟;

3. III-IOJI PASKAITA: Rodyklės. Nuorodos. Masyvai.

3.1. Rodyklės sąvoka

• Idėja panaudoti adresus – labai sena.

• Programose rašomose mašininiais kodais arba asembleriu daţnai sutinkamas uţdavinys – perkelti duomenis iš vieno

adreso į kitą

• Tokiose programose tai atliekama paprastai

• Aukšto lygio programavimo kalbose daţnai apie adresus negalvojama, o kai kuriose ir nėra jokių priemonių operuoti su

adresais

• C kalboje yra abiejų būdų komponentų: tiek darbui su adresais, tiek ir ne tiesioginio adresavimo galimybių

• Kas yra rodiklis? Kintamasis, kuriame saugomas adresas

• Apibrėţimas: kntamasis-rodiklis (arba tiesiog vadinama rodikliu) – ta kintamasis, skirtas adreso saugojimui atmintyje

• Kam naudojami rodikliai?

Kad efektyviai prieiti prie duomenų

Lanksčios programos parašymui

Kintamųjų, perduodamų į funkciją, reikšmių pakeitimui

Darbui su dinamiškai paskirstoma atmintimi

Priėjimui prie aparatinių kompiuterio resursų arba papildomų įrenginių

3.2. Rodyklės ir nuorodos C kalboje

• C kalboje apibrėţtos dvi specialios operacijos kintamųjų adresavimui per rodiklius

o operacija & - nuorodos (reference) operacija

o operacija * - rodiklio (pointer) operacija

Operacijos & rezultatas – tai objekto, kuriam taikoma i operacija, adresas

Operacija * – tai kreipinys į atminties ląstelę, kurios adresas saugomas tame objekte

Page 13: Programavimas C kalba

- 13 -

3.3. Rodiyklės aprašymas, inicializavimas ir naudojimas

• Kintamasis p aprašomas kaip rodiklis į sveiko tipo kintamąjį. Tai reiškia kad jame bus saugomas sveiko tipo kintamojo adresas

• int num1=3, num2=6, *p;

• Visi rodikliai turi būti inicializuoti

• p=&num1;

• Rodiklis p dabar ―rodys‖ į kintamąjį num1

• Dabar kintamąjį num1 bus galima adresuoti tiesiogiai, naudojant priskyrimo operaciją = , arba kaip rodiklį, naudojant operatorių *

3.4. Dar apie rodykles

• Svarbu prisiminti, kad ţenklas * - tai operatorius

• Kuomet jis naudojamas su dviem operandais (binarinis operatorius) – tai daugybos operatorius

• Kuomet jis naudojamas kaip unarinis operatorius – laikoma, kad tai rodiklis, nurodantis į ţenklą

• Negalima sumaišyti

• Sudėtingose išraiškose kartais gali būti painu suprasti kaip reikia perskaityti

• Pvz: p= a* *b *c **d;

3.5. Pratimai su rodyklėmis: operacijos & ir *

• Kas neteisinga ţemiau pateiktoje programoje

#iclude <stdio.h>

int main() }{

int num1=100, *p;

printf(“num1 is %d\n”,num1);

printf(“*p is %d\n”,*p);

}

Ar tokia programa bus sukompiliuota?

Ar bus įvykdyta ?

Kas bus išspausdinta ?

#include <stdio.h>

main() }{

int num1=3, num2=6;

int *p;

p=&num1;

printf(―%d\n‖,*p);

*p=20;

printf(―%d‖,*p);

printf(―%d\n‖,num1);

p=&num2;

printf(―%d\n‖,*p);

}

• 510 p ?

• 504 num2 6

• 500 num1 3

• 510 p 500

• 504 num2 6

• 500 num1 3

• 510 p 500

• 504 num2 6

• 500 num1 20

• 510 p 504

• 504 num2 6

• 500 num1 20

• Kas bus išvesta atlikus šitą programą

#include <stdio.h>

int main(){

int count=10,x;

int *ip;

ip=&count;

x=*ip;

printf(―count=%d, x=%d\n‖,count,x); }

• Kas bus išvesta atlikus šitą programą

#include <stdio.h>

int main(){

int i1,i2;

int *p,*q;

i1=5;

p=&i1;

i2=*q/2+10;

q=p;

printf(―i1=%d i2=%d‖,i1,i2);

printf(―*p=%d *q=%n‖,*p,*q); }

Page 14: Programavimas C kalba

- 14 -

3.6. Rodyklių aritmetika

• Svarbu aprašant rodiklius su teisingu duomenų tipu

• Naudojama padidinant / sumaţinant rodiklio reikšmę, palyginant rodiklius tarpusavyje, atimant vieną rodiklį iš kito ir

pan

• char *p;

• *p – tai simbolis

• p++ ekvivalentiška p=p+1

• short *p;

• *p – tai trumpas sveikas skaičius

• p++ - ekvivalentiška p=p+2

3.7. Masyvai

• Masyvas – tai eilės tvarka, vienas paskui kitą, atmintyje išdėstyti vieno ir to paties tipo elementai.

• Kiekvienas masyvas turi nuosavą unikalų pavadinimą

• Priėjimas prie masyvo elementų atliekamas naudojant masyvo pavadinimą ir elemento eilės numerį

• Pagrindinis masyvo privalumas: leidţia saugoti aibę elementų, aiškiai nenurodant kiekvieno iš elementų pavadinimų

• Masyvai gali būti vienmačiai arba daugiamačiai (dvimačiai, trimačiai, ir t.t. Kada pabaiga ?)

• Masyvo poţymis – kvadratinių skliaustelių buvimas šalia pavadinimo: char buffer[256]; int a[3]; ir t.t.

• Pagrindinės masyvų savybės C kalboje:

1) Visi masyvo elementai yra vieno ir to paties tipo

2) Aprašant masyvą nurodomas jo elementų tipas, masyvo pavadinimas ir bendras masyvo elementų skaičius

3) Pirmo masyvo elemento indeksas visada yra lygus 0, paskutinio n-1

4) Masyvo elementai į atmintį surašomi nuosekliai (pvz. 3 elementas atmintyje visada bus po 2)

5) Dvimačiai masyvai surašomi eilutėmis: pirmiausia pirmos eilutės elementai, po to antros ir t.t.

• Masyvo vardas yra rodiklis-konstantė (tiesiog rodiklis) ir visada lygus masyvo pradžios adresui

3.8. Masyvo inicializavimo būdai

• C kalboje numatyti du masyvų inicializavimo būdai:

• Inicializavimas pagal nutylėjimą: taikomas tik statiniams arba išoriniams masyvams

• Tiesioginė elementų inicializacija:

• char array[10]={„a‟,‟b‟,‟c‟,‟d‟,‟e‟,‟f‟,‟g‟,‟h‟,‟i‟,‟j‟};

• char array[]={1,2,3,4,5};

• char array[5]; array[0]=1; array[1]=2; array[2]=3;

• char array[10]; int i; for(i=0;i<10;i++) array[i]=i;

3.9. Nuorodos į masyvo elementus

• Darbas su atskirais masyvo elementais arba indekso, arba operacijos * pagalba

• Abu darbo su masyvo elementais būdai yra lygiaverčiai

• Naudojant indeksus

• masyvo_vardas[sveikaskaitinė_išraiška]

• Short a[15]; a[0]=5; a[2]=7; a[5]=a[0]+a[2]; a[7]=a[5];

• Naudojant rodiklius:

• short a[15]; *a=5; *(a+2)=7; *(a+5)=*a+*(a+2); *(a+7)=*(a+5);

3.10. Daugiamačiai masyvai

• C kalba palaiko ir daugiamačius masyvus

• Masyvo matiškumas – tai indeksų, naudojamų adresuojant masyvo elementą, skaičius

• Daugiamačių masyvų elementai saugomi atmintyje dešiniausio indekso didėjimo tvarka

• Dvimačio masyvo vardas yra rodiklis į rodiklių masyvą. Masyvo elementai yra rodikliai į kiekvienos eilutės pradţios

elemento adresą

• Matiškumų skaičius nėra ribojamas, praktiškai niekada nenaudojami didesni nei trimačiai masyvai

Page 15: Programavimas C kalba

- 15 -

3.11. Programos su masyvais pavyzdys

#include <stdio.h>

int main() {

const float investment=6000, interest=.085;

float rate; double value[5];

int year;

rate=1+interest; value[0]=investment; year=1;

while(year<5) {

value[year]=value[year-1]*rate;

year+=1; }

printf(―pradinis indelis %.2f\n‖,value[0]);

year=1;

while(year<5) {

printf(―metai %d: %.2f\n‖,year,value[year]);

year+=1; } }

3.12. Kelios pastabos apie masyvus

• C kalboje nėra atliekamas joks masyvų adresavimo korektiškumas

• Tai daţna klaidų prieţastis: adresuoti į tuos masyvų elementus, kurių pagal pradinį masyvo aprašymą paprasčiausiai

nėra

• Viena iš daugiamačių masyvų reto naudojimo prieţasčių – didesnis adresavimo sudėtingumas ir didesnė klaidų

tikimybė

short a[30]; for(i=0;i<30;i++) a[i]=i*i; //gerai

a[30]=a[29]; // blogai , tik 30 elementu galima

a[7*7]=a[5*5] // blogai

Visa atsakomybė uţ indeksų naudojimo teisingumą išimtinai priklauso programos autoriui

Jei adresuojama į masyvo elementą su didesniu indeksu, programa nulūţta

3.13. Masyvų kopijavimas

• Masyvai turi būti kopijuojami elementas po elemento

• Int prev[20],current[20];

• Neteisingai:

prev=current; // kompiliavimo klaida

• Teisingai:

i=0;

while(i<20) {

prev[i]=current[i];

i+=1; }

3.14. Inkremento ir dekremento operatoriai masyvuose

• Dėl savo patogumo ir efektyvumo inkremento/ dekremento operatoriai daţnai naudojami veiksmuose su masyvais

• Prefiksinė forma ++x, --x; postfiksinė forma x++,x—

• Prefiksinė forma – reikšmė pakeičiama nedelsiant, postfiksinė – reikšmė pakeičiama atlikus kitus veiksmus

• x=3; y=++x; // y? x?

• x=3; y=x++; // y? x?

• Pvz:

i=0; i=0;

while(<size) { => while(i<size) table[i++]=0;

table[i]=0;

i=i+1;

}

3.15. Simbolių masyvai

• Labai daţnai pasitaikantis uţdavinys: apdoroti tekstą (tekstinę informaciją)

• Tekstas kompiuterio poţiūriu – tai simbolių rinkinys. Bet mums reikia ne atskirų simbolių, o jų junginių

Page 16: Programavimas C kalba

- 16 -

• Kiekvienas teksto simbolis kaip ir masyvo elementas, nes visi elementai vienodo tipo

• Bet tokie masyvai specifiniai – tarpai, taškai, ir t.t. Kur pabaiga masyvo ?

• Daţnai iš anksto neţinomas teksto ilgis, daţnai būna kintamas

• Kitose kalbose (naujesnėse) simbolių sekų saugojimui yra skirti specialūs duomenų tipai, C to neturi

• Tokie duomenų tipai vadinami simbolių eilutėmis arba stringais

• Uţrašymas: simbolių eilutė – tai seka bet kokių simbolių, įtrauktų į dvigubas porines kabutes

• Simbolių eilutė C kalboje kompiuterio atmintyje saugoma kaip char tipo elementų masyvas, kurio pabaigoje yra

simbolis ‗\0‘ (null-terminatorius)

• Stringas – tai simbolių seka, pasibaigianti simboliu nul-terminatoriumi. Todėl jo ilgis visada vienetu didesnis negu

yra prasmingų simbolių !!!!!

• Daţnai pamirštama, kad stringui reikia išskirti vienetu daugiau, negu numatome saugoti simbolių. Aišku galima

rezervuoti ir dar daugiau atminties ląstelių.

3.16. Stringų aprašymai

• Aprašoma kaip ir char tipo duomenų masyvas:

• Ekvivalentiški aprašymai:

• char string[]=”eilute”;

• char string[7]=“eilute”;

• char string[7]={„e‟,‟i‟,‟l‟,‟u‟,‟t‟,‟e‟,‟\0‟};

• char *string=“eilute”;

Pastaba: svarbu suprasti, kad priskiriant eilutės reikšmę į rodiklio string atminties ląstelę persiunčiama ne visa eilutė, o tik

jos pirmojo elemento adresas. Todėl stringų, kaip ir kitų masyvų, negalima perkopijuoti prilyginant jų pavadinimus

3.17. Eilučių apdorojimas

• Veiksmams su simbolių eilutėmis yra parašyta daug standartinių funkcijų

• Reikia įtraukti header failą string.h, kad galėtume operuoti tomis funkcijomis

• #include <string.h>

• Keli pavyzdţiai:

• strcpy(src,dest) – perkopijuoti vieną eilutę į kitą

• strcmp(src,dest) – palyginti vieną eilutę su kita

• strcat(str1,str2) – prijungti vieną eilutę prie kitos

• Ir dar daug kitų funkcijų

Pavyzdys su stringais

#include <stdio.h>

int main() {

int i;

char first[11];

printf(“prasau ivesti varda:”);

i=0;

while(i<10 && (first[i]=getchar()) !=„\n‟)

i+=1;

first[i]=„\0‟;

printf(“ivestas vardas: %s\n”,first);

}

3.18. Masyvai kaip rodyklės

• Masyvų aprašymas su kvadratiniais skliausteliais paprastas ir patogus būdas tačiau turi trūkumų:

• Negalima rezervuoti didelių masyvų (didesnių negu 32676 elementai)

• Masyvo dydį reikia nurodyti iš karto ir negalima vėliau jo keisti (daţnai nelengva iškarto nustatyti kokio dydţio masyvo mums

reikės)

• Yra antras masyvų aprašymo būdas, neturintis tokių apribojimų – masyvų aprašymas per rodiklius:

• Pvz: short *a; long *b;

Tačiau kol kas nenurodytas masyvo dydis. Tą būtina padaryti !!!

Page 17: Programavimas C kalba

- 17 -

3.19. Masyvų dydžio nurodymas

• Naudojamos standartinės funkcijos, aprašytos header faile alloc.h:

• #include <alloc.h>

• Atminties rezervavimui naudojamos funkcijos malloc() ir farmalloc(), atminties atlaisvinimui naudojamos funkcijos

free() ir farfree().

• Atmintį atlaisvinti būtina, kai ji nėra reikalinga

• Reikalingos atminties dydis šiose funkcijose visada uţduodamas baitais . Todėl reikia pačiam apskaičiuoti reikalingą

baitų skaičių arba pasinaudoti komanda sizeof()

Masyvų dydţio nurodymo pavyzdys

• Reikia 100 elementų trumpų skaičių masyvo ir 300 elementų slankaus kablelio skaičių masyvo

• Pvz:

#include <alloc.h>

int main() {

short *a;

float *b;

a=malloc(200); // nes kiekvienas short tipo elementas 2 baitai

a=malloc(100*sizeof(short)); // arba taip

b=farmalloc(1200); // nes kiekvienas float elementas 4 baitai

b=farmalloc(300*sizeof(float)) // arba taip

……

free(a); farfree(b); }

3.20. Dinaminiai masyvai

• Aprašant masyvus kaip rodiklius galima pakeisti masyvui išskirtos atminties kiekį programos vykdymo metu

• Tam daţniausiai naudojamos funkcijos realloc() arba farrealloc();

• Dydis ir vėl nurodomas baitais

• Pvz: short *a;

a=malloc(10);

a=realloc(a,20);

• Pastaba: nepriklausomai nuo masyvo aprašymo būdo, masyvo elementus galima adresuoti abiem anksčiau nurodytais

būdais

4. IV-OJI PASKAITA: Funkcijos.

4.1. Bendros sąvokos apie funkcijas

• Kas yra funkcija ?

• Vieną funkcijos sąvoką ţinote iš matematikos. Ką reiškia funkcija matematikoje ?

• Programavime funkcija turi panašumų, bet turi ir daug esminių skirtumų

• Sąvoka paprogramė (subroutine) naudota daugelyje ankstyvųjų programavimo kalbų (pvz. Fortran, PL/1, Cobol ir

t.t.)

• Paprogramė – tai programos dalis , gebanti atlikti analogiškus veiksmus su skirtingais kintamaisiais

• Funkcija kiek platesnė sąvoka nei paprogramė

4.2. Funkcijos apibrėžimas

• Egzistuoja keletas funkcijos apibrėţimų

• Funkcija – tai operatorių grupė, atliekančių išbaigtą veiksmų seką. Į funkciją galimą kreiptis pagal pavadinimą,

perduoti jai argumentus ir gauti iš jos reikšmę

• Funkcija – tai logikai savarankiška programos dalis, turinti savo pavadinimą, kuriai gali būti perduodami parametrai

ir kuri gali graţinti reikšmę

• Pirmas apbrėţimas techniškesnis, antras – labiau atspindintis reikalo turinį

4.3. Funkcijos

• C kalba parašyta programa – tai iš esmės funkcijų rinkinys. Funkcijos išdėstytos bet kuria tvarka. Faktiškai funkcijos

gali būti išdėstytos keliuose failuose.

• C kalbos koncepcijoje numatyti visi paprogramių tipai: funkcijos ir procedūros

Page 18: Programavimas C kalba

- 18 -

• Funkcijos leidţia rašyti programą moduliniu būdu: kiekviena funkcija atlieką tam tikrą uţdavinį. Tokias programas

ţymiai lengviau skaityti

• Funkcijos leidţia išvengti analogiškų veiksmų dubliavimo

• Daugelis programų gali naudoti tas pačias funkcijas, todėl nereikia perrašinėti kiekvieną kartą.

4.4. Funkcijos aprašymas

Funkcijos aprašymo standartas atrodo taip:

• [duomenu_tipas] funkcijos_vardas(argumentu_sarasas) {

kintamuju aprasymai;

……. // funkcijos_kunas

operatoriai;

[return (israiska)];

}

[] – skliausteliuose pateikti neprivalomi funkcijos elementai

4.5. Funkcijos aprašymo paaiškinimas

• Laukas ―duomenų tipas‖ nurodo funkcijos graţinamos reikšmės tipą jeigu jis nėra nurodytas, pagal nutylėjimą

laikoma, kad funkcija graţina int tipo reikšmę. Jeigu lauke ―duomenų tipas‖ nurodytas raktinis ţodis void, tuomet

funkcija negraţina jokios reikšmės.

• Laukas ―funkcijos pavadinimas‖ – tai ypatingas rodiklio tipas, vadinamas rodikliu į funkciją. Jo reikšmė yra lygi

įėjimo į funkciją pradţios adresui. Funkcijos pavadinimas be to yra identifikatorius ir sudaromas pagal

identifikatoriams C kalboje keliamus reikalavimus.

• Laukas ―argumentų sąrašas‖ apibrėţia argumentus (kartais vadinami parametrais), perduodamus į funkciją.

Argumentų sąrašas gali būti sudarytas iš bet kokios duomenų tipų jų vardų kombinacijos. Argumentų skaičius

neribojamas. Argumentai tarpusavyje skiriami kableliais. Jeigu argumentai nenaudojami, sąraše rašomas ţodis void

4.6. Funkcijos prototipas

• C kalbos standartas reikalauja, kad dar iki pirmo funkcijos iškvietimo programoje būtų pateiktas funkcijos

apibrėţimas

• Toks pirminis funkcijos apibrėţimas vadinamas funkcijos prototipu.

• Prototipas praneša kompiliatoriui apie graţinamos reikšmės tipą, argumentų kiekį ir tipus.

• Po prototipo dedamas kabliataškis;

• Daţnai prototipai talpinami į atskirus failus, turinčius plėtinį .h ir vadinamus header-failais

• Standartinių funkcijų prototipai pateikti header failuose, kurie įtraukiami su direktyva include

4.7. Pirmas funkcijos pavyzdys

• Uţduotis: apskaičiuoti skritulio plotą, kai spindulys r=5,10,27

• Galima taip:

void main() {

int r1=5,r2=10,r3=27;

float s1,s2,s3;

s1=3.14159*r1*r1;

s2=3.14159*r2*r2;

s3=3.14159*r3*r3;

}

Funkcijos nenaudojamos

O galimą ta patį uţrašyti ir taip

float area(int r);

void main() {

int r1=5,r2=10,r3=27;

float s1,s2,s3;

s1=area(r1);

s2=area(r2);

s3=area(r3);

}

float area(int r) {

return(3.14159*r*r); }

Šiuo atveju laimėjimas atrodo nedidelis,

bet jei reikės atlikti tarkim 20 veiksmų

funkcijoje ?

Page 19: Programavimas C kalba

- 19 -

4.8. Formalūs ir aktualūs argumentai

• Kuomet aprašome funkcijos kūną, nurodome argumentų, kurie turėtų būti perduoti į funkciją, sąrašą.

• Šie argumentai vadinami formaliais, su jais veiksmai programos vykdymo metu nebus atliekami

• Kuomet iškviečiame funkciją, nurodome į funkciją perduodamų argumentų sąrašą.

• Šie argumentai (tiksliau – jų kopijos) programos vykdymo metu bus perduoti į funkciją ir su jais atliekami veiksmai.

Jie vadinami aktualiais argumentais.

• Privalo sutapti formalių ir aktualių argumentų tipai.

• Kompiliatorius pasirūpins, kad atitinkamas aktualus argumentas atsidurtų atitinkamo formalaus argumento vietoje.

4.9. Funkcijos iškvietimas

• funkcijos_vardas(argumentų sąrašas)

• Vykdymas perduodamas į funkciją

• Atliekami eilės tvarka funkcijos kūne aprašyti veiksmai

• Įvykdţius sugrįţtama į sekančią po funkcijos iškvietimo einančią operaciją

void intro(void);

int main() {

……

intro();

…..

}

void intro(void) {

printf(“pradedamas programos vykdymas\n”);

printf(“programos autorius jonukas\n”” }

4.10. Funkcijos argumentai

• Naudojami informacijos perdavimui į funkciją

• Į funkciją perduodamos reikšmės, o ne patys kintamieji

• Yra lokaliniai funkcijos kintamieji

• Iškviečiant funkciją reikia nurodyti tikslų jų skaičių, tipus, ir eilės tvarką

int main() {

float amount=250, interest=0.075;

print_growth(amount,interest);

printf(main: amount= %.2f\n‖,amount);

}

void print_growth(float val,float rate) {

val=1+rate)*val;

}

4.11. Tipų kastingavimas funkcijose

• Tipų kastingavimas naudojamas laikinam duomenų tipo pakeitimui

• Naudojamas aiškiam teisingo funkcijos tipo nurodymui

float func(float x);

void func1(int x);

int man() {

int x;

func((float)x);

funcą(x);

}

4.12. Duomenų perdavimas į funkciją

• Parametrų perdavimui į funkciją egzistuoja du stiliai:

1) funkcijų iškvietimas su reikšmių perdavimu (call-by-value);

2) funkcijų iškvietimas su kintamųjų adresų perdavimu (call-by-reference);

Page 20: Programavimas C kalba

- 20 -

• Iškvietimas su reikšmių perdavimu – tai kintamųjų reikšmių kopijų perdavimas į funkcijos kūną. Tai niekaip

neleidţia pakeisti kintamųjų reikšmes iškvietimo taške

• Iškvietimas su adresų perdavimu – tai kintamųjų adresų kopijų perdavimas į funkcijos kūną. Tokiu būdu mes galime

keisti reikšmes saugomas nurodytais adresais

4.13. Kintamųjų reikšmių perdavimo pavyzdys

void suma(int a,int b,int suma);

void main() {

int a=5,b=7,sum=5;

printf(―sum=%d\n‖,sum);

suma(a,b,sum);

printf(―sum=%d\n‖,sum);

}

void suma(int a,int b,int suma) {

suma=a+b;

}

void suma(int a,int b,int suma);

void main() {

int a=5,b=7,sum=5;

printf(―sum=%d\n‖,sum);

suma(&a,&b,&sum);

printf(―sum=%d\n‖,sum);

}

void suma(int *a,int *b,int *suma) {

*suma=*a+*b;

}

4.14. Keli pavyzdžiai

• Kas neteisinga šiame funkcijos aprašyme ?

int compute(int , int ){

int x;

double y;

..... }

Kas bus išspausdinta įvykdţius sekančią programą ?

void square(int val);

int main() {

int x=5;

square(x);

printf(―x lygu %d\n‖,x);

}

void square(int val) {

val=val*val:

printf(―%d\n‖,val); }

4.15. Steko reikšmė

• Stekas – ta atminties sritis, kurią vykdanti programa naudojama laikinam saugojimui;

• Kuomet iškviečiama funkcija, visi šios funkcijos argumentai patalpinami į steką, po to patalpinamos esamų registrų

reikšmės ir kiti parametrai

• Toks argumentų, registrų ir automatinių kintamųjų rinkinys, skirtas vienai funkcijai, vadinamas freimu.

• Jei iškviesta funkcija viduje iškviečią dar vieną funkciją, tai jai sukuriamas dar vienas freimas ir anksčiau steke buvę

parametrai perstumiami tolyn

• C kalba parašytoms programoms reikia daug steko, neretai stekas persipildo ir dėl to gali ―nulūţti‖ programa

4.16. Operatorius return

• Graţina reikšmę į iškviečiančią funkciją return išraiška;

• Nėra privalomas operatorius

Page 21: Programavimas C kalba

- 21 -

• Negraţina jokios reikšmės jeigu naudojama išraiška

return;

int main(){

int len=50, width=4, area;

area=area_rect(len,width);

printf(“plotas lygus %d\n”,area);

return 0; }

int area_rect(int l, in w) {

return l*w; }

4.17. Masyvai kaip funkcijos argumentai

• Į funkcija neperduodama viso masyvo kopija

• Perduodamas tik pirmo elemento adresas

• Per šį adresą funkcija gali prieiti prie masyvo elementų, juos modifikuoti.

void main() {

char current[30], target[0];

...

stringcopy(target,current);

... }

void stringcopy(char str1[], char str2[]) {

int i;

for(i=0; str2[i]!=‗\0‘;i++) str1[i]=str2[i];

str1[i]=‗\0‘;

}

4.18. Vienmačių masyvų perdavimas į funkciją

• Duoti du sveikų skaičių masyvai. Rasti kuriame iš jų yra daugiau teigiamų skaičių

• int n_posit(const int *a, const int n) {

int main() {

int i,n;

int a[50], b[50];

printf(“iveskite elementu skaiciu:”);

scanf(“%d”,&n);

printf(“iveskite elementus:”);

for(i=0;i<n;i++) scanf(“%d %d”,&a[i],&b[i]);

if(n_posit(a,n)>n_posit(b,n)

printf(“pirame daugiau teigiamu elementu);

else if ..

}

int n_posit(const int *a, const int n) {

int i, count=0;

for(i=0;i<n;i++) if(a[i]>0) count++;

return count; }

4.19. Stringų perdavimas į funkcijas

• Parašyti programą, kuri nustatytų kiek simbolių yra eilutėje

int string_elem(char *str);

void main() { char strp[256];

int elem;

printf(“iveskite simboliu eilute”);

gets(strp);

elem=string(elem);

printf(“stringe yra %d eleementu\n”,elem);

}

int string_elem(char *str) {

int elem;

for(i=0;str[i]!=„\0‟;i++)

elem++;

return(elem);

}

Page 22: Programavimas C kalba

- 22 -

4.20. Parametrų perdavimas į funkciją main

• Kai kada reikia perduoti parametrus į pagrindinę funkciją main

• tai naudoja pvz. archyvavimo programos, dirbančios iš komandinės eilutės

• [tipas] main(int argc, char **argv) {

funkcijos kunas

}

arba

• [tipas] main(int argc, char **argv, char **env) {

funkcijos kunas

}

4.21. Standartinės funkcijos

• Kiekvienoje C programų kūrimo sistemoje yra daug standartinių funkcijų

• Su visa eile standartinių funkcijų jau teko susitikti: printf, scanf

• Šios funkcijos yra sudėtos į bibliotekas, jų prototipai – į header-failus, kuriuos reikia įtraukti naudojant direktyvą

include

• Standartinės funkcijos sugrupuotos pagal tematiką į grupes, programuotojui reikėtų pasirūpinti reikalingų funkcijų

paieška

• Pats programuotojas taip pat gali kurti nuosavas funkcijų bibliotekas

4.22. Parametrų perdavimas į funkciją main

• Komandinės eilutės ţodţiai tai transformuotos į ASCII formatą simbolių sekos, atskirtos tarpais, uţduodamos

programos paleidimo metu

• Programos aplinka – tai seka ASCII simboliais išreikštų sekų, kuri tam prieinama programai, jos paleidimo metu

• Į funkciją perduodamų parametrų prasmė:

int argc – ţodţių skaičius komandinėje eilutėje

char **argv – rodiklis į rodiklių masyvą iš argc elementų. nulinis elementas – visada programos pavadinimas

char **env – rodiklis į kintamo dydţio masyvų rodiklį

Pavyzdys programos su argumentų perdavimu į funkciją main:

#include <stdio.h>

void main(int argc, char **argv) {

printf(“i programa perduota %d argumentu\n”,argc);

printf(“ perduoti duomenys irasyti faile %s\n”, argv[1]);

printf(“paleista programa vadinasi %s\n”, argv[0]);

}

4.23. Rekursinės funkcijos

• C kalba leidţia funkcijai iškviesti pačiai save.

• Funkcija, besikreipianti pati į save vadinama rekursija

• Kiekvienu atveju steke išskiriama atminties sritis saugoti kintmųjų kopijas ir kitus parametrus

• Klasika tapusi faktorialo skaičiavimo funkcija:

f(n) {

if(n) return n*f(n-1);

else return 1;

}

Page 23: Programavimas C kalba

- 23 -

5. V-OJI PASKAITA. Priešprocesorius. Grafika.

5.1. Kompiliacijos etapai

• Priešprocesorius (include failai)

• Išplėstinis Pradinis programos kodas

• programos kodas C kalba

• C kompiliatorius

• Kodas asemblerio kalba

• Asemblerio kompiliatorius

• Objektinis kodas

• Linkeris, objektų biblioteka

• Vykdomas kodas

5.2. Priešprocesorius

Praktiškai kartu su kiekvienu C kalbos kompiliatoriumi pateikiamas taip vadinama priešprocesorius (angl. preprocessor)

Priešprocesorius ieško jam skirtų direktyvų dar iki programos kompiliavimo pradţios ir atlieka veiksmus, kurių reikalauja

panaudotos direktyvos.

Priešprocesoriaus direktyvų vykdymas – tai atitinkamas programos išeities kodo sutvarkymas bet jokiu būdu ne

kompiliavimas, t.y. Programos kodo vertimas į mašinines komandas

Preišprocesorius – tai galinga priemonė, leidţianti pagerinti programos skaitymą

Visos priešprocesoriaus direktyvos pradedamos komanda #

5.3. Priešprocesoriaus apibendrinimas

• Tai pirmas kompiliavimo etapas

• Pranašumai:

Skaitymo patogumas

Programos palaikymo palengvinimas

Lankstumas

Mobilumas

• Direktyvos:

Pradedamos simboliu #

Gali būti bet kurioje programos vietoje, nors daţniausiai naudojamos pradţioje

5.4. Prešprocesoriaus priemonės

Priemonės:

• Komentarų pašalinimas

• Konstantų ir makrosų (arba makrokomandų) apibrėţimas

• Failų įtraukimas (file inclusion)

• Sąlyginė kompiliacija (conditional compilation)

5.5. Simbolinės konstantos

• Apibrėţus simbolinę konstantą, priešprocesorius pakeičia visas faile aptiktas nuorodas į šią konstantą jos faktine

reikšme

• Negalima pakeisti komentarų arba dvigubų kabučių

• Pvz. , jeigu programoje buvo apibrėţta simbolinė konstanta vardu MAXITEMS , visur, kur programoje

priešprocesorius aptiks tokiu vardu esančią konstantą, jis pakeis ją priskirta reikšme

• Reikšmė turi būti nurodyta aprašant simbolinę konstantą

• Simbolinės konstantos aprašymas:

#define identifikatorius eilutė-leksema

• Simbolinių konstančių pavadinimams

priimta naudoti tiktai didţiąsiąs

raides

#define TRUE 1

#define FALSE 0

#define MAXITEMS 500

int main() {

int i, found, val[MAXITEMS];

found=FALSE;

while(found==FALSE) {

….

if(i<MAXITEMS) { …

found=TRUE; } }

for (i=0;i<MAXITEMS;i++) … ;}

}

Page 24: Programavimas C kalba

- 24 -

5.6. Makrosai

• Makrosai (taip pat daţnai vadinami makrokomandomis) – tai trumpa programa, kuriai gali būti perduoti argumentai

• Sintaksė panaši kaip ir simbolinių konstantų, tačiau makrosuose egzistuoja eilė parametrų, einančių iš karto po

identifikatoriaus

• Tie parametrai gali būti argumentų pavadinimai

• Tarp identifikatoriaus ir atidarančio skliaustelio ( jokiu būdu negali būti tarpo

• Kuomet priešprocesorius išskleidţia makrosą, jis atitinkamoje vietoje įstato kodą su atitinkamais parametrais

5.7. Makrosų tęsinys

• Jeigu makrokomandos uţima daugiau negu vieną eilutę, reikia naudoti simbolį \ jų apjungimui

• Keliems sakiniams naudokite bloką

#define SWAP(A,B) { int temp; \

temp=A; \

A=B; \

B=temp; }

int main() {

int num1=30, num2=50;

if(num2>num1) SWAP(num1,num2);

}

• Leksemos makrokomandose gali būti apjungtos naudojant operatorių ##

• Makrososuose naudojami trigrafai – trijų simbolių sekos, kurios reiškia vieną simbolį

• Trigrafai naudojami norint surinkti simboliu, kurių nėra kai kuriose klaviatūrose:

• ??= # ??> } ??- ~

?? ( [ ??/ \

?? ) ] ??‘ ^

?? < { ??! |

#define WheatBread 0

#define RyeBread 1

#define WhiteBread 2

#define PumopernickeBread 3

#define Bread(x) x## Bread

int main() {

printf(―Value of WheatBread is %d\n‖, Bread(Wheat));

printf(―Value of RyeBread is %d\n‖, Bread(Rye));

printf(―Value of WhiteBread is %d\n‖, Bread(White));

printf(―%c\n‖, ‗??-‘);

}

5.8. Funkcijų ir makrokomandų palyginimas

• Greitaeigiškumas:

1) Makrosai greitesni, įterpiami atitinkamose vietose

2) Funkcijos lėtesnės, naudoja steką

• Vykdomos programos dydis:

1) Maţesnis, jei naudojamos funkcijos, kodas pasikartoja tik vieną kartą

• #define identifikatorius(arg[,arg],..)

eilutė-leksema

• Trumpa paprogramė, priimanti

argumentus

• Priimta naudoti didţiąsias raides

• Įtraukiami į kabutes, jei naudojami

kartu su operatoriais

#define SQUARE(X) ((X)*(X))

#define MAX(A,B) ((A)>(B) ? (A):B))

int main() {

int int1, int2;

int1=SQUARE(3);

int2=SQUARE(int1+1);

printf(―max=%d\n‖, MAX(int1,int2));

}

Kas isvesta bus ?

Page 25: Programavimas C kalba

- 25 -

• Kiti faktoriai:

1) Funkcijos gali sugraţinti reikšmę operatoriuje return, makrosai negali

2) Makrosai neleidţia rekursijos

3) Makrosai daţnai sudėtingesni programos derinimo metu

5.9. Failų įtraukimas

#include <filename.xxx>

#include ―filename.xxx‖

Į programą įtraukiama nurodyto failo kopija: aptikęs šią direktyvą priešprocesorius toje vietoje įdės nurodyto C kalba

parašyto failo kopiją

Daţnai naudojama header failų įtraukimui.

Header failai turi funkcijų prototipus

Gali būti naudojama ir bet kokių kitų programų failų įtraukimui į kompiliuojamą išeities programą

5.10. Naujo duomenų tipo pavadinimo apibrėžimas

• Komanda typedef – tai naujo, sinoniminio, pavadinimo suteikimas egzistuojančiam duomenų tipui

• typedef egzistuojantis_tipas naujas_tipas

• Naudojama skaitomumui ir mobilumui pagerinti

• Sintaksė analogiška kintamųjų aprašymui

• Rekomenduojama naudoti didţiąsias raides

typedef char BYTE;

typedef unsigned short USHORT;

typedef int WORD;

int main() {

BYTE input;

WORD buf[512];

USHORT a;

}

5.11. Sąlyginė kompiliacija

• #if, #else, #elseif, #endif, #ifdef, #ifndef -tai sąlyginės kompiliacijos direktyvos

• Leidţia sukurti keletą tos pačios programos versijų

• Kompiliuojama ta versija, kuriai patenkinamos uţduotos sąlygos

• Sąlygos paprastai uţduodamos naudojant direktyvą define

• Kai kuriais atvejais gali būti naudojamos kitos direktyvos

#define WINDOWS32

int main() {

#ifdef WINDOWS32

printf(― Programa skirta Win32 operacinei aplinkai\n‖);

#endif

#ifdef UNIX

printf(―programa skirta Unix operacinei aplinkai\n‖);

#endif

….. }

5.12. Kontroliniai pratimai

• Raskite klaidą šiame fragmente:

#define LINELEN 80;

int main() {

char line[LINELEN];

int x;

….

Kas padaryta neteisingai apibrėžiant makrosą

ISDIGIT:

#include <stdio.h>

#define ISDIGIT(C) return((C)>=„0‟ &&

(C)<=„9‟)

int main() {

int input, digits=0;

input=getchar();

if(ISDIGIT(input)) digits++;

Page 26: Programavimas C kalba

- 26 -

5.13. Darbas su grafika

• Informacija į standartinį išvedimo įrenginį (daţniausiai monitoriaus ekraną) gali būti išvedama dviem skirtingais

reţimais: tekstiniu ir grafiniu.

• Grafiniame reţime informacija išvedama taškais, tekstiniame – simboliais

• Bet kuriuo atveju išvedimas, ypač grafiniame reţime, labai priklauso nuo techninės įrangos

• Negalima padaryti universalių, nepriklausančių nuo aparatinės įrangos, išvedimo modulių.

• Todėl C kalboje nėra specialių grafikos apdorojimo metodų, o grafiniam išvedimui naudojamos standartinių

bibliotekų funkcijos

• Esminis elementas grafikos apdorojime – draiverio sąvoka

• Draiveris – tai speciali programa, atliekanti tarpininko vaidmenį, t.y. Perimanti programos pateikiamus duomenis,

atitinkamu būdu transformuojanti juos, ir perduodanti techniniams įrenginiams, kurie išveda atitinkantį grafinį vaizdą

į ekraną.

• Kaip taisyklė, savo programoje autorius turi nurodyti kokį grafinį draiverį reikia naudoti !!!

• Programiniu poţiūriu, bazinis grafikos elementas vadinamas pikseliu (sutrumpinimas nuo picture element).

• Pikselių kiekis uţduoda naudojamą grafinę rezoliuciją.

• Kokius grafinius reţimus (rezoliucijas) ţinote ?

5.14. Darbas su grafinėmis funkcijomis

• Labai priklauso nuo konkrečios programavimo aplinkos

• Mūsų funkcijos aprašytos faile graphics.h , todėl reikia naudoti direktyvą:

#include <graphics.h>

• Programiniu poţiūriu grafiko programavimas: nurodyti ką su kiekvienu ekrano pikseliu reikia daryti

• Programavimą visada sudaro trys pagrindiniai etapai:

1. Grafinio įrenginio atidarymas

2. Grafikos apdorojimo veiksmų programavimas

3. Grafinio įrenginio uţdarymas

5.15. Grafinio įrenginio atidarymas

• Grafinio įrenginio inicializavimo funkcija:

• void initgraph(int *graphdriver, int *graphmode chat *pathtodriver);

graphdriver – skaičius, ţymintis grafinio draiverio pavadinimą. Galima naudoti simbolinius pavadinimus DETECT, CGA,

VGA, MCGA ir t.t.

gmode – kintamasis, reiškiantis pradinį grafinį reţimą

pathtodriver – kelias iki direktorijos, kur įrašyti grafiniai draiveriai. Pas mus c:\bc\bgi

Pvz: int gdriver=DETECT, gmode;

initgraph(&gdriver, &gmode, ‖c:\\bc\\bgi‖);

5.16. Grafinio įrenginio uždarymas

• Pabaigus darbą su grafiniu reţimu, reikia uţdaryti grafinį įrenginį

• Uţdarymui naudojama funkcija closegraph:

• void closegraph(void);

• Pvz:

#include <graphics.h>

void main() {

int gdriver=detect, gmode;

initgraph(&gdriver, &gmode, ”c:\\bc\\bgi”);

…. // cia rasomi garfikos apdorojimo veiksmai

closegraph();

}

5.17. Kai kurios grafinės funkcijos

Ekrano išvalymo funkcija:

• void cleardevice(void);

Kursoriaus pozicijos valdymo funkcijos:

• void moveto(int x, int y);

• void moverel(int dx, int dy);

Tiesių braižymo funkcijos:

• void line(int x1, int y1, int x2, int y2);

Page 27: Programavimas C kalba

- 27 -

• void linerel(int dx, int dy);

• void linerel(int x, int y);

• Vieno pikselio išvedimo funkcija:

• void putpixel(int x, int y, int color);

Grafinių figūrų paišymo funkcijos:

• void rectangle(int left, int top, int right, int bottom);

• void circle(int x, int y, int radius);

• void arc(int x, int y, int stangle, int endangle, int radius);

• void drawpoly(int numpoints, int *polypoints);

• void bar(int left, int top, int right, int bottom);

• void fillpoly(int numpoints, int *polypoints);

5.18. Spalvų valdymo funkcijos

• Fono spalvos nustatymas: void setbkcolor(int color);

• Objekto spalvos nustatymas: void setcolor(int color);

• Spalva – tai sveikas skaičius iš intervalo 0 – 15 (kur 0 – juoda spalva, 15 – balta spalva).

• Be to galima naudoti šiuos simbolinius spalvų pavadinimus:

• BLACK , BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LIGHTGRAY, DARKGRAY, LIGHTBLUE,

LIGHTGREEN, LIGHTCYAN, LIGHTRED, LIGHTMAGENTA, YELLOW, WHITE.

• Atskiras spalvos modifikatorius: BLINK

5.19. Teksto valdymas grafiniame režime

Teksto išvedimo funkcijos:

• outtext(char *textstring);

• outtextxy(int x, int y, char *textstring);

Teksto dydžio, stiliaus valdymo funkcijos:

• void setextstyle(int font, int direction, int charsize);

• Font: TRIPLEX_FONT, SMALL_FONT, SANS_SERIF_FONT, GOTHIC_FONT

• Direction: HORIZ_DIR, VERT_DIR

• Charsize: 0,1 (8x8), 2 (16x16), 3 (32x32) ir t.t.

5.20. Paprastos programos su grafika pavyzdys

#include <graphics.h>

#include <conio.h>

void main() {

int gdriver=detect, gmode;

initgraph(&gdriver, &gmode, ”c:\\bc\\bgi”);

moveto(150,200);

lineto(200,250);

line(100,200,150,350);

setcolor(red);

rectangle(100,100,300,400);

outtextxy(150,275,”as parasiau”);

getch();

closegraph();

}

Page 28: Programavimas C kalba

- 28 -

6. VI-OJI PASKAITA. Matomumo sritis. Kintamųjų klasės.

6.1. Matomumo sritis

• Aprašėme programoje kintamąjį, tegul int a. Kurioje programos dalyje šis kintamasis yra matomas, tai yra juo galima

naudotis (priskirti reikšmes, naudoti operanduose ir pan.) ?

• C kalboje egzistuoja pagrindinė taisyklė: visi kintamieji yra matomi blokuose.

• Blokas – tai programos dalis, apimta riestiniais skliausteliais { }

• Kiek blokų gali būti vienoje programoje ?

• Kokio tipo blokai daţniausiai sutinkami programoje ?

• Daţniausiai pasitaikantis blokas programose yra funkcija, tokiu atveju ir kintamasis yra matomas funkcijos ribose

• Tačiau tai nėra privaloma

• Funkcijos viduje galima padaryti atskirus blokus: t.y. kintamasis bus matomas tik dalyje funkcijos

• Tačiau toks skaidymas naudojamas retai.

• Ţymiai daţniau naudojami globaliniai kintamieji – kintamieji , kurie yra matomi ne tik vieno bloko viduje, bet

platesnėje programos dalyje

6.2. Lokaliniai ir globaliniai kintamieji

• Pasikartosime: kintamieji apibrėţti bloke yra matomi tik to bloko ribose

• Tokie kintamieji vadinami lokaliniais

• Jų priešingybė – globaliniai kintamieji

• Globaliniai kintamieji yra apibrėţiami uţ bloko ribų (todėl nepriklauso jokiam blokui) ir yra matomi ...

• Kur yra matomi globaliniai kintamieji

• Priklauso nuo apibrėţimo: paprastai uţ bloko ribų aprašyti kintamieji yra matomi duoto failo ribose.

• Matomi visuose blokuose, t.y. visose tame faile aprašytose funkcijose

6.3. Globaliniai kintamieji

• Globaliniai kintamieji – vienas iš būdų perduoti į funkciją kintamuosius ir gauti iš funkcijos reikšmes.

int a;

void main() {

int c,b; a=7; b=5;

c=a+b;

func(c); printf(―%d\n‖,a); }

void func(int c) {

int b;

b=a+c; a=b; }

void main() {

int a, b, c;

{

int d;

a=7; b=2*a;

c=a|b;

d=c*b; // ar gerai ?

}

a=d/3+b; // ar gerai ?

}

void main() {

int a, b, c;

{

int d;

a=7; b=2*a;

c=a|b;

d=c*b; // ar gerai ?

}

d=d/3+b; // ar gerai ?

}

int a;

void main() {

int c,b;

a=7; b=5;

c=a+b;

func(); }

void func() {

int c,b;

c=a; b=c; }

void main() {

int a, c,b;

a=7; b=5;

c=a+b;

func(); }

void func() {

int c,b;

c=a; b=c; }

Page 29: Programavimas C kalba

- 29 -

6.4. Lokalinių ir globalinių kintamųjų vardų sutapimas

• Neretai pasitaiko situacijo, kuomet programoje yra lokalinių ir globalinių pavadinimų tais pačiais vardais:

int a,b;

void main() {

int c; a=7; b=5;

c=a+b;

func(c); printf(―%d\n‖,a); }

void func(int c) {

int b;

b=a+c; a=b; }

Jeigu yra lokalinis ir globalinis kintamasis tuo pačiu vardu, pagal nutylėjimą naudojamas lokalinis kintamasis.

• Jeigu norime panaudoti globalinį kintamąjį, prieš jo pavadinimą reikia parašyti modifikatorių :: (du dvitaškiai):

int a,b;

void main() {

int c; a=7; b=5;

c=a+b;

func(c); printf(―%d\n‖,a); }

void func(int c) {

int b;

b=a+c; ::b=b; }

6.5. Atminties klasių apžvalga

• Atminties klasės – tai alternatyvūs duomenų saugojimo variantai

• Atminties klasės:

o automatiniai

o registriniai

o išoriniai

o statiniai

• Veikimo sritis: sakiniai, kuriuose galima naudoti nurodytą kintamąjį

• Gyvavimo laikas: laiko tarpas, kurio metu išsaugoma kintamojo reikšmė

6.6. Automatiniai kintamieji

• Veikimo sritis: lokaliniai, blokas, aprašomi naudojant raktinį ţodį auto

• Gyvavimo laikas: sukuriami įeinant į bloką. Nustoja gyvuot (sunaikinami) išeinant iš bloko

• Vidiniai aprašymai išstumia išorinius

void print_cube(int);

int main(){

int x;

x=getchar():

if(x==„c‟) { ….

}

print_cube(100); }

void print_cube(int x) { // x zinoma tiktai funkcijoje print_cube

printf(“%d\n”,x*x*x); }

6.7. Registriniai kintamieji

• Registriniai kintamieji naudojami siekiant pasiekti aukštesnį programos veikimo našumą

• Aprašomi naudojant raktinį ţodį register

• Kompiliatoriui generuojama uţklausa, kad šis kintamasis būtų saugomas ne steke, o registre (kitaip sakant

procesoriuje)

• Ta automatinių kintamųjų poaibis, todėl gali būti aprašyti tik lokaliniai kintamieji

• Registrų nedaug, galima priskirti tik tuos kintamuosius, kurie tikrai naudojami programoje labai daţnai

• Patartina tokia galimybe naudotis tik labai patyrusiems programuotojams, nes naujokams tai kaip taisyklė neduos

jokios naudos.

• Šiuolaikiniai kompiliatoriai labai efektyviai optimizuoja registrinių kintamųjų priskyrimo procesą

• Greitis ir efektyvumas

• Naudojami procesoriaus registrai vietoj steko kintamųjų saugojimui

• Naudotini funkcijų parametrams ir automatiniams kintamiesiems

Page 30: Programavimas C kalba

- 30 -

• Matomumo sritis ir gyvavimo laikas: kaip automatiniams kintamiesiems

• Leidţiamų registrų skaičius priklauso nuo procesoriaus tipo

f(register int count, register int num) {

register int i;

for(i=0;i<count;i++) num--; }

6.8. Išorinė atminties klasė

• Išoriniai kintamieji aprašomi ne funkcijos viduje. Jie prieinami visoms funkcijoms, kurios randasi faile ţemiau

kintamojo aprašymo

• Ypatybė: išoriniai kintamieji pagal nutylėjimą inicializuojami 0, masyvai – nuliniais baitais.

• Pranašumas – išoriniai kintamieji uţtikrina skirtingoms funkcijoms bendrą naudojimą duomenimis. Tai greitesnis

būdas, nei naudoti argumentų sąrašo perdavimą į funkciją.

• Išorinių kintamųjų pavadinimams naudojami tos pačios taisyklės kaip ir paprastų kintamųjų pavadinimų sudarymui

• Programos skaitymas ir palaikymas daţnai sudėtingesnis negu naudojant vidinius kintamuosius

6.9. Išoriniai kintamieji

6.10. Keletas programos failų

• Daţnai didelių programų tekstas (išeities kodas) rašomas ne viename, o keliuose failuose

• Kartais failų skaičius gali būti ir labai didelis

• Kelių failų naudojimas palengvina redagavimo, kompiliavimo ir derinimo procesą

• Išoriniams kintamiesiems yra skirtumas tarp apibrėţimo ir aprašymo

• Apibrėţimas yra vienas, o aprašymas nurodo atminties sritį.

• Norint naudotis kituose failuose aprašytais globaliniais kintamaisiais naudojamas raktinis ţodis extern

6.11. Programa keliuose failuose

6.12. Statinė atminties sritis

• Statiniai kintamieji daug kuo panašūs į išorinius: jie inicializuojami 0 reikšmėmis

• Išorinis statinis kintamasis aprašomas ne bloko ribose, tačiau yra matomas tik to failo ribose. Joks kitas failas jokiu

būdu negali prieiti prie šio kintamojo

• Globaliniai kintamieji

• Aprašomi ne funkcijų viduje

ir įgyja nulines reikšmes

aprašymo metu

• Matymo sritis: nuo aprašymo

vietos iki failo pabaigos

• Gyvavimo laikas: programos

gyvavimo laikas

• Pranašumas: bendras

duomenų naudojimas

• Trūkumas: galimi konfliktai,

―privatumo‖ praradimas

int status;

char sysname[20];

void fillbuf(void), emptybuf(void);

int main(){

fillbuf();

empytybuf();

}

char buf[1024];

void fillbuf(void) {

… }

void emptybuf(void) {

…. }

one.c

int status;

char sysname[20];

void fillbuf(void);

void emptybuf(void);

main() {

fillbuf();

if(expression) empybuf(); }

two.c

extern int status;

extern char sysname[];

char buf[1024];

void fillbuf(void) {

}

void emptybuf(void) {

...

fillbuf();

}

Page 31: Programavimas C kalba

- 31 -

• Vidinis statinis kintamasis aprašomas bloko viduje ir tik jame matomas. Tačiau egzistuoja visą programos gyvavimo

laiką. Tai yra sugrįţus atgal į bloką (daţniausiai funkciją) jis išsaugo savo reikšmę.

• Vidiniai statiniai kintamieji: pirmą kartą nulis, kitus kartus – prieš tai buvusi reikšmė

6.13. Statiniai kintamieji

• Matymo sritis:

Išoriniai kintamieji:

aprašymas iki failo pabaigos

neprieinama kitiems failams

Vidinis kintamasis:

funkcija, blokas

• Pagal nutylėjimą : inicializuojama reikšmė nulis

• Pranašumai: pastovumas ir ―privatumas‖

6.14. Masyvų inicializacija

• Automatiniai masyvai: pagal nutylėjimą pradinės masyvų reikšmės yra neapibrėţtos

• Išoriniai ir statiniai masyvai: pagal nutylėjimą reikšmės lygios 0 arba NULL

char aplpha[10];

char beta[10]={„a‟,‟b‟,‟c‟,‟d‟};

char gamma[]=“this is gamma”;

int num1[10];

int main(){

static char local[];

int length[10];

6.15. Atminties klasių charakteristikos

Klasė Matymo sritis Gyvavimo

laikas

saugojimas inicializavimas Pradinė

reikšmė

automatinis blokas bloko viduje stekas taip nėra

registrinis blokas bloko viduje registras ne nėra

išorinis failas programa duomenų sritis taip 0

statinis

išorinis

failas programa duomenų sritis taip 0

statinis vidinis blokas programa duomenų sritis taip 0

void main() {

int a=10;

func(a);

….

func(a);

}

void func(int a) {

int i,sum=0;

for(i=0;i<a;i++) sum+=i;

printf(“sum=%d\n”,sum);}

void main() {

int a=10;

func(a);

….

func(a);

}

void func(int a) {

int i; static int sum;

for(i=0;i<a;i++) sum+=i;

printf(“sum=%d\n”,sum);}

Page 32: Programavimas C kalba

- 32 -

6.16. Kai kurie papildomi klausimai

• Greitesni for ciklai:

• Paprastai for( i=0; i<10; i++){ ... }

• Operacijų tvarka 0,1,2,3,4,5,6,7,8,9

• Jeigu nesvarbi operacijų vykdymo tvarka, ciklą galima rašyti taip:

• for( i=10; i--; ) { ... }

• Tvarka 9,8,7,6,5,4,3,2,1,0, ir ciklas bus šiek tiek greitesnis

Yra paprasčiau realizuoti "i--" kaip sąlygą ―nelygu nuliui? Jei taip, atlikti dekremento operaciją ir tęsti".

• Taip pat galima: for(i=10; i; i--){} ir for(i=10; i!=0; i--){}

• Niekada nenaudokite dviejų ciklų, kur pakanka ir vieno ciklo

• Pavyzdţiui turime tokią programos konstrukciją. Viskas teisinga, bet ...

• for(i=0; i<100; i++) { stuff(); }

for(i=0; i<100; i++) { morestuff(); }

Geriau taip:

for(i=0; i<100; i++) { stuff();

morestuff(); }

• Jeigu cikle yra nedaug iteracijų, gal verta ciklą paaukoti visai ir tas pačias operacijas, atliekamas cikle, išvardinti

atskirai

• Pavyzdţiui vietoj: for(i=0; i<3; i++) { something(i); }

• Gal verta panaudoti:

something(0);

something(1);

something(2);

6.17. Kai kurie optimizavimo klausimai

• Jei reikia cikle ką nors rasti,

tuomet įvykdţius sąlygą

patartina nutraukti tolesnį ciklo

vykdymą:

• found = FALSE;

for(i=0;i<10000;i++)

{

if( list[i] == -99 )

{

found = TRUE;

}

}

if( found ) printf("Yes, there is

a -99. Hooray!\n");

• found = FALSE;

for(i=0; i<10000; i++)

{

if( list[i] == -99 )

{

found = TRUE;

break;

}

}

if( found ) printf("Yes, there is a -99.

Hooray!\n");

• Tarkim turime

void func1( int *data ) { int i;

for(i=0;i<10;i++) {

somefunc2(*data, i); } }

Galbūt *data reikšmė nesikeis

kiekvieną kartą , tačiau kompiliatorius

to negali ţinoti ir kiekvieną kartą iš

steko nuskaito *data reikšmę

• Geriau tuos pačius veiksmus

uţrašyti sekančiai:

void func1( int *data ) {

int i; int localdata;

localdata = *data;

for(i=0; i<10;i++) {

somefunc2( localdata,i); }

Tokį uţrašą lengviau optimizuoti

• Kartais gali pasitaikyti tokio tipo

sąlyga:

switch ( queue ) {

case 0 : letter = 'W'; break;

case 1 : letter = 'S'; break;

case 2 : letter = 'U'; break; }

Arba

if ( queue == 0 ) letter = 'W';

else if ( queue == 1 ) letter = 'S';

else letter = 'U';

Bet geriausia būtų parašyti taip:

static char *classes="WSU";

......

letter = classes[queue];

Page 33: Programavimas C kalba

- 33 -

6.18. Keletas optimizavimo patarimų

• In general, savings can be made by trading off memory for speed. If you can cache any often used data rather than

recalculating or reloading it, it will help. Examples of this would be sine/cosine tables, or tables of pseudo-random

numbers (calculate 1000 once at the start, and just reuse them if you don't need truly random numbers).

• Avoid using ++ and -- etc. within loop expressions, eg. while(n--){}, as this can sometimes be harder to optimise.

• Minimize the use of global variables.

• Declare anything within a file (external to functions) as static, unless it is intended to be global.

• Use word-size variables if you can, as the machine can work with these better ( instead of char, short, double,

bitfields etc. ).

• Don't use recursion. Recursion can be very elegant and neat, but creates many more function calls which can become

a large overhead.

• Avoid the sqrt() square root function in loops - calculating square roots is very CPU intensive.

• Single dimension arrays are faster than multi-dimensioned arrays.

• Compilers can often optimise a whole file - avoid splitting off closely related functions into separate files, the

compiler will do better if can see both of them together (it might be able to inline the code, for example).

• Single precision maths may be faster than double precision - there is often a compiler switch for this.

• Floating point multiplication is often faster than division - use val * 0.5 instead of val / 2.0.

• Addition is quicker than multiplication - use val + val + val instead of val * 3

• puts() is quicker than printf(), although less flexible.

• Use #defined macros instead of commonly used tiny functions - sometimes the bulk of CPU usage can be tracked

down to a small external function being called thousands of times in a tight loop. Replacing it with a macro to

perform the same job will remove the overhead of all those function calls, and allow the compiler to be more

aggressive in it's optimization..

• Binary/unformatted file access is faster than formatted access, as the machine does not have to convert between

human-readable ASCII and machine-readable binary. If you don't actually need to read the data in a file yourself,

consider making it a binary file.

• Last but definitely not least - turn compiler optimization on! Seems obvious, but is often forgotten in that last minute

rush to get the product out on time. The compiler will be able to optimize at a much lower level than can be done in

the source code, and perform optimizations specific to the target processor.

Page 34: Programavimas C kalba

- 34 -

7. VII-OJI PASKAITA

Struktūros. Sąjungos. Išvardijimai

7.1. Agregatiniai kintamieji

• Iki šiol naudojome tik paprastus kintamuosius: tik iš vieno tipo sudarytus kintamuosius.

• Paprasti kintamieji ir masyvai

• Tikslas: struktūrų ir apjungimų panaudojimas skirtingų tipų duomenų saugojimu naudojant vieną identifikatoriaus

pavadinimą

• Aprašymas, inicializavimas ir naudojimas:

struktūrų

struktūrų masyvų

rodiklių į struktūras

• Aprašymas, inicializavimas ir naudojimas:

apjungimų

apjungimų masyvų

rodiklių į apjungimus

7.2. Struktūrų apžvalga

• Struktūra gali būti įsivaizduojama kaip įrašas, kurį sudaro laukai arba elementai

• Struktūros naudojamos giminingų kintamųjų grupių aprašymui

• Vartojimas labai priklauso nuo vartotojo: vieni mėgsta, kiti – ne

• Skirtumas nuo masyvų: gali apjungti skirtingo tipo kintamuosius

• Masyvai – tai išvestinis duomenų tipas, struktūros – tai agregatinis duomenų tipas (agregatas)

• Agreguotu vadinamas toks tipas , kurį sudaro keli nepriklausomi duomenų tipai (arba duomenų blokai)

• Kas yra struktūra ?

―Įrašas‖

Rinkinys iš vienos arba kelių kintamųjų, galbūt ir skirtingo tipo, sugrupuotų į vieną bloką ir trinčių vieną vardą

Išvestinis sudėtinis duomenų tipas

• Struktūrų pranašumai:

Naudojamos duomenų grupavimui

Suteikia galimybę apdoroti grupę giminingų kintamųjų kaip vieną visumą

Pavardė id. nr. atlyginimas

7. 3. Struktūros šablonas ir aprašymas

• Skirtingai nei paprasti duomenų tipai, struktūra yra sudėtinis tipas, sukuriamas programuotojo iš egzistuojančių

duomenų tipų, naudojant šabloną.

• Šablonas – iš esmės kintamųjų aprašymų sąrašas

• Šablono matymo sritis analogiška kintamojo matymo sričiai (globalinis arba lokalinis)

• Jeigu aprašan struktūrą naudojamas tegas, tai tokio tipo struktūros gali būti aprašomos likusioje failo dalyje

• Struktūros elementai atmintyje saugomi ta pačia tvarka, kaip ir yra išvardinami aprašant

• Struct [tegas] { elementų sąrašas }

struct emp {

char name[21];

char id[8];

double salary; };

int main() {

struct emp prgmr;

int num;

... }

int f(void) {

struct emp supervisor;

}

Page 35: Programavimas C kalba

- 35 -

7.4. Nuorodos į struktūros elementus

7.5. Struktūrų masyvai

• Struktūrų masyvai panašūs į kitus masyvus

• Vienas skirtumas: struktūrų masyvo elementas yra struktūra

• Staff[0] - ta struktūra

• Staff[0].name - tai struktūrų masyvo elemento laukas

• Staff[0].name[4] – tai penktas lauko name elementas pirmos masyvo struktūros

• Struktūrų masyvai naudojami gana plačiai

7.6. Rodikliai į struktūras

• Rodiklis į struktūrą aprašomas taip pat kaip ir kiti rodikliai: naudojant operatorių *

• struct emp *sp;

• Priėjimui prie struktūros, kuri parašyta kaip rodiklis į struktūrą, laukelių naudojamas specialus operatorius ->

• Šis operatorius nenaudojamas niekam kitam, nes rodikliai į struktūras naudojami labai daţnai

• sp->salary=2750.50;

• Operatorius . (taškas) naudojamas

priėjimui prie struktūros

elementų

#include <stdio.h>

#include <stdlib.h>

struct emp {

char name[21];

char id[8];

double salary; };

int main() {

struct emp prgmr;

char buf[256];

….

gets(prgmr.name);

gets(prgmr.id);

gets(buf);

prgmr.salary=atof(buf);

printf(―vardas: %s\n‖,prgmr.name);

….

prgmr.salary*=1.15;

}

int main() {

struct emp staff[NUM_EMPS];

int i;

double sal_tot=0;

fill_array(staff, NUM_EMPS];

for(i=0;i<NUM_EMPS;i++)

sal_tot+=staff][i].salary;

printf(―Bendras atlyginimas: %.2f‖

sal_tot);

}

#include <stdio.h>

#define NUM_EMPS 100

void fillarray(struct emp *, int );

struct emp {

char name[21];

char id[8];

double salary;

};

#include <stdio.h>

#define NUM_EMPS 100

void fillarray(struct emp *, int );

struct emp {

char name[21];

char id[8];

double salary;

};

int main() {

struct emp staff[NUM_EMPS], *sp;

int i;

double sal_tot=0;

fill_array(staff, NUM_EMPS];

for(sp=staff;

sp!=&staff[NUM_EPS];sp++)

sal_tot+=sp->salary;

printf(―Bendras atlyginimas: %.2f‖

sal_tot);

}

Page 36: Programavimas C kalba

- 36 -

7.7. Alternatyvūs struktūrų aprašymo būdai

• Tego uţdavimas ir kintamųjų aprašymas toje pačioje vietoje

struct emp { char name[12];

char id[8];

double salary;

} prgmr employe[100], *p;

• Aprašymas be tego

struct { char name[12];

char id[8];

double salary;

} prgmr, employe[100], *p;

• Tipo modifikatoriaus panaudojimas

typedef struct { char name[12];

char id[8];

double salary;

} EMPLOYEE;

EMPLOYEE prgmr,employe[100], *p;

7.8. Struktūros ir funkcijos

7.9. Pratimas – rodikliai į struktūras

• Prieš tai pateikta programa būtų ţymiai efektyvesnė, jeigu į funkciją raise() būtų perduotas rodiklis į struktūrą, o ne

pati struktūra Pakeiskite brūkšnelius, kad į funkciją būtų perduodamas rodiklis į struktūrą

#include <stdio.h>

#include ―emp.h‖

void main() {

struct emp progmr;

----- raise(struct emp ---, double);

…..

printf(―senas atlyginimas: %.2f\n‖, prgmr.salary);

prgmr=raise(---- prgmr, 0.12);

printf(―naujas atlyginimas: %.2f\n‖, prgmr.salary);

}

------ raise(struct emp ---person, double increase) {

person---salary*=(1+increase);

return person;

}

• Struktūra gali būti perduodama į

funkciją ir funkcija gali graţinti

struktūrą

#include <stdio.h>

#include ―emp.h‖

void main() {

struct emp progmr;

raise(struct emp, double);

…..

printf(―senas atlyginimas: %.2f\n‖,

prgmr.salary);

prgmr=raise(prgmr, 0.12);

printf(―naujas atlyginimas: %.2f\n‖,

prgmr.salary);

}

struct emp raise(struct emp person,

double increase) {

person.salary*=(1+increase);

return person;

}

Page 37: Programavimas C kalba

- 37 -

7.10. Struktūrų inicializavimas

• Struktūros gali būti inicializuojamos aprašymo metu

• Struktūros laukams priskiriamos reikšmės pateikiamos kaip sąrašas, atskiriamos kableliais ir apskliaudţiamos

riestiniais skliausteliais

• Neinicializuoti struktūrų elementai pagal nutylėjimą lygūs 0

• Neinicializuoti automatinių struktūrų elementai pagal nutylėjimą nėra apibrėţti

struct course {

char name[30];

int number;

char nickname[30]; } title = { ―c for programmers‖, 1001, ―my guide‖ };

struct mailinfo {

char name[25];

char mail_addr[30]; } proj_member[]= {

{―jean griffin‖, ― first 25‖ }

{―sue armani‖, ―second 13‖ }

{ ―frank kruk‖, ―boulevard 6‖ }

};

int f(void) {

static struct mailinfo admin=

{―administartor‖, ―computer 7‖ };

}

7.11. Struktūros su struktūromis

• Struktūros lauku gali būti struktūra

• Struktūros elementu gali būti rodiklis į jos pačios tipą

• Naudojama susietiems sąrašams ir medţiams

• Susietas sąrašas:

struct info { int num;

float sum;

struct info *next; };

• Medis:

struct node { int key;

char description[50];

struct node *left, *right; };

7.12. Apjungimai

• Visi struktūrų aprašymo ir panaudojimo aspektai (tegai, šablonai, priėjimas), kurie buvo aprašyti kalbant apie

struktūras, tinka ir apjungimams.

• Vienintelis skirtumas – naudojamas ne raktinis ţodis struct, bet raktinis ţodis union.

• Lietuviškai kartais vadinama apjungimais, kartais vadinama sąjungomis

• Skirtingai negu struktūrose, apjungimas turi tik vieną iš savo elementų kiekvienu laiko momentu.

• Apjungimas panaudoja vieną atminties sritį skirtingų kintamųjų saugojimui skirtingais laiko momentais

• Faktiškai apjungimas – tai struktūra, kurios visi elementai pradedami su postūmiu lygiu 0 ir skirtingais momentais

konceptualiai persidengia.

7.13. Apjungimų palyginimas su struktūromis

• Aprašymas, tegas, šablonai – viskas taip, kaip ir su struktūromis.

• Aprašymui naudojamas raktinis ţodis union

• Duotu laiko momentu saugo tik vieną elementą

• Pakankamai didelis, kad saugotų didţiausią galimą elementą

struct s_tag { union u_tag {

char c; char c;

int i; int i;

double d; double d;

} s_item; } u_item;

printf(―s_tem dydis %d\n‖,sizeof(s_item));

printf(―u_tem dydis %d\n‖,sizeof(u_item));

Page 38: Programavimas C kalba

- 38 -

7.14. Apjungimų pranašumai

• Apjungimai neretai įtraukiami į struktūras, o vienas iš struktūros elementų naudojamas kaip raktas, kad parodyti kuris

iš apjungimo elementų bus naudojamas

• Lankstumas – gali saugoti skirtingo tipo objektus atmintyje

• Daţnai naudojama, kad taupyti atmintį

struct mail {

char id; // a- active, r – retired

union { struct { char name[30];

char dept[10];

char location[3]; } active;

struct { char name[30];

char street[20];

char city_code[5]; } retired; } info; } person;

7.15. Išvardijimai

• Naudojami tuomet, kada reikia konstantų sekos ir nenorime sukurti naujo duomenų tipo.

• Įvedami išvardinti tipai (enumerated types)

• Aprašomi naudojant raktinį ţodį enum.

• Tarkime mums reikia mėnesių sekos metuose ―masyvo‖:

enum e_months {JAN=1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC};

typedef enum e_months month;

month currentmonth;

currentmonth = JUN; /* same as currentmonth = 6; */ printf("%d\n", currentmonth);

• Mes išvardijame mėnesius metuose naujame tipe vadinamame month.

• Mes nesukuriame naujo tipo, nes išvardijimai yra paprasti int tipo skaičiai. Todėl printf funkcija naudoja %d, o ne %s.

• Dėmesio, jeigu JAN=1 pasako C kompiliatoriui išvardijimą pradėti nuo 1 vietoj 0.

• Pastaba: Tai bus beveik tas pats , kas:

#define JAN 1

#define FEB 2

#define MAR 3 /* ... etc ... */

7.16. Struktūrų masyvo surūšiavimas

7.16. Kai kurie praktiniai patarimai: komentarai

1) Nerašykite akivaizdţių dalykų:

pvz: /* graţinam SUCCESS reikšmę */

return SUCCESS;

zerocount+; // padidinam zerocount reikšmę vienetu

Tokie komentarai ne padeda, o tik trukdo.

2) Komentuokite funkcijas ir globalinius kintamuosius. Kadangi globaliniai kintamieji pasirodo įvairiose programos

vietose, patartina kartais priminti jų reikšmę ir paskirtį. Prie funkcijos kūno visada patartina pateikti jos trumpą

charakteristiką. Jei funkcija sudėtinga, patartina nurodyti šaltinį, kuriame aprašytas algoritmas.

#includ <string.h>

#include <stdlib.h>

void main() {

const int l_name=30, l_year=5,

l_pay=10, l_buf=l_name+l_year+l_pay;

struct Man { int birth_year;

char name[l_name+1];

float pay; };

const int l_dbase=100;

Man dbase[l_dbase];

char buf[l_buf+1];

int n_record=1, i=0, j;

get_from_file(dbase, l_dbase);

for(i=0;i<n_record-1; i++) {

imin=i;

for(j=i+1;j<n_record;j++)

if(dbase[j].birth_year<dbase[imin].birth.year) imin=j;

Man a=dbase[i];

dbase[i]=dbase[imin];

dbase[imin]=a; }

return; }

Page 39: Programavimas C kalba

- 39 -

3) Nekomentuokite blogo kodo, o perrašykite tą kodą kartais nepavykus parašyti kodo fragmento sėkmingai, jis

paliekamas, tik uţkomentuojamas. Tuo tarpu komentarai paliekami, ir daţnai nebeaišku kam tie komentarai priklauso.

4) Neprieštaraukite kodui: paprastai parašius programą, komentarai atitinką kodo prasmę, tačiau vėliau padarius kokias

nors modifikacijas, kodas pataisomas, o komentarai paliekami.

5) Komentarai turi įvesti aiškumą ne sumaištį.

7.16. Kai kurie patarimai: vieningas stilius ir idiomos

• Būkite nuoseklūs naudodami atitraukimus ir figūrinius (riestinius) skliaustelius

• Naudokite idiomas vieningam stiliui palaikyti: yra tam tikri stiliai – idiomos, kurie yra priimtini ir naudojami, nors

yra teisingi ir kiti

Galima:

a) i=0;

while(i<=n-1) array[i]=1.0;

b) for(i=0;i<n;) array[i++]=1.0;

c) for(i=n;--i.=0;) array[i]=1.0;

Tačiau naudojamas toks uţrašas:

for(i=0;i<n;i++) array[i]=1.0;

• Begaliniam ciklui naudojamos dvi konstrukcijos ir nereikia naudoti jokių kitų:

for(;;) arba while(1)

• Naudokite else-if grandines daugiašakėms sąlygoms

if(condition1)

expression1

else if(condition2)

expression2

.......

else

default_expression

7.17. Kai kurie patarimai: paslaptingi skaičiai

• Tai konstantos, masyvų dydţiai, simbolių pozicijos ir kitos skaitinės reikšmės

• Tokiems skaičiams suteikite pavadinimus: pvz. enum e={ MINROW=1, MINCOL=1, MAXROW=24, MAXCOL=80,

WIDTH=MAXCOL-1}

• Naudokite simbolines, bet ne sveikas konstantes:

Negerai naudoti if(c>=65 && c<=90)

Geriau naudoti: if(c>=‗A‘ && c<=‗Z‘)

Dar geriau: if(isupper(c))

Objekto dydţio nurodymui naudokite programavimo kalbos priemones:

#define NELEMS(array) (sizeof(array)/sizeof(array[0]))

Page 40: Programavimas C kalba

- 40 -

8. VIII-OJI PASKAITA

Objektinio programavimo principai

8.1. Objektinis programavimas

• Objektiškai orientuoto (objektinio) projektavimo principai

• Sąvokų įsisavinimas: klasė, objektas, sąryšis

• Objektinio programavimo instrumentų panaudojimas

• Projekto, sukurto naudojant objektinius principus, kokybės įvertinimas

• Tinkamo modelio objektiniam projektui parinkimas

• Objektinio projekto dokumentavimas (aprašymas)

• Objektinio projekto gyvavimo ciklas

8.2. C ir C++ kalbos

• Sutinkami daţnai terminai – C ir C++. Tai ta pati kalba, ar dvi skirtingos kalbos ?

• C – tai įprastinė procedūrinė (kartais vadinam struktūrinė) aukšto lygio programavimo kalba. Giminiškos kalbos

Pascal, Fortran, PL/1 ir t.t.

• C++ - tai objektiškai orientuota programavimo kalba. Giminiškos kalbos – Delphi, Smalltalk, šiek tiek Java ir t.t.

• C++ sukurta panaudojant C kalbos sintaksė, leksemas ir visa iki tol sukaupta tos kalbos patirtį.

• Prie klasikinių C kalbos savybių C++ buvo prijungtos objektinio programavimo galimybės

• Teisinga teigti, kad C – tai C++ poaibis, realizuojantis procedūrinio programavimo principus

8.3. Kam reikalingas objektinis programavimas ?

• Visų pirma naudojamas dideliuose projektuose

• Labiausiai nauda juntama, kai programinį produktą kuria dideli ţmonių kolektyvai

• Daugumą šiuolaikinių programų kuria būtent dideli programuotojų kolektyvai

• Tačiau pakanka ir dviejų programuotojų kad nauda būtų akivaizdţiai juntama

• Kolektyvinio programavimo principas – skirtingi asmenys būna atsakingi uţ skirtingas projekto dalis ir reikia, kad jų

dalys būtų tarpusavyje suderintos

• Objektinis programavimas leidţia programą rašyti objektais (realizuoti atskirais objektais), kurie su kitais objektais

bendrauja per tam tikrus interfeisus

8.4. Objektinio programavimo principai

• Kuriant objektinio programavimo principus, stengtasi įvertinti ţmogiško mąstymo principus

• Ţmonės daţnai skirsto stebimus objektus į klases, tos pačios klasės objektai turi bendrų savybių; bendresnės klasės

objektus galima skirstyti į smulkesnių klasių objektus; smulkesnių klasių objektai paprastai paveldi stambesnių klasių

objektų savybes ir įgyja naujų savybių

• Skirtingų klasių objektai turi bendras savybes, bet jos būna išreikštos per skirtingo tipo parametrus.

• Panašūs principai buvo realizuoti, kuriant objektinio programavimo principus.

8.5. Objektinio programavimo procesas

• Objektinio programavimo stilius projektuojant – tai iteracinis aplikacijos vystymas

• Faktiškai tai priešingybė ―kulinarinių receptų‖ stiliui

• Projektuojant objektiniu principu reikia atlikti sekančius veiksmus:

Išorinių reikalavimų nustatymas

Esybių identifikavimas

Jų savybių ir elgesio identifikavimas

Esminių ryšių ir savybių identifikavimas

Iteracijos baigiamos, kai visas projektas tampa pinu ir korektišku

8.6. Išorinis aprašymas

• Sudaromas aukšto lygio koncepcinis projektuojamo objekto modelis

• Išorinis aprašymas:

Sąskaitų tipai, kuriuos padoroja bankas

Page 41: Programavimas C kalba

- 41 -

1. Komercinės sąskaitos (max 7 procentai palūkanų priklausomai nuo kitų sąlygų)

2. Nekomercinės sąskaitos (palūkanos nemokamos, min indėlio dydis 200)

Finansinių operacijų tipai:

1. Indėlio atidarymas, uţdarymas, pakeitimas

2. Finansinės ataskaitos sudarymas

Bankomato funkcijos:

1. Kortelės tikrumo patikrinimas

2. Sąskaitos būklės patikrinimas

3. Finansinių operacijų vykdymas

8.7. Esybių identifikavimas

• Ţodyno sudarymas:

Reikalavimų analizė

Bendravimas su ekspertais

• Esminių abstrakcijų nustatymas, kurios gali būti potencialių pakitimų šaltiniais

Procedūrų abstrakcijos

Duomenų abstrakcijos

• Esybės, kurios ţymimos daiktavardţiais:

gali būti realios arba irrealios

Gali būti specialiai išrastos

Ne visos priskiriamos konkrečioms klasėms

Bendru atveju yra kandidatais konkrečiai klasei

Esybių identifikavimo pavyzdys

• Procedūros:

• Visų finansinių deklaracijų spausdinimas

• Objektai:

• Komercinės sąskaitos

• Nekomercinės sąskaitos

8.8. Esybių elgesio identifikavimas

• Išnagrinėti kiekvieną esybę atskirai nuo kitų

• Identifikuoti duotos esybės elgesį

• Esybės ribos gali būti pakeistos dėl:

Kai kurių esybių didelio sudėtingumo

Esybių apjungimo

Kitų esybių reikšmių pasikeitimo

• Esybių elgesio identifikavimas – tai visada iteracinis procesas

• Esybių identifikavimo stadija kaip taisyklė sudėtingesnė, negu esybių aibės nustatymo stadija

8.9. Esybių požymių nustatymas

• Sumaţinti abstrahavimo lygį

• Išnagrinėti kiekvieną esybę iš išorės

• Nustatyti poţymius

• Nustatyti naujas esybes

• Objektiškai orientuoto projektavimo principas nepalaiko grynųjų ―iš viršaus – į apačią‖ arba ―iš apačios – į viršų‖

projektavimo strategijų

• Nustatant poţymius daţnai tena grįţti į ankstesnes stadijas

• Nustatant poţymius galimos projektavimo proceso iteracijos

8.10. Ryšių identifikavimas

• Objektų integravimo į sistemą būdų nustatymas:

- bendrumų, panašumų nustatymas

- statinės ir dinaminės semantikos nustatymas

- matomumo nustatymas

Ryšių identifikavimo metodai:

Iš apačios į viršų

Iš viršaus į apačią

Kombinuotas

Page 42: Programavimas C kalba

- 42 -

8.11. Objektinio projektavimo būdo apibendrinimas

• OOP procesas yra iteracinis, jame realizuota mišri projektavimo strategija

• OOP palaiko projektuotojo darbą keliuose projekto abstrahavimo lygiuose

• Objektinis projektavimas - tai ―kulinarinių receptų knygos antitezė

• Pagrindiniai OOP etapai:

o išorinis projektavimas ir reikalavimų sistemai nustatymas

o Esybių identifikavimas

o Esybių elgesio nustatymas, jų poţymių ir charakteristikų aptikimas

o Ryšių ir struktūrų identifikavimas

• OOP procesas sustabdomas po uţbaigto ir korektiško projekto sugeneravimo

8.12. Objekto sąvokos įsisavinimas

• Objektas yra tam tikros objektų klasės realizacija

• Objektas gali turėti būseną

• Objektas gali turėti elgseną

• Objektas gali turėti pavadinimą arba likti bevardis

• Objektas – tai tam tikros klasės egzempliorius

• Objekto matomumas yra apibotas kitų objektų atţvilgiu

• Objektas gali būti nagrinėjamas specifikavimo ir realizavimo poţiūriu

8.13. Objekto būsena

8.14. Objektų rolės

• Objektai gali funkcionuoti keliuose reţimuose:

• Operatoriaus reţimas: Operatorius veikia į kitus objektus ir nepatiria poveikio iš jų pusės. Bankinis automatas gali

būti vertinamas kaip kortelių apdorojimo interfeisas

• Serverio reţimas. Serveris – tai toks objektas, kuris patiria išorinius poveikius ir nedaro poveikio kitiems objektams.

• Tarpininko reţimas. Tarpininkas – ta objektas, kuris priima kitų objektų poveikius ir pats daro poveikius kitiems

objektams.

• Didelę įtaką turi poveikių seka

8.15. Objektų elgesys

• Visiškai izoliuotų objektų neegzistuoja. Objektai priima poveikius ir perduoda poveikius kitiems objektams

• Vartotojo poţiūriu galima išskirti penkias poveikių klases:

• Modifikatoriai – operaotoriai, kurie pakeičia objekto būseną

• Selektoriai – operatoriai, kurie įgalina prieiti prie objekto būsenos

• Iteratoriai - leidţia prieiti prie visų objekto dalių grieţtai apibrėţta tvarka

• Konstruktoriai – operatoriai, kurie inicializuoja objektą

• Destruktoriai – operatoriai, kurie sunaikina objektą.

• Konstruktoriai ir destruktoriai C++ kalboje sukuriami automatiškai

class ATM {

public:

ATM(int serial_num);

~ATM();

void login();

void password();

void whichtransaction();

void requestwithdraw();

void requestdeposit();

void requesttransfer();

void logout();

private:

const int serialNumer;

enum events {CARD,PIN,TRANSACTION,WITHDRAW, DEPOSIT,

TRANSFER, ANOTHER} event;

enum state {LOGIN, LOGOUT, IDENTIFY_TRANSACTION,

PROCESSING } state;

void (ATM::*functiobns) {SIZE]{EVENT]();

MoneyDispatcehr md;

ReceiptDispatcehr rd;

Cardslot cs;

};

Page 43: Programavimas C kalba

- 43 -

8.16. Klasės

• Klasė:

• Tai abstrakti sąvoka (duomenų tipas)

• Apibrėţiama objektų, kurie turi panašią elgseną ir panašią struktūrą, aibei

• Interfeisas aprašo išorines klasės savybes. Interfeiso elementai visada turi modifikatorių public. Interfeiso elementais

gali būti:

• - operatoriai

• - klasių aprašymai

• - konstantės

• -kintamieji

• Realizacija parašo klasės sandarą. Realizacijos elementai turi modifikatorių private. Realizacijos elementai – tai:

• - operatoriai

• - klasių aprašymai

• - konstantės

• - kintamieji

• Klasė aprašoma naudojant raktinį ţodį class

• Konkreti klasės realizacija vadinama objektu

8.17. Klasių ir objektų ryšiai

• Klasių ryšiai

• - IS-A (ryšio tipas ―yra)

• - HAS –A (ryšio tipas ―turi‖)

• - USES – A (ryšio tipas ―naudoja‖)

• - LIKE – A (ryšio tipas ―panašus‖)

• - CREATE – A (ryšio tipas ―sukuria)

Objektų ryšiai:

- HAS - A

- USES - A

8.18. Trys objektinio programavimo banginiai

• Daţnai teigiama, kad objektinis programavimas remiasi trimis banginiais (trimis pagrindiniais principais):

• - inkapsuliacija

• - paveldėjimu

• - polimorfizmu

• Inkapsuliacija – tai duomenų kintamųjų) ir jų apdorojimo procedūrų susiejimas į vieną objektą. C++ kalboje

inkapsuliacijos principą realizuoja klasės. Klasės susieja kintamuosius (duomenis) ir funkcijas (procedūras)

veiksmams su jais į vieną objektą. C++ terminologijoje funkcijos, priklausančios klasėms, vadinamos metodais

8.19. Klasės

• C kalboje duomenys ir funkcijos apibrėţiami atskirai. Toks atskyrimas apsunkina programų struktūrinį skaidymą.

• C++ įvesta nauja sąvoka – klasė. Klasė leidţia apjungti duomenis ir struktūras, kurios operuoja su jais, į vieną

struktūrą. Toks apjungimas vadinamas duomenų inkapsuliacija. Inkapsuliacija leidţia paslėpti konkrečią klasės

realizaciją, palengvinant programų derinimą ir modifikavimą.

• Klasės apibrėţimas:

class [<tag>] {

< member – list>

} <declarators>

• < tag> - klasės pavadinimas

• <member-list> - klasės narių sąrašas. Funkcijos, priklausančios klasei, vadinamo funkcijomis- elementais arba

metodais.

• <declarators> - vieno arba daugaiu tos klass objektų apibrėţimai

Page 44: Programavimas C kalba

- 44 -

• Raktinis ţodelis this – tai rodiklis į einamą klasės objektą. Rodiklis this yra pastovus dydis ir programoje negali būti

keičiamas.

• Aprašius klasę ir sukūrus tos klasės objektus, jais galima manipuliuoti. Kai kuriuos duomenis ir metodus galima

padaryti nematomais uţ klasės ribų

8.20. Klasei priklausančių elementų matomumas

• Priėjimo prie klasės elementų valdymui naudojami trys operatoriai: public, private ir protect.

• Public tipo elementai prieinami visiems klasės metodams ir kitų klasių objektams

• Private tipo elementai prieinami tik tos klasės metodams

• Protected tipo elementai prienami visiems tos klasės metodams ir kitų klasių objektams, bet jų prieinamumas

neperduodamas paveldėjimo metu

• Šie raktiniai ţodţiai aprašant klasę gali būti pateikti bet kuria tvarka, po jo turi būti dvitaškis ir visi po to aprašyti

klasės elementai yra nurodyto tipo

Klasės aprašymo pavyzdys

8.21. Klasei priklausantys metodai

• Jeigu metodo kūnas yra trumpas, toks metodas daţniausiai apibrėţiamas klasės viduje. Taip pat galima vietoj

iškvietimo naudoti metodo kūno įstatymą, naudojant raktinį ţodį inline

• Pvz:

class Line {

public:

void setlength(int newLength) { length= newLength; }

int getLength() { return length; }

private:

int length; }

• Jeigu metodo išeities tekstas nėra toks trumpas, tuomet jis uţduodamas uţ klasės ribų. Taip uţduodant metodą prieš

jo pavadinimą turi eiti klasės vardas ir matomumo srities operatorius ::

• Pvz:

void convert:: ConvertString(void) {

int i;

for(i=0; sText[i]!=„\0‟;i++) {

sText[i]=tolower(sText[i]); }

return i; }

8.22. Klasei priklausančių metodų iškvietimas

• Metodų iškvietimas:

klasės_pavadinimas.metodo_pavadinimas(argumentų sąrašas); klasės_pavadinimas ->

metodo_pavadinimas(argumentų sąrašas);

Ką primena tokia metodų iškvietimo procedūra ?

Jeigu metodas iškviečiamas iš kito tos pačios klasės metodo, tuomet klasės pavadinimo nurodyti neprivaloma.

Pvz: class A { void fun1();

void fun2(); }

A.fun1();

class Sample {

int x;

void Load();

public:

void setStr();

void getStr();

char sDataText[80];

private:

char snameText[80];

int iIndex;

public:

void convertStr();

int iLevel();

};

Page 45: Programavimas C kalba

- 45 -

8.23. Metodai, nekeičiantys klasės objekto

• Jeigu metodas nekeičia objekto, kuriam yra iškviečiamas, tuomet jį galima aprašyti su raktiniu ţodeliu const.

• Tokie metodai negali keisti klasės elementų arba kveisti kitus metodus, apibrėţtus be raktinio ţodţio const.

• Pvz: class ClassMem {

• public:

• void setWeight(int newWeight);

• int getWeight() const;

• private:

• int weight; }

8.24. Statiniai metodai

• Kai kuriuos klasės elementus galima apibrėţti statiniais, naudojant raktinį ţodį static.

• Jiems taikomi apribojimai:

• - statiniai metodai gali tiesiogiai kreiptis tik į statinius klasės narius;

• - statinis metodas negali būti paskelbtas virtualiu metodu

• Negalima apibrėţti statinio metodo su tuo pačiu pavadinimu ir tuo pačiu parametrų rinkiniu kaip ir statinį klasės

metodą

• Statinių metodų ypatybė – juos galima iškviesti nesukuriant klasės objektų

• Pvz:

class Circle {

public:

static void GetPi() { return fPI; }

private:

static float fPi; };

float fNumber;

fNumber = Circle::getPi();

Page 46: Programavimas C kalba

- 46 -

9. IX-OJI PASKAITA

Naujos C++ savybės. Objektų klasifikavimas.

9.1. Naujos C++ savybės

• C++ kalboje įvesta keletas naujų savybių, kurių neturi C programavimo kalba.

• Šios savybės nėra objektinio programavimo dalis, tiesiog dalinis C kalbos patobulinimas

• Pvz. komentarų tipas // pirmiausia buvo įvestas C++ kalboje, tačiau vėliau sėkmingai perkeliavo į C kalbą

• Čia kalbėsime apie panašias C++ kalbos modifikacijas

• Jų nėra C programavimo kalboje, todėl nesistenkite jų ir taikyti rašydami C programas

9.2. Įvedimas/ išvedimas

• C++ įvesti teksto įvedimo iš klaviatūros arba teksto išvedimo į ekraną modifikatoriai konsoliniame reţime:

• cout << - teksto išvedimas į ekraną

• cin >> - teksto įvedimas iš klaviatūros

• int iNum;

• cout << “iveskite sveika skaiciu”;

• Cin<<iNum;

• cout>> “jus ivedete skaiciu”>>iNum>>”\n”;

• Reikia panaudoti header failą iostream.h, t.y. , į programą įtraukti eilutę

• #include <iostream.h>

9.3. Konstantos

• Jei standartinėje C kalboje apibrėţti pastoviems dydţiams reikia naudoti priešprocesoriaus direktyvą #define, tai C++

įvestas raktinis ţodis const.

• Jo pranašumas prieš direktyvą tai, kad kompiliatorius visada patikrina jo tipą

• Pvz: const int max_number=256;

• Paţymėtina, kad C++ const tipo objektas gali būti pakeistas:

• Pvz: int iNumber;

int *const ptrNumber = &iNumber;

9.4. Nuorodos

• C++ galima apibrėţti nuorodą į objektą-kintamąjį arba klasės objektą.

• Nuorodai sukurti naudojamas operatorius &

• Nuoroda saugo objekto adresą, bet ją galima naudoti ir kaip patį objektą

9.5. Kintamųjų aprašymas

• C kalboje reikalaujama visus lokalinius kintamuosius apibrėţti funkcijos pradţioje, t.y. iki pirmojo toje funkcijoje

atliekamo operatoriaus.

• C++ šis reikalavimas suprastintas: kintamasis turi būti aprašytas iki pirmo duoto kintamojo panaudojimo programoje

• Pvz:

void main() {

int a, b, c;

a=5; b=7;

c=a+b;

for (int i=0, int sum=0;i<10;i++) sum+=i;

}

9.6. Atminties paskirstymas

• Standartinė C kompiliatoriaus biblioteka turi specialias funkcijas (malloc, free) atminties valdymui (rezervavimui,

atlaisvinimui).

• C++ kalboje atminties valdymui įtraukti specialūs operatoriai atminties valdymui – new ir delete

• new operatorius sukuria uţduoto tipo objektą

• Operatoriaus new formatas:

Page 47: Programavimas C kalba

- 47 -

• new type_name [initializer]

new (type_name) [initializer];

Initializer sako, kad sukurtam objektui galima priskirti pradinę reikšmę

Pvz: char *litera;

int *pi;

litera= new char;

pi=new int(3.1415);

Kad atlaisvinti anksčiau uţrezervuotą atmintį operatoriumi new, naudojamas operatorius delete

pvz: delete pointer;

Operatorius new leidţia sukurti bei atlaisvinti ir dinaminius masyvus:

pvz:

long *pdatažnew long[100];

delete [] pointer;

9.7. Funkcijų pavadinimų perkrovimas

• C++ leidţia sukurti ir naudoti keletą funkcijų su vienodais pavadinimais, bet skirtingu parametrų rinkiniu ir skirtingu

funkcijos turiniu.

• C variante toks elgesys negalimas

• Pvz: int Square(int a, int b);

int Square (int a);

int Square(nt a, int b) { return (a*b); }

int Square(int a) { return(a*a); }

9.8. Funkcijos parametrų uždavimas pagal nutylėjimą

• C++ galima uţduoti funkcijos argumentus pagal nutylėjimą:

• Pvz: int Summa(int first, int second, int third=0, int fourth=0) {

return(first+second+third+fourth); }

void main() {

int value1=10, value2=20, value3=30, value4=40;

int result;

result=Summa(value1, value2, value3, value4);

result=Summa(value1, value2, value3);

result=Summa(value1, value2);

9.9. Abstrakcijų klasifikavimas

• Esybių grupavimas klasėse gali būti atliekamas atsiţvelgiant į:

• - apibendrinimą

• - specializavimą

• - agregavimą

• Klasifikavimo procesas apima savyje:

• - esminių abstrakcijų identifikavimą (sąskaitos, indėliai, depozitai)

• - abstrakcijų išradimą (duomenų bazė, terminalo ekranas, banko valdytojas)

• Klasifikavimo procesas visada yra reliatyvus ir priklauso nuo kategorizacijos tikslų

9.10. Skirstymas į klases priklauso nuo klasifikavimo tikslų

• Klasė ―katė‖ savininko poţiūriu:

class Domestic {

public:

virtual void pet();

virtual void feed();

virtual void brush();

private: };

class Cat: public Domestic {

public:

void pet();

void feed();

void brush();

private:

};

• Klasė ―katė‖ veterinaro poţiūriu:

class Patient {

public:

virtual void mendLegs();

virtual void fix();

};

class Cat: public Patient {

public:

void mendLegs()l;

void fix();

private:

}

Page 48: Programavimas C kalba

- 48 -

9.11. Klasifikavimo šablonai

9.12. Mechanizmų klasifikacija

• Mechanizmas – tai suderinta objektų klasių sąveika, tenkinanti tam tikrus išorinius reikalavimus

• Specifinės sudėtingų, painių objektų savybės išreiškiamos per priklausomybę nuo projektinių sprendimų

• Mechanizmų klasifikacija atliekama per:

- Esminių mechanizmų identifikaciją

- Naujų mechanizmų išradimą

9.13. Konstruktoriai ir destruktoriai

• Daţnai sukuriant objektą, reikia atlikti pradinę objekto inicializavimą, pvz. išskirti atminties sritis masyvams,

priskirti kintamiesiems pradines reikšmes.

• Objektą sunaikinant atminties sritis reikia atlaisvinti

• C++ tuo tikslu yra sukurt specialūs metodai, vadinami konstruktoriais ir destruktoriais

• Funkcija-konstruktorius visada turi ta patį pavadinimą, kaip ir klasė. Ji leidţia atlikti objekto inicializavimą jo

sukūrimo metu

• Funkcija-destruktorius taip pat turi tą patį pavadinimą kaip ir klasė, bet prieš pavadinimą visada dedamas tildės ~

ţenklas. Ji atlieka objekto sunaikinimą.

9.14. Bendri klasės objektų nariai

• Kai kada yra patogu, kad visi duotos klasės objektai turėtų bendrus duomenų elementus, kurie ir yra naudojami

bendrai.

• Bendri klasės duomenų elementai apibrėţiami naudojant raktinį ţodį static

• Pvz: class CWindow {

public:

int xLeftTop, xRightBottom;

int yLeftTop, yRightBottom;

static char title[80];

void SetTitle(char *); }

char CWindow::title[80]=“lango pavadinimas”;

Kiekvienas klasės CWindow objektas turės unikalias lango koordinates ir tą patį lango pavadinimą

9.15. Draugiškos klasės ir draugiškos funkcijos

• C++ galima uţduoti draugišką klase funkciją, naudojant raktinį ţodį friend.

• Aprašant klasę nurodomas tiktai funkcijos pavadinimas.

• Paprastai gali būti

klasifikuojami:

• Realūs daiktai

• Rolės

• Įvykiai

• Sąveikos

• Specifikacijos

• Ţmonės, daiktai, būstai

• organizacijos

• Koncepcijos

• Struktūros

• Kitos sistemos

• Įrenginiai

• Daiktavardţiai,

veiksmaţodţiai (reikia būti

atsargiems)

#include <iostream.h>

class CRectangle {

int *width, *height;

public: CRectangle (int,int);

~CRectangle ();

int area (void) {

return (*width * *height);} };

CRectangle::CRectangle (int a, int b) {

width = new int;

height = new int;

*width = a; *height = b; }

CRectangle::~CRectangle () {

delete width;

delete height; }

int main () {

CRectangle rect (3,4), rectb (5,6);

cout << "rect area: " << rect.area() <<

endl; cout << "rectb area: " <<

rectb.area() << endl;

return 0; }

Page 49: Programavimas C kalba

- 49 -

• Draugiška funkcija nėra klasės elementas, bet ji gali prieiti prie visų klasės elementų, įskaitant ir private bei protected

elementus

class point {

public:

friend void point:::Clear(point *);

private:

int m_x;

int m_y; };

void Clear(point *ptr) {

ptrPoint -> m_x=0;

ptrPouint -> m_y=0;

return;

}

• Analogiškai galima uţduoti ir draugiškas klases:

class point {

...............

};

class line {

public:

friend class point; // klasė pouint skelbiama

// draugiška klasei line

}

9.16. Paveldėjimas

• Prisiminkime tris bazinius objektinio programavimo principus: inkapsuliaciją, paveldėjimą ir polimorfizmą

• Paveldėjimas – antrasis iš šių bazinių principų

• Iš kur kilo idėja panaudoti paveldėjimą ? Be abejo iš gamtos

• Ką gamtoje reiškia paveldėjimas ?

• Objektiniame programavime paveldėjimas reiškia beveik tą patį, ką ir gamtoje

• Motininės klasės perduoda savo savybes dukterinėms klasėms

• Daţniausiai naudojami pavadinimai: bazinė klasė ir išvestinė klasė; kartais naudojamos sąvokos – motininė klasė ir

dukterinė klasė

• Iš anksčiau išvestų klasių galima išvedinėti ir naujas išvestines klases

• Išvestinė klasė apima savyje visus bazinės klasės elementus ir metodus, bei gali juos papildyti nuosavais elementais ir

metodais

• Išvestinė klasė pati gali tapti bazine klase kitoms išvestinėms klasėms. Tokiu atveju išvestinė klasė paveldės visų

bazinių klasių elementus ir metodus

9.17. Vienetinis paveldėjimas

• Vienetinio paveldėjimo atveju išvestinė klasė paveldi elementus tik iš vienos bazinės klasės

• Paveldėjimas apibrėţiamas taip:

class [<tag>] [: <base> ] ] {

<member_list>

} [<declarators>]

Angliškoje literatūroje paveldėjimas vadinamas inheritance

Sukurtoje klasėje galima apibrėţti elementus, kurių vadai sutampa su bazinės lasės elementų vardais

• Vienetinio paveldėjimo pavyzdys:

class Base {

// klasės Base elementai

};

classs DerivedFirst: Base {

// klasės DerivedFirst elementai

};

class DerivedSecond : Base {

// klasės DerivedSecond elementai

};

Page 50: Programavimas C kalba

- 50 -

9.20. Daugybinis paveldėjimas

• Daugybinis paveldėjimas atliekamas paveldėjimas. Išvestinė

klasė šiuo atveju gali turėti keletą bazinių klasių panašiai

kaip vienetinis

• Vietoj vienos bazinės klasės pavadinimo, nurodomas bazinių

klasių pavadinimų sąrašas

• Apibrėţimas:

• class [<tag> [: [<base_list]] {

<member_list>

} [<declarators>]

• Daugybinio paveldėjimo parašymo pavyzdys:

class BaseFirst {

// klasės BaseFirst elementai

};

class BaseSecond {

// lasės BaseSecod elementai

}

class Derived: BaseFirst, BaseSecond {

// klasės Derived nuosavi elementai

}

9.21. Priėjimo prie bazinės klasės elementų apribojimas

• Priėjimą prie klasės elementų galima valdyti naudojant priėjimo modifikatorius

• Kuomet paveldima bazinė klasė, priėjimą galima valdyti prie bazinės klasės elementų

• Tokiu atveju yra svarbu su kokiais specifikatoriais yra aprašyti bazinės klasės elementai

9.22. Bazinės klasės metodų perdefinavimas

• Išvestinėje klasėje galima apibrėţti metodus ir duomenų elementus tais pačiais vardais, kurie jau buvo panaudoti

bazinėje klasėje

• Tokiu atveju tie bazinės klasės elementai tampa paslėptais

• Norint operuoti su paslėptais elementais, reikia naudoti pilną vardą:

bazinės_klasės_vardas:: elemento_vardas

Pvz:

class C: A,B {

a=A::a

}

9.23. Daugybinio paveldėjimopavyzdys

Bazinės klasės

elemento

specifikatorius

Bazinės klasės priėjimo specifikatorius

public protected private

public public protected private

protected protected protected private

private - - -

Derived

Class

Derived

ClassOne

Derived

ClassSecond

Base

ClaassOne

BaseClassSecond

BaseClass

• #include <iostream.h>

class CPolygon { protected:

Int width, height;

public: void set_values (int a, int b) {

width=a; height=b;} };

class COutput { public:

void output (int i); };

void COutput::output (int i) {

cout << i << endl; }

class CRectangle: public CPolygon, public

COutput { public:

int area (void) { return (width * height); } };

class CTriangle:

public CPolygon, public COutput { public: int

area (void) {

return (width * height / 2); } };

int main () { CRectangle rect; CTriangle trgl;

rect.set_values (4,5); trgl.set_values (4,5);

rect.output (rect.area()); trgl.output (trgl.area());

return 0; }

Page 51: Programavimas C kalba

- 51 -

9.24. Rodikliai į klases

• C++ leidţiama apibrėţti rodiklius į klases.

• Apibrėţta klasės tampa veikiančiu duomenų tipu

• Apibrėţti rodiklį į klasę paprasčiausiai reikia panaudoti klasės pavadinimą ir rodiklio ţenklą

• CRectangle * prect; //is a pointer to an object of class

• // CRectangle.

Kaip ir su kitais agreguotais duomenų tipais, norint prieiti prie rodiklių į klases elementų, reikia naudoti ţenklą ->

#include <iostream.h>

class CRectangle {

int width, height;

public: void set_values (int, int);

int area (void) {

return (width * height);} };

void CRectangle::set_values (int a, int b) {

width = a; height = b; }

int main () {

CRectangle a, *b, *c;

CRectangle * d = new CRectangle[2]; b= new

CRectangle;

c= &a;

a.set_values (1,2);

b->set_values (3,4);

d->set_values (5,6);

d[1].set_values (7,8);

cout << "a area: " << a.area() << endl;

cout << "*b area: " << b->area() << endl;

cout << "*c area: " << c->area() << endl;

cout << "d[0] area: " << d[0].area() << endl;

cout << "d[1] area: " << d[1].area() << endl;

return 0; }

Page 52: Programavimas C kalba

- 52 -

10. X-OJI PASKAITA

Paveldėjimas. Operatorių perkrovimas.

10.1. Išvestinės klasės

• Sudaro prielaidas sukūrimui naujos klasės, kuri yra anksčiau sukurtos klasės variacija

• Išvestinė klasė gali prieiti prie bazinės klasės atvirų ir uţdarų narių

• Išvestinėje klasėje nustatomi private, protected ir public bazinės klasės narių apribojimai

• Pagal nutylėjimą nustatomi private apribojimai

• Pilnai atitinka įprastinės klasės apribojimus, bet papildomai turi bazinės klasės elementus su nuosavais priėjimo

apribojimais

10.2. Išvestinių ir bazinių klasių elementai

• Grafiškai elementų apribojimai gali būti pavaizduoti taip:

• Private Base Derived

private ------ private

protected ---- private

public -------- private

• Protected

private ------- private

protected ---- protected

public -------- protected

• Public

private -------- private

protected ----- protected

public ---------- public

10.3. Išvestinės klasės funkcijos- nariai

• Išvestinėse klasėse gali pasitaikyti funkcijos-nariai, turinčios tuos pačius pavadinimus kaip ir bazinės klasės nariai

• Argumentų kiekis ir jų tipai, o taip pat graţinamos reikšmės tipas gali skirtis nuo bazinės klasės metodo argumentų

skaičiaus, tipai ir graţinamos reikšmės tipas

• class PayPhone: public Phone { // ......

public:

// ......

void GiveDialTone(); };

Phone home(516,555,8858);

PayPhone booth(708,555,5444);

//.....

home.GiveDialTone();

// Phone::GiveDialTone();

booth.GiveDialTone();

// payPhone::GiveDialTone();

• Išvestinės klasės funkcijos-nariai gali kreiptis į bazinės klasės funkcijas-narius.

• Galima kreiptis net į tas funkcijas – narius, kurių pavadinimai sutampa

• Pvz: void PayPhone::GiveDialTone() {

// atli

Phone::GiveDialTone(); // iškviečia bazinės klasės metodą

}

10.4. Priėjimo valdymas

class Phone {

.......

// klasės Phone nariai

}

class PayPhone: public Phone

{

int centsDeposit;

public:

PayPhone(int area, in exchange, int ,line);

Void GiveDialTone();

Int AcceptCoins();

};

// išvestinės klasės objekto apibrėţimas

PayPhone booth(708,555,5444);

• Leidţia paskelbti uţdarais arba atvirais

uţdaros klasės elementus arba atviros klasės

elementus atitinkamai

• Perkrautoms funkcijoms leidţia sugraţinti

pirminį priėjimo apribojimų nustatymą, kurį

jos turėjo bazinėje klasėje

• class Base {

int a;

void g();

public:

int b,c;

void f(), f(int), g(int);

};

class Derived: private Base {

public:

Base::a; // klaida: negalima public

Base b; // b vėl public

int c;

Base c; // negalima c du kartus

Base:: f; // visos f() vėl public

Base::g // negalima

Page 53: Programavimas C kalba

- 53 -

10.5. Virtualios funkcijos-nariai

• Leidţia išrinkti narius su tais pačiais pavadinimais per rodiklį į funkciją, priklausomai nuo objekto tipo, į kurį nurodo

rodiklis, o ne nuo rodiklio tipo

• Leidţia naudoti objektinę programavimo paradigmą

• Argumentų tipai, jų skaičius, o taip pat graţinamos reikšmės tipas, gali būti tokie patys kaip ir to paties pavadinimo

bazinės klasės funkcijoje

• Negali būti statinėmis

• Gali būti naudojamos abstrakčių bazinių klasių sudarymui

• Abstrakti bazinė klasė - tai klasė, turinti bent vieną virtualią funkciją- narį (metodą)

• Pilnai virtuali funkcija - narys - tai virtuali funkcija-narys, kuriai yra deklaruotas interfeisas, o jo realizacija parašyta

išvestinėje klasėje

• Tam reikia metodo apibrėţimą prilyginti nuliui

• Abstrakčios klasės destruktorius visada privalo būti virtualus

• Anstyvosios C++ versijos nepalaikė abstrakčių bazinių klasių

• Negalima apibrėţti abstrakčios klasės objekto. Galima apibrėţti tik išvestinės klasės objektą

• Pilnai virtuali funkcija niekada negali aiškiai arba netiesiogiai iškviesta iš konstruktoriaus

• Iš konstruktoriaus gali būt iškviesta tik per ne virtualią klasės funkciją-narę. Tačiau bus iškviesta duotoje klasėje

apibrėţta funkcija

10.6. Pilnai virtualios funkcijos - nariai

10.7. Virtualios klasės ir kostruktoriai

class Phone {

// ...

public:

virtual void GiveDialTone();

// virtuali funkcija

};

class PayPhone:: public Phone {

int centsDeposited;

public:

PayPhone(int area, int exchange, int

line);

void Give DialTone();

int AcceptCoins(); };

// .....

Phone home(516,555,8858);

PayPhone booth(708,555,5444);

Phone *p;

// rodiklis į bet kurį Phone tipą

p=&home; p->GiveDialTone();

// Phone::GiveDialTone();

p=&booth; p->GiveDialTone(); //

PayPhone::GiveDialTone();

struct Point {

int x,y;

Point(int x0=0, y0-0) {

x=x0; y=y0; }

};

class Shape { // abstrakti bazine klase

protected:

Point center;

public:

Shape(Point c): center(c) { }

virtual Shape& Draw() const=0; };

// pilnai virtuali Shape

class Cicle: public Shape {

int radius;

public:

Circle(Point c, int r=1);

Shape& Draw() const; };

// Draw() bus apibrezta

//……

Shape amorphus; // Klaida: abstrakti

klase

Circle c;

Shape *p=&c; // teisinga

class Phone {

// ....

public:

Phone(int a, int e, nt l);

{ //.....

AcceptDigits(); // si funkcija iskviecia ...

}

virtual void GiveDialTone(); // ... Sia funkcija

long AcceptDigits() {

// ....

GiveDialTone(); // ... kadangi tiesiogonis

iskvietimas yra cia

}

// ....

};

class PayPhone: public Phone {

// ...

public:

// ....

void GiveDialTone(); // si funkcija

negali buti iskviesta

};

Page 54: Programavimas C kalba

- 54 -

10.8. Bazinių klasių konstruktoriai

• Iškviečiami prieš išvestinių klasių konstruktorių iškvietimą

• Turi būti aiškiai nurodyti kiekviename išvestinės klasės apibrėţime, jeigu bazinėje klasėje nėra konstruktoriaus pagal

nutylėjimą

• Bazinės klasės konstruktoriaus pavadinimas ir jo argumentai atskiriami nuo išvestinės klasės konstruktoriaus

pavadinimo dvitaškiu

• Daugybinių bazinių klasių konstruktoriai atskiriami vienas nuo kito dvitaškiais

• Niekada tiesiogiai arba netiesiogiai iškviesti virtualios bazinės klasės metodus

10.9. Bazinių klasių destruktoriai

• Iškviečiami po išvestinių klasių destruktorių

• Gali būti virtualiais. Abstrakčios klasės destruktorius gali būti virtualiu

• Gali per ne virtualias funkcijas- narius tiesiogiai arba netiesiogiai iškviesti virtualius metodus

• Tačiau šiuo atveju iškviečiama funkcijos versija duotai klasei arba bazinei klasei, jeigu tokia egzistuoja, ir niekuomet

išvestinei klasei

10.10. Daugybinės bazinės klasės

• Leidţia išvesti naują klasę daugiau negu iš vienos bazinės klasės

• Bazinių klasių išvardijimo tvarka sąraše neturi įtakos.

• Priėjimas prie bazinių klasių elementų, turinčių vienodus pavadinimus, turi būti atliekamas per bazinių klasių

pavadinimus

class A { public: void f(); };

class B { public: void f(); };

class C: public A, public B { /* .... */ };

// .....

C c;

c.f(); // klaida: kur f ?

c. A:f(); // teisingai

• Patogiausia dviprasmybes spręsti abiejų funkcijų perdengimu išvestinėje klasėje

class C: public A, public B {

// ....

public:

void f() { A::f(); B::f(); }

};

// ...

C c;

c.f(); // dabar teisingai

• Klasėms, kurios yra išvestos iš klasių su bendra baze, pagal nutylėjimą egzistuoja du bendros bazės objekto

egzemplioriai

• Į bendros bazinės klasės elementus galima kreiptis per bet kurios iš išvestinių klasių pavadinimą

10.11. Virtualios bazinės klasės

• Klasėms, kurios yra išvestos iš išvestinių klasių su bendra virtualia bazine klase, egzistuoja tiktai vienas bendros

bazinės klasės elementas

• Apibrėţiami raktinio ţodţio virtual panaudojimu bazinės klasės priėjimo lygio specifikatoriuje

• Prieinant prie bazinės klasės elementų nebereikia nieko nurodyti papildomai

• Jų konstruktoriai iškviečiami pagal paskutinės išvestinės klasės grandinėlę

Class Phone {

// ...

public:

Phone(int, int, int); // turi

argumentus

// .....

};

class PayPhone: public Phone {

// .....

public:

PayPhoneint a, int e, int l):

Phone(a,e,l) {

// .....

}

// .....

};

Page 55: Programavimas C kalba

- 55 -

• Apibrėţiant klasę galima sumaišyti su ne virtualiomis bazinėmis klasėmis

10.12. Šablonai

• Kas yra šablonas ?

• Šablonai naudojami ir objektiniame programavime

• Jie išplečia klasės ir funkcijos supratimą

• Suteikia galimybes parametrizuoti funkcijas ir klases

• Faktiškai įgalina apibrėţti funkcijas ir klases kaip ―bet kurio tipo‖ elementus

• Sąvotiškai leidţia atsisakyti tipų

10.13. Funkcijų šablonai

• Tai funkcijos kaip šablono specifikacijos paskelbimas. Šablono specifikaciją sudaro raktinis ţodis template, paskui

kurį seka parametrų, įtrauktų į < > skliaustelius, sąrašas

• Turi tipo parametrus kurie ţymimi raktiniu ţodţiu class, po kurio seka identifikatorius. Identifikatorius naudojamas

tipo pavadinimo pakeitimui

• Automatiškai kompiliatorius išplečia iki pilno funkcijos aprašymo

• Gali būti perkrautos kitomis funkcijomis – šablonais

10.14. Klasių šablonai

• Tai klasių apibrėţimai, naudojant specifikaciją template

• Automatiškai juos kompiliatorius išplečia iki pilno klasių apibrėţimo, kaip reikalauja taisyklės

• Negali būti įstatyti į kitas klases (skirtingai nuo įprastų klasių)

• Gali keisti netipizuotus parametrus. Reikšmės, nurodytos šiems parametrams, privalo būti konstantos

• Gali būti išvesti iš kaip iš ne šabloninių klasių, taip ir iš klasių šablonų

• Iš jų gali būti išvestos kaip ne šabloninės klasės, taip ir klasės šablonai

• Kai kuriems tipams gali būti perdengti tam, kad atlikt (arba neatlikti) kokius nors veiksmus, kuriuos klasių šablonai

neatlieka

• Taip pat gali būti klasėmis-struktūromis arba klasėmis-apjungimais

class Stack <char *> {

char * *v;

int size, top;

public:

Stack(int ezis);

~Stack();

void Push(const char * &);

char * & Pop();

char * & Top() const; };

template <class T> const T& Max(const T&, const

T&);

Max(const T&a, const T&b) {

return a>b ? a: b;

}

// ….

int I,j;

float a,b;

// ….

int k=Max(I,j);

// iskvieciama Max(int, int)

float c=Max(a,b); // iskvieciama Max(float, float)

// perkrovimas

template <class T> const T& Max(const T&, const

T&);

template <class T. const T&Max(const T*, int);

int Max(int(*) (int), int (*) (int));

template <class T> class Stack

{

T *v;

int size, top;

pPublic:

Stack(int ezis);

~Stack();

void Push(const TŲ);

T& Pop();

T& Top() const;

};

Stack <int> i; // int duomenims

Stack <char *> cp; // char duomenims

// Netipizuoti duomenys

template <class T, int size> class Stack {

T v[size];

int top;

public:

Stack(): top(-1) { }

}

Stack <int,20> tiny;

Stack <int, 500> huge;

Page 56: Programavimas C kalba

- 56 -

10.15. Statiniai duomenys- nariai

• Yra bendri duomenys visiems tam tikros klasės-šablono egzemplioriaus klasės objektams.

• Apibrėţiami failo matomumo srityje, kuomet prieš apibrėţimą naudojamas template

template <class T> class C {

static int i;

static T t; };

template <class T> int C <T>::i; // apibrėţiame matomumo srityje

template <class T> int C <T>::t;

C <char> c;

C <float> f;

10.16. Funkcijų-narių šablonai

• Apibrėţiami uţ klasių, kurioms priklauso, apibrėţimų ribų naudojant specifikatorių template

• Apibrėţtiems tipams gali būti perdengti, kad atlikti tam tikrus veiksmus, kuriuos metodų šablonai neatlieka

template <class T> void

Stack <T>::Push(const T& element)

{

if(top==size-1)

error(―stack oveflow‖);

else v[++top]=element;

}

10.17. Draugiškos funkcijos

• Kiekvienam T tipui gali būt visų T tipo klasių draugais. Tai įprastos draugiškos klasės

• T tipui gali būt T tipo klasės draugais

• Prieš juos gali eiti specifikatorius template

• Gali būti kitos klasės funkcijomis- nariais

• Gali būti apibrėţti visai klasei

• Gali būti ne šabloninių klasių draugais

10.18. Operacijų perkrovimas

• Gali išplėsti iki klasės tipo bet kurių operacijų reikšmes, įskaitant :: , sizeof, ? :, ., *

• Atliekama deklaruojant funkciją, susidedančią iš raktinio ţodţio operator, po kurios seka viena iš vidinių operacijų

• Nedaro jokių prielaidų apie tokias operacijas. Pvz: jeigu i yra int tipo, tai ++i yra tas pats, kas i=+1 ir i=i+1.

Perkrautiems operatoriams tokios prielaidos nebegalioja tol, kol pats programuotojas jų atitinkamai neapibrėţia

• Negali naudoti argumentų pagal nutylėjimą

10.19. Unariniai operatoriai

• Gali būti apibrėţti kaip nestatinės funkcijos-nariai, neturintys argumentų. Tai yra @ x interpretuojama kaip

x.operator@() bet kuriam operatoriui @

• Gali būti apibrėţti kaip funkcijos, nesančios kokios nors klasės nariais, ir turinčios vieną argumentą

• Šis argumentas yra tos klasės kintamasis arba nuoroda į tokį kintamąjį

• Šiuo atveju @x interpretuojama kaip operator@(x) bet kuriam operatoriui @

Page 57: Programavimas C kalba

- 57 -

11. XI-OJI PASKAITA

Operatorių perkrovimas. Polimorfizmas.

11.1. Unariniai operatoriai

Class X {

X operator-() const; // unarinis minusas

X operator &() const; // adreso gavimas

X operator ^() const; // klaida: ^ binarine operacija

};

class Y {

friend Y operator –(const Y&); // unarinis minusas

friend Y operator &(const Y&); // adreso skaiciavimas

friend Y operator^(const Y&); // klaida

};

11.2. Binarinės operacijos

• Gali būti deklaruotos kaip nestatinės funkcijos, kurios turi vieną argumentą. Tai yra uţrašas x@y interpretuojamas

kaip x.operator@(y) bet kuriam operatoriui @.

• Gali būti deklaruotos kaip funkcijos, nepriklausančios konkrečiai klasei ir turinčios vieną argumentą.

• Šis argumentas turi būti arba duotos klasės kintamuoju, arba nuoroda į tokį kintamąjį. Ta yra bet kuriai operacijai @,

Įskaitant ir operaciją =, x@y interpretuojama kaip operator@(x,y)

• Pvz:

class X {

X operator –(const X&) const; // binarinis minusas

X operator &(const X&) const; // poskiltinis IR

X operator! (const X&) const; // klaida: ! Unarine operacija

};

class Y {

friend Y operator –(const Y&, const Y&);

friend Y operator &(const Y&, const Y&);

friend Y operator! (const Y&, const Y&); // klaida

};

11.3. Operatorių perkrovimas

• class complex {

double re, im;

public:

complex (double r, double i) { re=r; im=i; }

friend complex operator +(complex, complex);

friend complex operator*(complex, complex);

}

• void f() {

complex a= complex(1, 3.1);

complex b = complex(1.2, 2);

complex c = b;

a=b+c;

b=b+c*a;

c=a*b + complex(1,2);

• class matrix {

double m[4][4];

public:

matrix();

friend matrix operator+(matrix&, matrix &);

friend matrix operator*(matrix&, matrix&);

};

• matrix operator + (matrix& arg1, matrix& arg2) {

matrix sum;

for (int i=0; i<4; i++)

for (int j=0; j<4; j++) sum.m[i][j]= arg1.m[i][j] +

arg2.m[i][j];

return sum;

}

Page 58: Programavimas C kalba

- 58 -

11.4. Funkcijos iškvietimo operacija

• Turi būt paskelbta, kaip nestatinė klasės funkcija narys

• Leidţia vartotojui nustatyti operandų kiekį

Class X {

// ....

public:

X(int a, int b, int c);

// ....

void operator() (int i, int j, in k);

};

X Xample(1,2,3); // iškviečiamas konstruktorius

Xamople(4,5,6); // iškviečiama operacija ()

11.5. Priskyrimo operacija

• Naudojama vieno duotos klasės objekto reikšmės priskyrimui kitam objektui

• Jeigu vartotojas jos neapibrėţė, tai atlieka vieno klasės objekto laukų priskyrimą kitam objektui

• Turi būti apibrėţta, jeigu klasėje yra laukai, kurie yra rodikliai į dinamiškai išskirtas atminties sritis

• Tai tik operacijos funkcija, kuri nėra paveldima

• Turi būti apibrėţta, kaip nestatinė klasės funkcija - narys

11.6. Indeksavimo operacija

• Turi būti apibrėţta kaip nestatinė klasės funkcija- narys

• Daţniausiai graţina nuorodą, todėl ją galima naudoti priskyrimo operacijoje iš abiejų operando pusių

class String* {

char *s;

//…

public:

String(char);

String(const char *);

char &operator[](int pos) { return s[pos]; }

// …

};

String ball=mitten‖;

ball[0]=‗k‘;

11.7. Priėjimo prie nario operacija

• X->m interpretuojama kaip (x.operator->())->m.

• Pastebima, kad tai unarinė operacija ir kad x – tai klasės objektas, o ne rodiklis į jį.

• Turi graţinti rodiklį į klasės objektą, arba patį klasės objektą, arba nuorodą į klasės objektą, kuriam ši operacija yra

priskirta, kadangi originali operacijos -> prasmė nėra prarandama, o tik uţlaikoma

• Turi būti apibrėţta, kaip nestatinė klasės funkcija - narys

11.8. Polimorfizmas

• Polimorfizmas išvertus iš graikų kalbos reiškia daugiaformiškumas

• Tai paskutinė bazinė objektinio programavimo koncepcija

• class IntStack {

int *v, size, top;

public:

// …

IntStack& operator=(const IntStack &);

};

IntStack& IntStack:: operator=(const IntStack& from) {

if(this !=&from )

{

delete [] v;

v= new int[size=from.size];

for(register int i=0; i<size; i++)

v[i]=from.v[i];

top=from.top;

}

return *this;

}

// ….

IntStack a(100),b,c;

//….

c=b=a;

Page 59: Programavimas C kalba

- 59 -

• Polimorfizmas objektiniame programavime suprantamas kaip objekto sugebėjimas sureaguoti į tam tikrą uţklausą

priklausomai nuo savo tipo, netgi ir tuo atveju, kuomet kompiliacijos metu objekto, kuriam nukreipta uţklausa, tipas

dar nėra ţinomas.

• C++ kalboje polimorfizmo koncepcija realizuota naudojant virtualių funkcijų-narių mechanzmą

11.9. Virtualios funkcijos-nariai

• Jeigu kurioje nors klasėje yra funkcija, aprašyta kaip virtual, tai į tokią klasę kompiliatorius patalpina paslėptą narį –

rodiklį į virtualių funkcijų lentelę.

• Taip pat sugeneruojamas specialus kodas, leidţiantis parinkti virtualią funkciją, tinkančią duoto tipo objektui,

programos vykdymo metu.

• Šis procesas įgijo vėlyvo surišimo pavadinimą (angl. late binding).

• Kita vertus virtualių funkcijų naudojimas lėtina programos veikimą ir didina klasės objektų dydį

• Jeigu kokia nors funkcija bazinėje klasėje apibrėţta kaip virtuali, tai funkcija tokiu pačiu pavadinimu, su tuo pačiu

argumentų sąrašu ir tokio paties tipo graţinama reikšme, apibrėţta bazinėje klasėje, automatiškai tampa virtualia

• Negalima apibrėţti išvestinėje klasėje funkcijos, besiskiriančios tiktai graţinamos reikšmės tipu

• Virtuali funkcija savaime suprantama turi būti kokios nors klasės metodu, tačiau ji negali būti statiniu kokios nors

klasės metodu.

• Išvestinėje klasėje galima apibrėţti funkciją su kitu besiskiriančiu argumentų sąrašu ir ji bus paprasta (nevirtuali)

funkcija

class Base {

int dummy;

public:

void f() { cout<<f_msg<<―Base::f()\n‖; }

11.10. Programavimas Windows aplinkai

• Palyginus su Dos aplinkai parašytomis programomis, Wiindows programos pasiţymi neįprastu veikimo principu

• Funkcija WinMain gauna darbo pradţioje valdymą ir atlieka tam tikrus veiksmus, inicializuojančius programos langą

• Po to ši funkcija pereina į pranešimų apdorojimo reţimą (ciklą)

• Išėjus iš pranešimų apdorojimo ciklo programos darbas baigiamas

• Funkcijos WndProc neiškviečia nė viena kita programos funkcija, nors būtent ši funkcija atlieka visą naudingą

vartotojo poţiūriu darbą

#define STRICT

#include <windows.h>

//lango klases pavadinimas

char const szClassName[]=―MyWindowsAppClass‖;

//lango pavadinimas

char const szWindowsTitle[]=―MyWindowApplication‖;

Int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpszCmdLine, int nCmdShow) {

HWND hwnd; // lango identifikatorius

MSG msg;

ATOM aWndClass; // grizimo kodo atomas

WNDCLASS wc; // lango klases registravimo struktura

// uzpildome lango klases registravimo strukturos laukus

//lango stilius

wc.style=0;

// rodikis i lango funkcija, apdorojancia visus sios klases langu pranesimus

wc.lpfnWndPoc=(WNDPROC)WndProc;

wc.cbClsExtra=0;

wc.cbWndExtra=0; // papildomos atminties dydis

wc.hInstance=hInstance;

wc.hIcon=LoadIcon(NULL,IDI_APPLICATION); //ikoneles identifikatorius

wc.hCursor=LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground=(HBRUSH)(COLOR_WINDOW=1);

wc.lpszMenuName=(LPSTR)NULL;

wc.lpszClassName=(LPSTR) szClassName;

// uzregistruojame lango klase

aWndClass=RegisterClass(&wc);

// sukuriam langa

Page 60: Programavimas C kalba

- 60 -

hwnd=CreateWindow(szClassName, szWindowTitle, WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT,

CW_USEDEFAULT,

// lango dydis ir vieta

0, // motininio lango identifikatorius

0, // meniu identifikatorius

hInstance, NULL);

if(!hwnd) return FALSE;

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

// paleidziam pranesimu apdorojimo cikla

while(GetMessage(&msg,0,0,0)) {

DispatchMessage(&msg); }

return msg.wParam; }

LRESULT WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {

switch(msg) {

case WM_LBUTTONDOWN: {

MessageBox(NULL, ―paspaustas kairysis peles klavisas‖, ―pranesimas‖, MB_OK);

return 0; }

case W_RBUTTONDOWN: {

MessageBox(NULL, ―paspaustas desinysis peles klavisas‖, ―pranesimas‖, MB_OK);

return 0; }

case WM_DESTROY: {

PostQuitMessage(0);

return(0);

}

}

return DefWindowProc(hwnd, msg, wParam, lParam);

}

11.11. Darbas su Windows sistemos meniu

• Beveik kiekviena Windows aplinkai parašyta programa turi meniu.

• Daţniausiai meniu kuriamas naudojant programos resursų failą ir resursų kompiliatorių

• Resursų failas turi plėtinį .rc

• Resursu faile gali buti ir kai kurie kiti programai reikalingi duomenys (pavyzdţiui akseleratoriai, ikonėlės ir t.t.)

MY_MENU

nameID MENU

BEGIN

POPUP ―&File‖

BEGIN

MENUITEM ―&New‖, CM_NEW

MENUITEM ―&Open‖, CM_OPEN

MENUITEM ―&Save‖, CM_SAVE

END

POPUP ―&Edit‖

BEGIN

MENUITEM ―&Undo‖, CM_UNDO

MENUITEM ―&Cut‖, CM_CUT

MENUITEM ―&Paste‖, CM_PASTE

MENUITEM ―&Copy‖, CM_COPY

END

END

MENUITEM SEPARATOR

Programos fragmentas:

case WM_COMMAND:

{

switch(wParam) {

case CM_NEW:

….

// aprasomi reikalingi veiksmai

return 0;

case CM_UNDO:

…..

// aprasomi Undo veiksma

return 0; // ir t.t. visi meniu