Zrozumienie i używanie wskaźników w Delphi

Mimo że wskaźniki nie są tak ważne w Delfy jak są w C lub C ++, są tak „podstawowym” narzędziem, z którym prawie wszystko ma związek programowanie musi w jakiś sposób radzić sobie ze wskaźnikami.

Z tego powodu możesz przeczytać o tym, jak łańcuch lub obiekt tak naprawdę jest tylko wskaźnikiem, lub że procedura obsługi zdarzenia, taka jak OnClick, jest w rzeczywistości wskaźnikiem do procedury.

Wskaźnik do typu danych

Mówiąc najprościej, wskaźnik jest zmienną, która przechowuje adres czegokolwiek w pamięci.

Aby skonkretyzować tę definicję, należy pamiętać, że wszystko używane przez aplikację jest przechowywane gdzieś w pamięci komputera. Ponieważ wskaźnik przechowuje adres innej zmiennej, mówi się, że wskazuje na tę zmienną.

Przez większość czasu wskaźniki w Delphi wskazują na określony typ:

var
iValue, j: liczba całkowita; pIntValue: ^ liczba całkowita;
zaczynać
iValue: = 2001; pIntValue: = @iValue;... j: = pIntValue ^;
koniec
;

The składnia do zadeklarowania typu danych wskaźnika używa daszek (^)

instagram viewer
. W powyższym kodzie iValue jest zmienną typu liczby całkowitej, a pIntValue jest wskaźnikiem typu liczby całkowitej. Ponieważ wskaźnik jest niczym więcej niż adresem w pamięci, musimy mu przypisać lokalizację (adres) wartości przechowywanej w zmiennej całkowitej iValue.

The @ operator zwraca adres zmiennej (lub funkcji lub procedury, jak pokazano poniżej). Odpowiednikiem operatora @ jest Funkcja Addr. Zauważ, że wartość pIntValue nie jest 2001.

W tym przykładowym kodzie pIntValue jest typowanym wskaźnikiem liczb całkowitych. Dobrym stylem programowania jest używanie jak najwięcej pisanych wskaźników. Typ danych Pointer jest ogólnym typem wskaźnika; reprezentuje wskaźnik do dowolnych danych.

Zauważ, że gdy „^” pojawia się po zmiennej wskaźnika, usuwa odwołanie do wskaźnika; to znaczy zwraca wartość zapisaną pod adresem pamięci przechowywanym przez wskaźnik. W tym przykładzie zmienna j ma tę samą wartość co iValue. Może to wyglądać na to, że nie ma to sensu, gdy możemy po prostu przypisać iValue do j, ale ten fragment kodu kryje się za większością wywołań Win API.

Wskaźniki NILing

Nieprzypisane wskaźniki są niebezpieczne. Ponieważ wskaźniki pozwalają nam pracować bezpośrednio z pamięcią komputera, jeśli spróbujemy (przez pomyłkę) zapisać w chronionym miejscu w pamięci, możemy otrzymać błąd naruszenia zasad dostępu. Dlatego zawsze powinniśmy inicjować wskaźnik na NIL.

NIL to specjalna stała, którą można przypisać do dowolnego wskaźnika. Kiedy zero jest przypisane do wskaźnika, wskaźnik nie odnosi się do niczego. Delphi przedstawia na przykład pustą tablica dynamiczna lub długi łańcuch jako wskaźnik zerowy.

Wskaźniki postaci

Podstawowe typy PAnsiChar i PWideChar reprezentują wskaźniki do wartości AnsiChar i WideChar. Ogólny PChar reprezentuje wskaźnik do zmiennej Char.

Te wskaźniki znaków służą do manipulowania zakończeniem zerem smyczki. Pomyśl o PChar jako o wskaźniku do łańcucha zakończonego znakiem null lub tablicy, która go reprezentuje.

Wskaźniki do rekordów

Kiedy definiujemy rekord lub inny typ danych, powszechną praktyką jest również definiowanie wskaźnika do tego typu. Ułatwia to manipulowanie instancjami tego typu bez kopiowania dużych bloków pamięci.

Możliwość posiadania wskaźników do rekordów (i tablic) znacznie ułatwia konfigurowanie skomplikowanych struktur danych jako połączonych list i drzew.

rodzaj
pNextItem = ^ TLinkedListItem
TLinkedListItem = rekordsName: String; iValue: liczba całkowita; NextItem: pNextItem;
koniec
;

Ideą połączonych list jest umożliwienie nam przechowywania adresu do następnego połączonego elementu na liście w polu rekordu NextItem.

Wskaźników do rekordów można także użyć na przykład do przechowywania niestandardowych danych dla każdego elementu widoku drzewa.

Wskaźniki proceduralne i metodyczne

Inną ważną koncepcją wskaźnika w Delphi są wskaźniki procedur i metod.

Wskaźniki wskazujące adres procedury lub funkcji są nazywane wskaźnikami proceduralnymi. Wskaźniki metod są podobne do wskaźników procedur. Jednak zamiast wskazywać na samodzielne procedury, muszą wskazywać metody klasowe.

Wskaźnik metody to wskaźnik, który zawiera informacje zarówno o nazwie, jak i wywoływanym obiekcie.

Wskaźniki i Windows API

Najczęstszym zastosowaniem wskaźników w Delphi jest interfejs do kodu C i C ++, który obejmuje dostęp do interfejsu API systemu Windows.

Windows Funkcje API używają wielu typów danych, które mogą być nieznane dla programisty Delphi. Większość parametrów wywoływanych funkcji API jest wskaźnikami do niektórych typów danych. Jak wspomniano powyżej, używamy ciągów zakończonych znakiem zerowym w Delphi podczas wywoływania funkcji Windows API.

W wielu przypadkach, gdy wywołanie API zwraca wartość w buforze lub wskaźniku do struktury danych, bufory i struktury danych muszą zostać przydzielone przez aplikację przed wykonaniem wywołania API. Jednym z przykładów jest funkcja interfejsu API systemu Windows SHBrowseForFolder.

Przydział wskaźnika i pamięci

Rzeczywista moc wskaźników wynika z możliwości odłożenia pamięci podczas wykonywania programu.

Ten fragment kodu powinien wystarczyć, aby udowodnić, że praca ze wskaźnikami nie jest tak trudna, jak mogłoby się początkowo wydawać. Służy do zmiany tekstu (podpisu) kontrolki za pomocą dostarczonego uchwytu.

procedura GetTextFromHandle (hWND: THandle);
var
pText: PChar; // wskaźnik do char (patrz wyżej)TextLen: liczba całkowita;
zaczynać

{uzyskaj długość tekstu}
TextLen: = GetWindowTextLength (hWND);
{alokuj pamięć}

GetMem (pText, TextLen); // przyjmuje wskaźnik
{pobierz tekst kontrolki}
GetWindowText (hWND, pText, TextLen + 1);
{wyświetl tekst}
ShowMessage (String (pText))
{zwolnij pamięć}
FreeMem (pText);
koniec
;