Pateiktis įkeliama. Prašome palaukti

Pateiktis įkeliama. Prašome palaukti

Lekt. Tomas G. Lipnevičius

Panašios pateiktys


Pateikčių temos: "Lekt. Tomas G. Lipnevičius"— Pateikties kopija:

1 Lekt. Tomas G. Lipnevičius
Programavimo ir IT pagrindai 7 paskaita Lekt. Tomas G. Lipnevičius

2 Programavimo pagrindai
Programavimas

3 Masyvai C kalboje perduodant masyvus funkcijoms yra perduodama ne pati duomenų struktūra, o tik rodyklė į ją, t.y. nurodant masyvo pavadinimą iš tikrųjų turime omeny rodyklę į pirmą masyvo elementą. Dėl šios priežasties visi pakeitimai daromi kitose funkcijose su reikalingo masyvo elementais yra “matomi” funkcijose kurioje masyvas buvo apibrėžtas ar kuriai masyvas yra perduodamas. Išvada: masyvo grąžinti iš funkcijos nereikia.

4 Masyvai Perduodant masyvą funkcijai kartu prasminga perduoti ir jo elementų kiekį: int suma (int masyvas[], int kiekis) { int i, suma; for (i=0; i<kiekis; i++) suma+=masyvas[i]; return suma; } int main() int mas[10], kiekis=10; printf (“Masyvo elementų suma lygi %d”, suma(mas, kiekis));

5 Daugiamačiai masyvai #define ROWS 5 #define COLS 10
int multi[ROWS][COLS]; Norint pasiekti konkretų elementą rašysime multi [row][col] arba *(*(multi + row) + col). Pakeiskime reiškinį *(multi + row) reikšme X – tada aukščiau parašytą reiškinį parašytume *(X + col). X šiuo atveju yra rodyklė o col yra integer tipo skaičius, t.y. matome paprastą aritmetinę operaciją kuriai pritaikyta išadresavimo operacija. Žiūrint į šiuos pertvarkymus galime pasakyti kad iš tikrųjų turime tik vienmatį masyvą kuriame eilutės eina viena po kitos, t.y. bet kurį daugiamatį masyvą galime pertvarkyti į vienmatį masyvą.

6 Daugiamačiai masyvai Trimatis masyvas int arr[L][M][N].
Kadangi šį masyvą galime interpretuoti kaip masyvą kurio elementais yra dvimačiai masyvai MxN tai norint gauti tam tikrus elementus masyve galime taikyti šias operacijas: ptr – masyvo L pirmo elemento adresas, t.y. šiuo atveju pirmas elementas yra pirmas masyvas MxN ptr + i *(M*N) - masyvo L i-tojo elemento adresas ptr + i*(M*N) + j *N - masyvo L j-tojo elemento adresas ptr + i*(M*N) + j *N + k - masyvo L k-tojo elemento adresas *(ptr + i*(M*N) + j *N + k) - masyvo L k-tojo elemento reikšmė

7 duomenu_tipas *vardas;
Rodyklės – kas tai? Kintamasis tai objektas turintis vardą ir kintančią reikšmę. Kintamajam išskiriama atmintis, kurios dydis priklauso nuo tipo. Kintamojo reikšme gali būti adresas. Rodyklės tipo kintamasis apibrėžiamas taip: duomenu_tipas *vardas; pvz.: int *ptr; char *eilute; Sakome, kad rodyklė “rodo” į objekto, kuris saugomas nurodytu adresu, reikšmę.

8 Rodyklės – kas tai? Rodyklė tai kintamasis kurios reikšmė yra kito kintamojo adresas (eng. pointer). Sakome, kad jei vienas kintamas saugo kito kintamojo adresą, tai pirmas kintamasis “rodo” į antrą.

9 Rodyklės – kas tai? Rodyklės reikšmei saugoti reikalingas tam tikras baitų kiekis. Šis kiekis priklauso nuo kelių faktorių: naudojamos platformos (pvz. 32 bitų platformoje adresui saugoti reikia 4 baitų) Kompiliatoriaus #include <stdio.h> void main() { int *p; printf(“pointer size: %d\n”, sizeof(p)); }

10 Pagrindiniai operatoriai
Pagrindiniais operatoriais kurie operuoja rodyklės tipo operandais yra: * - išadresavimo operatorius. Šis unarinis operatorius “paima” arba nuskaito tikrąją reikšmę pagal operando adresą. Šio operatoriaus operandais gali būti tik rodyklės tipo kintamieji. & - adreso operatorius. Šio unarinio operatoriaus rezultatas yra nurodyto kintamojo adresas. Šio operatoriaus rezultatas gali būti priskiriamas tik rodyklės tipo kintamiesiems.

