Lekt. Tomas G. Lipnevičius

Slides:



Advertisements
Panašios pateiktys
Laisvės ir kalnų šauksmas
Advertisements

“Ieškosiu Tavo veido...” pagal Isabel Guerra.
Lakštingala, čiulbanti 100 metų
Gėlių horoskopas MOTERIMS
Juozas Aputis (g. 1936) – rašytojas, bandantis surankioti ir savaip sudėlioti pasaulio grožį ir neįžvelgiamą jo gelmę reiškiančius žodžius. Parengė Vilniaus.
ATRASK DIEVO PAŠAUKIMĄ
III klasių viktorina Paruošė G.Baublienė ir L.Venskutė
Pateikties kopija:

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

Programavimo pagrindai Programavimas

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.

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));

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ą.

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ė

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ę.

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ą.

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)); }

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.

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); }

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

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); }

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

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) ...

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); }

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 1000. Jei atliksim operaciją ptr++; kokia bus ptr reikšmė? Int atveju 1004. Atitinkamai ptr— Adresą galime apskaičiuoti pagal formulę: Pradinis_adresas + n*sizeof(duomenu_tipas), kur n elementų kiekis.

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);

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

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;

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; }

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;

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.

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);

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);

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)); }

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;

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

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??? }

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

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