Informatyka MTDI1 Wykład 11 Delphi Pascal c.d. Pliki Typ zbiorowy Rekurencja Obiekty Struktury dynamiczne
Obsługa plików elementy pliku Pojęcie i istota stosowania składowe takiego samego dowolnego typu - prostego, strukturalnego - nie pliki dostęp do pliku jest sekwencyjny - operacje np.: czytaj pierwszy | czytaj następny zapisz na początku | zapisz na końcu brak selektora (adresacji) rozmiar dynamiczny istnieje wewnętrzny wskaźnik elementu bieżącego, automatycznie modyfikowany po każdej operacji odczyt | zapis fizycznie - w pamięci zewnętrznej: dysk, CD-ROM, pendrive - znakowe urządzenia wej/wyj: (monitor), drukarka
Uwagi: Po otwarciu do odczytu wskaźnik ustawia się na początku pliku, każdy odczyt lub zapis przesuwa wskaźnik o jedną pozycję. Otwarcie nowego (nieistniejącego) pliku powoduje utworzenie pustego pliku, jeśli plik istniał jego zawartość zostaje usunięta, Można sprawdzić czy wskaźnik jest na końcu pliku Można przewinąć wskaźnik na początek – jeśli wtedy stwierdzimy, że jesteśmy jednocześnie na końcu pliku to znaczy że plik jest pusty, Zapis nowego elementu zalecany tylko na końcu pliku (w środku można ale zmienimy (nadpiszemy) wartość elementu). Dopisanie „w środku” pliku wykonuje się przez etapowe przepisywanie do innego pliku.
textFile - plik tekstowy czyli file of string istotne cechy - gromadzenie dużej ilości informacji w sposób trwały - przenoszenie danych między programami | komputerami Dwa podstawowe typy plikowe textFile - plik tekstowy czyli file of string file of Tb - plik elementowy ( binarny, zdefiniowany ) o składowych typu Tb Wprowadza się tzw. zmienne plikowe służące do komunikowania programu z plikami fizycznymi deklaracja zmiennej plikowej: var lista_nazw_zmiennych: Tp; - Tp jest opisem typu plikowego lub nazwą typu są to zmienne całościowe - reprezentują cały plik nie ma zmiennych składowych - brak selektora elementu są operacje dotyczące składowych pliku (procedury, funkcje), korzystamy ze zmiennych odpowiadających składowym plików
Przykłady deklaracji zmiennych plikowych: type osoba = record nazw: string[ 20 ]; imie: array[1..2] of string[ 15 ]; data_ur: data; pensja: real end; dwa_napisy = array[1..2] of string[15]; var oceny: file of real; nazwiska: file of string[20]; zaloga: file of osoba; adresy: file of dwa_napisy; wyniki: textFile; //plik tekstowy pliki elementowe
Reguły obsługi plików Wymagane czynności opis zmiennych plikowych type osoba = .....; var grupa: file of osoba; skojarzenie z plikiem fizycznym - f ’d:\ścieżka\plik’ otwarcie pliku f do - zapisu - odczytu - dopisania (tylko tekstowe) operacje - zapis | odczyt zamknięcie pliku f możliwe też operacje usunięcie pliku f zmiana położenia (nazwy)
!!! Kolejność operacji na plikach: skojarzenie zmiennej plikowej z plikiem fizycznym otwarcie pliku (do zapisu lub odczytu) operacje (czytanie, zapis) zamknięcie
..istnieje grupa standardowych procedur i funkcji, m.in. procedura: assignFile( f, Wt ) – skojarzenie z plikiem fizycznym zmienna plikowa tekstowy opis położenia na dysku np.: assignFile( grupa, ' C:\ROK_II\grupa_1.bin ' ); procedura : reset( f ) - otwarcie do odczytu /zapisu (zastępowanie) - jeśli plik istnieje!!! - plik staje się aktywny - wskaźnik na początku pliku - gdy plik nie istnieje błąd wykonania procedura : rewrite( f ) - otwarcie do zapisu - gdy plik nie istniał jest tworzony - gdy plik istniał jest usuwana jego zawartość ! - wskaźnik znajduje się na początku pliku (końcu pustego)
Także można wykoywać operacje systemu plików – np procedura procedura : closeFile( f ) - zamknięcie pliku zamyka plik zwalnia łączność z plikiem funkcja: eof( f ) - badanie końca pliku (end of file) - wartość logiczna: true - wskaźnik po ostatniej wartości (na końcu) false - wskaźnik w środku Także można wykoywać operacje systemu plików – np procedura erase(plik) – usunięcie pliku
Procedura zapisu do pliku !! Plik tekstowy write(zmienna_plikowa, lista_elementów); kursor pozostaje w wierszu writeln(zmienna_plikowa, lista_elementów); piszemy i kursor zmienia wiersz Plik elementowy write(zmienna_plikowa, składowa); //tylko jedna! Tak było jeśli chcieliśmy wyświetlać na konsoli (monitorze) writeln(lista_elementów);
Procedura odczytu z pliku !! Plik tekstowy read(zmienna_plikowa, lista_elementów); ew. następne czytanie w tym samym wierszu readln(zmienna_plikowa, lista_elementów); czytanie i zmiana wiersza Plik elementowy read(zmienna_plikowa, składowa); //tylko jedna!
Przykład: zapis do pliku tekstowego program test; var p1:TextFile; napis:string; begin napis:='Jakis tekst'; Assignfile(p1,'a.txt'); rewrite(p1); //utworzenie i otwarcie pliku do zapisu writeln(p1,napis); //wpisanie tekstu do pliku CloseFile(p1); end. nazwa fizycznego pliku (wraz z ewentualną ścieżką dostępu)
Przykład: odczyt z pliku tekstowego program test; var p1:TextFile; z:string; begin assignfile(p1,'a.txt'); reset(p1); readln(p1,z); //czytanie z pliku do zmiennej closeFile(p1); writeln(z); // wypisz na ekran readln end.
Jeśli więcej wierszy w pliku i nie wiemy ile, zwykle stosuje się konstrukcję pętli while program test; var p1:TextFile; z:string; begin assignfile(p1,'a.txt'); reset(p1); while not eof(p1) do readln(p1,z); //czytanie z pliku do zmiennej writeln(z); //wypisz na ekran end; closeFile(p1); readln end. dopóki nie ma końca pliku wykonuj...
Przykład: Zapis do nowego pliku elementowego program test; type osoba= record nazwisko:string[20]; wzrost:integer; end var p1:file of osoba; z:osoba; begin assignfile(p1,'spis.bin'); rewrite(p1); z.nazwisko:='Kowalski'; z.wzrost := 180; write(p1,z); //wpisanie rekordu w zmiennej z do pliku closeFile(p1); readln end.
Przykład: Zapis do istniejącego pliku elementowego program test; type osoba= record nazwisko:string[20]; wzrost:integer; end var p1:file of osoba;//zmienna plikowa z:osoba; //zmienna rekordowa begin Assignfile(p1,'spis.bin'); reset(p1); while not eof(p1) do read(p1,z); // czytanie do końca (przewinięcie) z.nazwisko:='Nowak'; z.wzrost := 190; write(p1,z); //wpisanie elementu do pliku CloseFile(p1); readln end.
Przykład: Odczyt z pliku elementowego program test; type osoba= record nazwisko:string[20]; wzrost:integer; end var p1:file of osoba; z:osoba; begin Assignfile(p1,'spis.bin'); reset(p1); while not eof(p1) do read(p1,z); // czytanie elementu writeln(z.nazwisko); writeln(z.wzrost); end; CloseFile(p1); readln end.
Typ zbiorowy type nazwa_typu = set of typ_porządkowy ; Typ zbiorowy to zbiór potęgowy danego typu porządkowego, czyli zbiór wszystkich podzbiorów tego typu. Zmienna typu zbiorowego może zatem zawierać zbiór pusty, jedno- lub wieloelementowy. Definicja typu zbiorowego: type nazwa_typu = set of typ_porządkowy ; typ zbiorowy typ bazowy Liczba elementów nie może przekraczać 256 – czyli typ bazowy może być: okrojonym całkowitym, np. 1..256 znakowym (w tym okrojonym np. 'a'..'z' ) wyliczeniowym logicznym Zmienna typu zbiorowego zawierać może dowolny podzbiór elementów typu bazowego, od zbioru pustego do zbioru zawierającego wszystkie elementy.
Czyli: var zbiór: set of 1..100; Zmienna typu integer może mieć w danej chwili jedną wartość: 1 lub 100, ale nie może jednocześnie 1 i 100! Zmienna typu array może zawierać wiele wartości, ale zawsze ma statyczny (stały) rozmiar i nawet jak komórki są puste to rezerwują pamięć komputera Zmienna typu wyliczeniowego może zawierać jedną wartość, ale tylko z podanej listy wartości Zmienna typu zbiorowego może zawierać zero, jedną lub wiele wartości z danego zbioru var zbiór: set of 1..100; Zmienne typu zbiorowego 1 5 7 19 4 8 34 67 69 88 100
Przykłady definicji typu zbiorowego: type dni = set of (pon,wto,sro,czw,pia,sob,nie) ; znaki = set of 'a'..'z' ; miesiac = (sty,lut,mar,kwi,maj,cze,lip,sie,wrz,paz,lis,gru) ; zbior_miesiecy = set of miesiac ; var nazwa_miesiaca : miesiac ;//zmienna typu wyliczeniowego zbior_nazw : zbior_miesiecy ; //zmienna typu zbiorowego UWAGA: nazwa_miesiaca może przyjąć wartość tylko jednej z nazw – typ wyliczeniowy; zbior_nazw może przyjąć wartość dowolnego podzbioru z nazw bazowych – typ zbiorowy
Operacje logiczne wykonywane na zbiorach to relacje (porównania): Zmiennych typu zbiorowego nie wolno używać w instrukcjach czytania i wyprowadzania wyników, używa się ich jedynie w operacjach wykonawczych, testujących itp. Operacje logiczne wykonywane na zbiorach to relacje (porównania): a = b równość zbiorów, te same elementy w obu zbiorach, a < > b różność zbiorów, różne elementy w obu zbiorach (chociaż niektóre mogą się powtarzać) a <= b zawieranie zbioru a w zbiorze b (true jeśli każdy element zbioru a jest w zbiorze b) a >= b zawieranie zbioru b w zbiorze a (true jeśli każdy element zbioru b jest w zbiorze a) c in a czy element c jest w zbiorze a
Stałe typu zbiorowego [lista wartości podzbioru] np. [1, 5, 7], Wartości stałych typu zbiorowego zapisujemy w nawiasach kwadratowych w postaciach: [lista wartości podzbioru] np. [1, 5, 7], [okrojenie ze zbioru] np. [1..3], lub łącznie: np. [1..3, 5, 7],
Przykład 1: type x=(alfa, beta, gamma, delta) ; {typ wyliczeniowy} var z1,z2,z3,z4 : set of x ; begin z1 := [alfa, beta] ; {lista - wybór podzbioru alfa, beta} z2 := [alfa..gamma] ; {okrojenie - wybór podzbioru alfa, beta, gamma} z3 := [gamma] ; //tylko gamma z4:= [ ]; //zbiór pusty end;
Przykład 2: type miesiace = set of 1..12 ; var v, x, y, z: miesiace ; lit: char ; begin x :=[1..12] ; {cały rok} y := [1..6] ; {pierwsze półrocze} z := [1, 3, 5 , 7 , 8, 10, 12] ; {miesiące mające 31 dni} lit := 'a' ; if x<>y then writeln('tak') else writeln('nie'); {tak} if x<=y then writeln('tak') else writeln('nie'); {nie} if x>=y then writeln('tak') else writeln('nie'); {tak} if x = y then writeln('tak') else writeln('nie'); {nie} if 1 in x then writeln('tak') else writeln('nie'); {tak} if 9 in z then writeln('tak') else writeln('nie'); {nie} if lit in ['a'..'z'] then writeln('tak') else writeln('nie'); {tak} end ;
x:= [italic,podkreslony]; x:= [italic,pogrubiony]; x:= [podkreslony]; Przykład 3: Czcionka var x: set of (italic, podgrubiony, podkreslony); Można: x:= [ ]; x:= [italic,podkreslony]; x:= [italic,pogrubiony]; x:= [podkreslony];
Operacje działań na zmiennych typu zbiorowego (znaczenie jak w teorii mnogości): + suma zbiorów – różnica zbiorów iloczyn zbiorów (część wspólna) Przykład: type zbiorowy = set of 1..6 ; var x , y, v : zbiorowy ; begin x :=[2, 3, 4] + [4, 5, 6] ; {wynik [2,3,4,5,6] } y := [2, 3, 4] - [4, 5, 6] ; {wynik [2,3] } v := [2, 3, 4] * [4, 5, 6] ; {wynik [4] (część wspólna) } y := v * x ; { przeanalizować wynik} end . Na przykładach zrozumieć działanie
xn = Algorytmy rekurencyjne Wiele problemów obliczeniowych można zdefiniować rekurencyjnie. Rekurencja oznacza takie zdefiniowanie zagadnienia, gdzie w trakcie formułowania definicji odwołujemy się do niej samej. Przykładem definicji rekurencyjnej może być zapis całkowitej, nieujemnej potęgi rzędu n liczby rzeczywistej x: xn-1*x dla n > 0 (tu użycie definiowanej potęgi) xn = 1 dla n = 0
Rekurencja w językach programowania jest realizowana za pomocą podprogramów wywołujących kolejno same siebie ze zmienianymi parametrami wywołania. Aby podprogramy rekurencyjne działały poprawnie powinny zawierać warunek zakończenia rekurencji, aby wywołanie wykonywane było skończoną liczbę razy. Rekurencja daje proste programy lecz ma także wadę: każde wywołanie podprogramu wymaga wykonania przez procesor dodatkowych czynności, co spowalnia działanie programu oraz powoduje odłożenie na stos systemowy dużej liczby danych
function potega_n (x:real ; n:integer):real ; begin program rekur; function potega_n (x:real ; n:integer):real ; { funkcja wyznacza n-tą potęgę n dla liczby x } begin if n=0 then potega_n := 1 else potega_n := potega_n(x, n – 1)*x ; {w definicji funkcji wykorzystanie samej funkcji} end ; var x:real; begin {program główny} x:= potega_n (2,10) ; {obliczenie 210} writeln(x); readln; end.
program silnia; function silnia_x (x: integer): longint ; {zastosowano typ longint ze względu na duże wartości funkcji silnia} begin if x = 1 then silnia_x := 1 else silnia_x := silnia_x(x-1)*x ; end ; //przykładowe użycie var alfa : integer ; alfa:=5; write( 'Silnia wynosi:',silnia_x(alfa)); readln; end.
Podstawowe cechy programowania obiektowego
Programowanie strukturalne (proceduralne) – koncepcja tradycyjna Programowanie obiektowe – koncepcja nowoczesna
■ dane są powszechnie dostępne – łatwo o błędy, Wady programowania strukturalnego (tradycyjnego) ■ dane są powszechnie dostępne – łatwo o błędy, ■ sekwencyjność wykonywania programu, ■ wszystkie sytuacje trzeba przewidywać i obsługiwać, ■ konieczność testowania po każdej zmianie, ■ wiele instrukcji, obszerny kod, trudność zrozumienia algorytmu służy do nauki programowania niewygodne nie przystaje do obecnych systemów operacyjnych obiektowych (komponentowych)
Potrzebne były metody zwiększające wydajność i systematyczność tworzenia systemów informatycznych i ich wydajność. Poza tym powstały interfejsy graficzne (Windows)! Korzenie technologii obiektowej – lata 60-te, Nygaard i Dohl, Simula 1, Simula67 (1967).
OBIEKTOWOŚĆ – filozofia tworzenia na podstawie rzeczywistych zjawisk otaczającego świata (nie tylko język programowania). Obiekty (świata rzeczywistego a także systemu operacyjnego komputera – plik, ikona, przycisk, okno) – mają swoje właściwości statyczne (nazwa, kolor itp.) a także zbiory operacji na nich czy przez nie wykonywanych.
Np. typ tablica ma swoje cechy – atrybuty: ■ wymiar ■ rozmiar ■ typ przechowywanych danych nie określa się jednak sposobów operacji na tablicach (np. dodawanie tablic), trzeba do tej operacji tworzyć własne kody lub korzystać z bibliotecznych procedur, których użycie wymaga szczegółowego zapoznania się z zestawem parametrów formalnych (sposób użycia).
■ funkcje przetwarzania parametrów obiektów Stworzono tzw. ADT – abstrakcyjny typ danych – podążanie w kierunku naturalnego języka (zbliżenie do rzeczywistości), nazwano modułem (język Modula) lub klasą (język Simula). System reaguje na zdarzenia („siły sprawcze”), efektem są procesy: ■ funkcje przetwarzania parametrów obiektów ■ przesyłu informacji między obiektami ■ oddziaływania jednych obiektów na inne
PROGRAMOWANIE OOP – podstawowe pojęcia Programowanie zorientowane obiektowo (OOP – Object Oriented Programming) umożliwia przedstawienie problemu w postaci logicznie powiązanych ze sobą struktur danych zwanych obiektami, wymieniających informacje między sobą. „Obiektowość” opiera się na koncepcyjnym (intuicyjnym) klasyfikowaniu rzeczywistości. Na świat składają się obiekty i procesy w nich zachodzące. Koncepcja (pojęcie) KLASA = typ obiektowy=encja (entity) Reprezentacja w klasie = instancja w klasie = OBIEKT. Podobnie jak typ zmiennej i zmienna
Zwierzę (kot, pies, tygrys) KLASA - zbiór obiektów „przefiltrowanych” przez definicję typu obiektowego - sklasyfikowanych do tego typu. OBIEKTY – egzemplarze w klasie (tzw. instancje w klasie) Zwierzę (kot, pies, tygrys) Elementy systemu Windows to też obiekty (ikony, kontrolki, pliki itp.)
metody (methods) – procedury i funkcje wykonywane na polach. Typ obiektowy jest to złożona struktura danych o określonej liczbie atrybutów. Atrybuty dzielimy na pola i metody. pola (fields) – atrybuty (właściwości opisane wartościami dowolnych typów, także strukturalnych) Pole jest to zmienna, która może być różnego typu. metody (methods) – procedury i funkcje wykonywane na polach. Metoda jest czynnością wykonywaną na własnych polach (lub innych obiektach) w postaci procedury lub funkcji. Metoda obiektu operuje na polach (danych) obiektu, przy ich pomocy mamy dostęp do pól. Czyli typ obiektowy to typ rekordowy poszerzony o metody
nazwa_obiektu.nazwa_pola nazwa_obiektu.nazwa_metody Metoda jest to procedura lub funkcja mająca definicję w ramach typu obiektowego. Nazwy pól i metod są kwalifikowane, czyli wskazują na obiekt, którego dotyczą czyli dostęp do pól (też metod) identyczny jak w zmiennych rekordowych, zapis z kropką (desygnacja do pola lub metody) nazwa_obiektu.nazwa_pola polem może być zmienna dowolnego typu (liczba, tekst, tablica itp.) nazwa_obiektu.nazwa_metody metoda jest podprogramem (funkcją, procedurą) – związaną z danym obiektem Przykładowo: auto.pojemność_baku pole – będzie liczbą auto.stan_baku pole – będzie liczbą auto.tankuj (litry:real) metoda - akcja
DZIEDZICZENIE Typ obiektowy może on być: niezależny, (zdefiniowany podobnie jak typ rekordowy) - rodzic jako potomek istniejącego. Wtedy mówimy, że obiekt dziedziczy wszystkie elementy (pola i metody) swojego przodka lub jest typem potomnym. Obiekty potomne mogą mieć własnego potomka (lub wielu).
Wzajemne zależności obiektów układają się w drzewo hierarchii obiektów. Dziedziczność bezpośrednia – przodek jest niezależny (sam nie ma przodka) Dziedziczność pośrednia – przodek już dziedziczy (sam ma przodka) Przykład: type polozenie = class {obiekt niezależny} x:integer; y:integer; end; punkt = class (polozenie) {obiekt potomny} widocznosc: Boolean;
Przykład: type Tpolozenie = class {obiekt niezależny} x:integer; y:integer; procedure przesun (nx, ny: Integer); end; procedure Tpolozenie.przesun(nx, ny: Integer); begin x:=x+nx; y:=y+ny;
Jeśli mamy zdefiniowany typ (klasę) Tpolozenie …możemy wykorzystać… var p:Tpolozenie; //definicja instancji obiektu p w klasie Tpolozenie begin //nadanie wartości polom (w zależności od ich typu) p.x:=p.x+100; p.y:=p.y+30; //ale jeśli pola są prywatne, to możliwe tylko z użyciem metody p.przesun(100,50) end;
Środowiska programistyczne do tworzenia aplikacji "okienkowych" mają gotowe biblioteki typów obiektowych, np. TEdit, TMemo, TMenu, TCheckBox itp. TEdit to obiekt dla jednowierszowej edycji tekstu. var Edit1:TEdit; W części wykonawczej dadanie wartości polu w procedurze obsługi zdarzenia (np.. kliknięcia w jakiś inny obiekt – przycisk lub pozycję menu): Edit1.Text:= 'jakiś tekst'; Wykonanie metody: Edit1.Clear; //usuń tekst
Obsługa zdarzeń PRZYKŁAD w Delphi Można zdefiniować obsługę zdarzenia dla obiektu – metodę obsługi: procedure TForm1.przycisk1Click (parametry); begin //nadanie wartosci polu width obiektu Label1 etykieta1.width := 40; //wykonanie metody "Ukryj" dla obiektu Label2 etykieta2.hide ; end; PRZYKŁAD w Delphi
STRUKTURY DYNAMICZNE Do elementu możemy dołączać kolejny element Specjalny typ danych umożliwiający rozrastanie się struktur Cel podstawowy – oszczędność pamięci Element jest rodzajem rekordu zawierającego: - pole (pola) danych - dodatkowe pole przechowujące adres (tzw. WSKAŹNIK) do następnego elementu Do elementu możemy dołączać kolejny element Rozmiar zbioru nie jest zdefiniowany, każde dołączanie nowego elementu powoduje nową rezerwację pamięci – ostatni element ma wskazanie puste NIL. Pobieranie elementu (usuwanie), dołączanie nowego – mogą być obarczone pewnymi kryteriami dostępu.
Lista jednokierunkowa dane adres dane adres dane adres dane nil koniec wskazanie puste musi być znane wskazanie (adres) p początku listy
Lista jednokierunkowa może być "w przód" lub "wstecz", czyli element może zawierać wskaźnik na następny lub poprzedni element. Tworzenie nowego elementu polega na stworzeniu nowego początku i połączenie z poprzednim początkiem listy Istnieją standardowe procedury: inicjacja nowego elementu new(wskaźnik) usuwanie elementu dispose(wskaźnik)
Lista dwukierunkowa Rodzaje struktur dynamicznych liniowo uporządkowany zbiór składników, w którym dla każdego składnika, poza pierwszym i ostatnim, jest określony składnik poprzedni i następny – czyli 2 wskazania na 2 adresy Dla ostatniego składnika listy dwukierunkowej jest określony tylko składnik poprzedni, a dla pierwszego tylko następny. dane wskazanie na poprzedni wskazanie na następny
Stos (stack) FILO lub LIFO to struktura danych, składająca się z liniowo uporządkowanych zbiorów składników (elementów), z których tylko ostatnio dołączony jest w danej chwili dostępny. Miejsce dostępu to wierzchołek stosu. Jest to jedyne miejsce, do którego można dołączyć lub z którego można usunąć elementy. FILO lub LIFO first in – last out last in - first out
Kolejka (queue) FIFO first in – first out jest strukturą danych, składającą się z liniowo uporządkowanych zbiorów składników, do której można dołączyć składnik tylko na jednym końcu (koniec kolejki), a usunąć tylko w drugim końcu (początek kolejki). Powiązanie między składnikami kolejki jest takie samo jak pomiędzy składnikami stosu. FIFO first in – first out
Drzewo binarne jest strukturą danych, składającą się nieliniowo uporządkowanych zbiorów składników. Do każdego składnika można dołączyć zero, jeden lub dwa składniki. Drzewo ma swój "korzeń" z którego wyrasta struktura. korzeń dane wsk_lewe wsk_prawe dane dane wsk_lewe wsk_lewe nil wsk_prawe dane dane dane nil nil nil nil nil nil brak dołączeń Drzewo binarne, w którym liczba "potomków" każdego wierzchołka wynosi albo zero albo dwa, nazywane jest drzewem regularnym KONIEC
KONIEC