免費的編程自學網站「pascal語言入門教程」

指針,是C語言中的一個重要概念及其特點,也是掌握C語言比較困難的部分。指針也就是內存地址指針變量是用來存放內存地址的變量,不同類型的指針變量所佔用的存儲單元長度是相同的,而存放數據的變量因數據的類型不同,所佔用的存儲空間長度也不同。有了指針以後,不僅可以對數據本身,也可以對存儲數據的變量地址進行操作

引自百度百科

這裡面提到了兩個比較重要的名詞:指針指針變量,其實只要理清楚這兩個東西就會感覺指針並不難(基礎使用)

C語言之所以強大,以及其自由性,很大部分體現在其靈活的指針運用上。因此,說指針是C語言的靈魂,一點都不為過。

這種說法也讓很多人產生誤解,似乎只有C語言的指針才能算指針。其他語言不支持指針,其實,Pascal語言本身也是支持指針的。從最初的Pascal發展至今的Object Pascal,可以說在指針運用上,絲毫不會遜色於C語言的指針。

類型指針

類型指針的定義。對於指向特定類型的指針,在C中是這樣定義的:

int *ptr;
char *pcr;

與之等價的Object Pascal是如何定義的呢?

var
ptr : ^Integer;
pcr : ^char;

針對ptr和pcr這種變量我們就可以稱為指針變量,和普通變量相比而言他們的值不一樣而已,類似於下圖這樣

Delphi基礎教程圖文版之指針

無類型指針

所謂無類型指針類似於老外心目中的上帝

C中有void *類型,也就是可以指向任何類型數據的指針。Object Pascal為其定義了一個專門的類型:Pointer。於是,ptr : Pointer;就與C中的void *ptr;等價了。

在新版本的Delphi中其實很少使用指針了,所以個人建議無類型指針更應該少用甚至不用

基本使用

主要是指針的解除引用和取地址,不說了直接代碼演示

var
  // 定義普通變量,因為是全局變量可以直接賦初始值
  Age: Integer = 10;

  // 定義同類型的指針變量,可以使用^數據類型的形式,他們是等同的
  PAge: PInteger;

begin
  // 給指針變量賦值,它只能接收這樣的值
  PAge := @Age;

  // 獲取指針變量PAge的值,即變量Age的內存地址
  Writeln(IntToHex(Integer(PAge)));

  // 直接獲取變量Age的內存地址
  Writeln(IntToHex(Integer(@Age)));

  // 獲取指針變量中存儲的具體值(解除指針引用)
  Writeln(PAge^);

  readln;

end.

上面代碼演示的僅僅為一級指針,指針是可以嵌套的

指針運算

在C中,可以對指針進行移動的運算,如:

char a[20];
char *ptr=a;
ptr++;
ptr+=2;

當執行ptr++;時,編譯器會產生讓ptr前進sizeof(char)步長的代碼,之後,ptr將指向a[1]。ptr+=2;這句使得ptr前進兩 個sizeof(char)大小的步長。同樣,我們來看一下Object Pascal中如何實現

var
   a : array [1..20] of Char;
   ptr : PChar; //PChar 可以看作 ^Char
begin
   ptr := @a;
   Inc(ptr); // 這句等價於 C 的 ptr++;
   Inc(ptr, 2); //這句等價於 C 的 ptr+=2;
end;

可能我接觸Delphi 的時間比較短,指針運算這一塊我幾乎沒怎麼用過,作為一個知識點整理出來

字符數組的運算

C語言中,是沒有字符串類型的,因此,字符串都是用字符數組來實現,於是也有一套str打頭的庫函數以進行字符數組的運算,

char str[15];
char *pstr;
strcpy(str, "teststr");
strcat(str, "_testok");
pstr = (char*) malloc(sizeof(char) * 15);
strcpy(pstr, str);
printf(pstr);
free(pstr);