11 Pavyzdys #include <stdio.h> void main() { int num; int *p; num = 10; p=&num; printf(“Adreso operatoriaus panaudojimas: %p”, p); printf(“Išadresavimo operatoriaus panaudojimas: %d”, *p); }

12 Pavyzdys #include <stdio.h> void main(void) { int num, q; int *p; num = 100; p = &num; q = *p; printf("%d", q); }

13 Pavyzdys #include <stdio.h> int j, k; int *ptr; void main(void) { j = 1; k = 2; ptr = &k; printf("j reiksme %d ir jos adresas %p\n", j, &j); printf("k reiksme %d ir jos adresas %p\n", k, &k); printf("ptr reiksme %p ir jos adresas %p\n", ptr, &ptr); printf("Reiksme i kuria rodo ptr yra %d\n", *ptr); }

14 Pavyzdys #include <stdio.h> void main() { int num; num = 10; //Kam bus lygu *&num ? //O *&*&num ? //O *&*&*&*&*&*&*&num? }

15 Rodyklės tipo kintamųjų inicializavimas
Paprastai globalieji kintamieji, juos apibrėžiant bet nepriskiriant jiems reikšmės, įgauna reikšmę 0 (pagal ANSI standartą). Rodyklės tipo kintamasis nėra inicializuojamas pagal nutylėjimą, jei jam reikšmė nėra priskiriama apibrėžimo metu. Sakome, kad rodyklė „rodys“ į jokį objektą, t.y. jos reikšmė bus NULL. NULL yra makrosas kuris leidžia, nepriklausomai nuo naudojamos platformos, realizuoti tuščią rodyklę. Šį makrosą galima naudoti priskyrime arba palyginimo sakiniuose, pvz.: if (ptr == NULL) ...

16 Rodyklių priskyrimas Reikšmės rodyklės tipo kintamiesiems priskiriami įprasta tvarka. #include <stdio.h> void main (void) { int x; int *p1, *p2; p1 = &x; p2 = p1; printf ("%р %р", p1, р2); }

17 Rodiklių aritmetika Rodyklės tipo kintamiesiems gali būti taikomos operacijos: galima pridėti integer tipo skaičių prie rodyklės tipo kintamojo reikšmės; pvz. ptr1++, ptr1 + i galima atimti integer tipo skaičių nuo rodyklės tipo kintamojo reikšmės; pvz. ptr1--, ptr1-i galima atimti vienos rodyklės tipo kintamojo reikšmę nuo kitos rodyklės tipo kintamojo reikšmės; pvz. ptr2-ptr1 – gausime elementų kiekį tarp ptr1 ir ptr2. Tas skaičius gali būti neigiamas. Unarinės operacijos * ir & turi aukščiausią prioritetą (po skliaustų). Kuo skiriasi *ptr++; ir *(ptr++);? Adresų negalima dauginti, dalinti, iš jų negalima atimti ar pridėti float ar double tipo reikšmių. Rodyklės tipo kitamiesiems negalima taikyti postūmio operacijų. Tarkime turime int *ptr kur ptr adresas yra Jei atliksim operaciją ptr++; kokia bus ptr reikšmė? Int atveju Atitinkamai ptr— Adresą galime apskaičiuoti pagal formulę: Pradinis_adresas + n*sizeof(duomenu_tipas), kur n elementų kiekis.

18 Rodiklių aritmetika #include <stdio.h> int const N = 10; void Spausdinti(int *); int main() { int masyvas[N], i; for (i=0;i<N; i++) masyvas[i]=(i+1)*10; } Spausdinti(masyvas); return 0; void Spausdinti(int *p) int i; printf("%2d-asis masyvo elementas yra: %d\n", i+1, *(p+i)); printf("Masyvo elemntu kiekis: %d", (p+N) - p);

19 Rodyklių palyginimas Rodyklės tipo kintamiesiems gali būti taikomos palyginimo operacijos: == palyginti ar du rodyklės tipo kintamieji turi vienodas reikšmes; pvz ptr1 == ptr2 teisybė jei ptr1 ir ptr2 rodo į tą patį elementą != palyginti ar du rodyklės tipo kintamieji turi nevienodas reikšmes; pvz ptr1 != ptr2 teisybė jei ptr1 ir ptr2 rodo į skirtingus elementus >, <, >=, <= palyginti rodyklių reikšmes. ptr1<ptr2 arba ptr1<=ptr2 gausime teisybę jei ptr1 rodo į masyvo elementą su mažesniu ar lygiu indeksu nei ptr2