而在Object Pascal中,有了String類型,因此可以很方便地對字符串進行各種運算。但是,有時我們的Pascal代碼需要與C的代碼交互(比如:用 Object Pascal的代碼調用C寫的DLL或者用Object Pascal寫的DLL準備允許用C寫客戶端的代碼)的話,就不能使用String類型了,而必須使用兩種語言通用的字符數組。其實,Object Pascal提供了完全相似C的一整套字符數組的運算函數,以上那段代碼的Object Pascal版本是這樣的:

var str : array [1..15] of char;
   pstr : PChar; //Pchar 也就是 ^Char
begin
   StrCopy(@str, 'teststr'); //在C中,數組的名稱可以直接作為數組首地址指針來用
    //但Pascal不是這樣的,因此 str前要加上取地址的運算符
   StrCat(@str, '_testok');
   GetMem(pstr, sizeof(char) * 15);
   StrCopy(pstr, @str);
   Write(pstr);
   FreeMem(pstr);
end;

函數指針

函數指針能用於兩種不同的目的:聲明函數指針類型的變量;或者把函數指針作為參數傳遞給另一例程。

Delphi中可以通過函數指針把一個函數作為參數來傳遞,然後在另外一個函數中調用。首先,申明函數指針類型TFunctionParameter

type
          TFunctionParameter = function(const value : integer) : string; //函數指針

定義準備被作為參數傳遞的函數

function One(const value : integer) : string;                            //函數-實例1
begin
  result := IntToStr(value) ;
end;

function Two(const value : integer) : string;                            //函數-實例2
begin
  result := IntToStr(2 * value) ;
end;

定義將要使用動態函數指針參數的函數

function DynamicFunction(f : TFunctionParameter; const value : integer) : string;
begin
  result := f(value) ;
end;

上面這個動態函數的使用實例

var
  s : string;
begin
  s := DynamicFunction(One,2006) ;
  ShowMessage(s) ; //will display "2006"

  s := DynamicFunction(Two,2006) ;
  ShowMessage(s) ; // will display "4012"
end;

雖然這種調用方法比直接調用麻煩了,那麼我們為什麼要用這種方式呢?

  1. 因為在某些情況下,調用什麼樣的函數需要在實際中(運行時)決定,你可以根據條件來判斷,實現用同一個表達,調用不同的函數,很是靈活.
  2. 利用函數指針我們可以實現委託,委託在.NEt中被發揮得淋漓盡致,但Delphi同樣能實現
  3. 實現回調機制

例子

//********************************************************
// 函數指針(指向一般函數和過程)
//*********************************************************
unit DelegateUnit;
interface
     procedure Func1;
     //定義兩個函數型構相同但功能不同的函數
    function    FuncAdd(VarA , VarB : Integer):Integer;
    function    FuncSub(VarA , VarB : Integer):Integer;
type
    DelegateFunc1 = procedure;
    DelegateFuncCalc = function(VarA , VarB : Integer):Integer;
var
  I : Integer;
implementation

procedure Func1;
begin
      Writeln('Func1 was called!');
end;

function    FuncAdd(VarA , VarB : Integer):Integer;
begin
     Result := VarA + VarB;
end;
function    FuncSub(VarA , VarB : Integer):Integer;
begin
   Result := VarA - VarB;
end;
end.

調用

program Delegate;
{$APPTYPE CONSOLE}
uses
  DelegateUnit;
 var
    ADelegateFunc1 : DelegateFunc1;
    ADelegateFuncCalc : DelegateFuncCalc;
 begin
     //通過函數指針調用過程
     ADelegateFunc1  := Func1;
     ADelegateFunc1 ;
    //通過同種方式調用不同函數
    ADelegateFuncCalc  := FuncAdd;
    Writeln(ADelegateFuncCalc(3,5));
    ADelegateFuncCalc  := FuncSub;
    Writeln(ADelegateFuncCalc(3,5));
end.

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/277035.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
投稿專員的頭像投稿專員
上一篇 2024-12-19 13:24
下一篇 2024-12-19 13:24

相關推薦

發表回復

登錄後才能評論