20 Rodyklių palyginimas #include <stdio.h> int const N = 10; int main() { int masyvas[N], i; int *p, *k; for (i=0;i<N; i++) masyvas[i]=(i+1)*10; } p = masyvas + 5; k = masyvas + 6; printf ("p reiksme: %d\n", *p); printf ("k reiksme: %d\n", *k); if (p == k) { printf("rodykles p ir k rodo i ta pati objekta"); } else {printf("rodykles p ir k rodo i skirtingus objektus"); } return 0;

21 Rodyklių palyginimas #include <stdio.h> int const N = 10; int main() { int masyvas[N], i; int *p, *k; for (i=0;i<N; i++) { masyvas[i]=(i+1)*10; } p = masyvas + 5; k = masyvas + 6; printf ("p reiksme: %d\n", *p); printf ("k reiksme: %d\n", *k); if (p < k) { printf("rodykles p rodo i masyvo elementa su mazesniu indeksu nei k"); } return 0; }

22 Rodyklės ir masyvai int main(void) { int my_array[] = {1,23,17,4,-5,100}; int *ptr; int i; ptr = &my_array[0]; // ptr rodys i pirma masyvo elementa //ptr = my_array; printf("\n"); for (i = 0; i < 6; i++) printf("my_array[%d] = %3d\t",i,my_array[i]); //eilute A: paimam masyvo reiksme naudojantis indeksu printf("ptr + %d = %3d\n",i, *(ptr + i)); //eilute B: paimam masyvo reiksme taikydami rodykliu postumius } return 0;

23 Rodyklės ir masyvai ptr = &my_array[0]; ir ptr = my_array; yra tas pats. Bet my_array = ptr rašyti negalima, nes ptr yra kintamasis o my_array yra konstanta, todėl pirmo masyvo elemento adreso pakeisti negalima, nes atmintis visiems masyvo elementams buvo jau išskirta masyvo apibrėžimo metu.

24 Pavyzdys #include <stdio.h> #define DYDIS 10 main() { int masyvas[DYDIS]; int suma = 0; int i; int *p; for (i=0;i<DYDIS;i++) {masyvas[i] = i+1;} //skaiciuojame masyvo elementu suma //1 budas {suma = suma + masyvas[i];} printf ("Masyvo elementu suma yra %d\n", suma);

25 Pavyzdys //2 budas suma = 0; p = &masyvas[0]; for (i=0;i<DYDIS;i++) { suma = suma + (*p); p++; } printf ("Masyvo elementu suma yra %d\n", suma); //3 budas suma = 0; {suma = suma + *(p + i);} printf ("Masyvo elementu suma yra %d\n", suma);

26 Rodyklės į neapibrėžtą tipą
void * rodykles_vardas; Žodis void leidžia mums konkretizuoti tipą vėliau, t.y. programos vykdymo metu. Tokio tipo rodyklė gali rodyti į bet kokio objekto tipą. Bet norint operuoti su neapibrėžto tipo rodyklėmis reikia pirmiausia atlikti konvertavimo operaciją: #include <stdio.h> main() { int a = 10; double d = 5.236; void *vp; vp = &a; printf ("a=%d\n", *((int *) vp)); vp = &d; printf ("d=%f\n", *((double *) vp)); }

27 Rodyklių taikymas Duomenų perdavimas pagal adresą (byref) main() {
int x,y; …. x = 5; y = 10; swap (x,y); } void swap (int a, int b) int temp; temp = a; a = b; b = temp;

28 Rodyklių taikymas void swap (int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; } main() int x, y; … swap ( &x, &y);

29 Galimos klaidos #include <stdio.h> void main() { int x = 65000, y; short *ptr; ptr = &x; y = *ptr; printf ("x=%d\n", x); printf ("y=%d\n", y); // kodel gausime kita skaiciu??? }

30 Galimos klaidos void main (void) { int х, *р; х = 10; *р = х; // klaida, kodėl??? }

31 Galimos klaidos #include <stdio.h> void main(void) { int x, *p; x = 10; p = x; // klaida, kodel??? printf ("%d", *p); }


Atsisiųsti ppt "Lekt. Tomas G. Lipnevičius"

Panašios pateiktys


Google reklama