<10> ポインタ型 (標準 Pascal 範囲内での Delphi 入門)〔裏〕

# 10. ポインタ型 (Pointer Types)

## 10.1. ポインタ変数と動的変数 (対象変数)

### (10.1.1.) ポインタ型の宣言

### ・ポインタ型の宣言 (Modula-2 の場合)

**Modula-2** では **POINTER TO** でポインタ変数を作るようになっています。`^` は逆参照演算子として使うので、この記述の方が初学者は混乱しないかもしれません。

```pascal:Modula-2
TYPE
  T: INTEGER;
  P = POINTER TO T;
```

## 10.2. New と Dispose

#### ・クラシック Pascal の Dispose()
> 動的変数が不要になった場合には　**Dispose(Ptr)** を使って動的変数が使用していた領域を解放します。

**クラシック Pascal** には `Dispose()` がありませんでした。

**See also:**

 - [標準 Pascal の規格票と解説書を読んでみる (Qiita)](https://qiita.com/ht_deko/items/091661d6fa3d72700a56)


### (10.2.1.) New と Dispose の二番目の書式

#### ・New と Dispose の二番目の書式 (標準 Pascal)

Delphi では可変部を持つレコード型は共用体の代わりくらいにしか使われていないため、「何故レコード型の可変部に **case** 文に類似した構文が含まれているのか？」というのを理解しづらいと思います。

New と Dispose の二番目の書式は解りにくい機能ですが、要は**入れ子になった可変部のあるレコード型を一部に限定して確保するメモリを節約する**というものです [^1]。New(P, C<sub>1</sub>,..., C<sub>n</sub>) を使って作られた動的変数は Dispose(Q, K<sub>1</sub>,..., K<sub>m</sub>) で解放する必要があります。

次のような定義があったとします。

```pascal
type
  a = (a1, a2);
  b = (b1, b2);
  c = (c1, c2);
  rec1 = record
           case tc: c of
             c1: (fc1: Integer);
             c2: ()
         end;
  rec2 = record
           case ta: a of
             a1: (case tb: b of
                    b1: (fb1: rec1);
                    b2: ()
                 );
             a2: ()
         end;
var
  p: ^rec2;                                                 
```

パラメータが一つの書式を使うと、rec2 は可変部のうちの最大の可変要素サイズでメモリが確保されますが、

```pascal
  New(p);
```

二番目の書式を使うと、パラメータで指定した可変要素のサイズでメモリが確保されます。次の例では b1 を格納するためのメモリは確保されません。

```pascal
  New(p, a1, b2);
```

二番目以降の実パラメータは可変部の可変要素に使った**選択定数**を渡します。変数を渡すことはできません。

| レコード型の<br>ポインタ変数 | 1 段目の<br>可変要素 | 2 段目の<br>可変要素 |
|:-:|:-:|:-:|
| p | a1 | b2  |


次の指定は許されません。b1 は入れ子になった可変部を持っていないからです。

```pascal
  New(p, a1, b1, c2);
```

二番目の書式を使って作られた動的変数 p は、rec2 型の変数 r への代入もアクセスもできない事に注意が必要です。

```pascal
var
  r: rec2;
  p: ^rec2;
begin
  New(p, a1, b2); 
  
  p^ := r; { NG }
  r := p^; { NG }

  Dispose(p, a1, b2); 
end.
```

この二番目の書式を詳細に解説してある書籍はそれほど多くありません。

## (10.3.) @ 演算子

#### ・@ 演算子の由来

> Delphi には @ 演算子があります。

この拡張は **Apple Lisa Pascal** 由来のようです。

**Turbo Pascal** には Version 4 で導入されています (正確には Turbo Pascal for the Mac から)。

#### ・Addr() 関数

@ 演算子に類似のルーチンとしては `Addr()` があります。@ 演算子の存在しない、古い Turbo Pascal では `Addr()` を使ってオブジェクトのアドレスを知る事ができます。

上記コードは Turbo Pascal 3.0 (CP/M) で `Hello,world.` を表示させるものです。

```STRTEST.PAS
program STRTEST;
var
  s: string[20];
begin
  s := 'Hello,world.$';
  Bdos(9, Addr(s[1]));
end.
```

Delphi での Addr() は常に形なしポインタ (Pointer 型) を返します。`{$T+}` や `{$TYPEDADDRESS ON}` に影響されません。

**See also:**

 - [<2> Clascal のオブジェクト指向拡張 (Pascal へのオブジェクト指向拡張の歴史と Delphi) (Qiita)](https://qiita.com/ht_deko/items/770f2db98c9cf3e8ef7b)
 - [System.Addr (DocWiki)](http://docwiki.embarcadero.com/Libraries/ja/System.Addr)


## (10.4.) ポインタ定数とグローバルポインタ変数の初期化

## (10.5.) Pointer 型

## (10.6.) 型チェック済みポインタ

## (10.7.) 型キャスト

### (10.7.1.) 値 型キャスト

### (10.7.2.) 変数 型キャスト
サイズが同じならキャストできるようになったのは、**Turbo Pascal 4.0** 以降です。それ以前の Turbo Pascal では、byte <-> char のような一部の型しかキャストできませんでした

## (10.8.) ポインタ演算 (Pointer Arithmetic)

# 索引
[:ramen:](https://qiita.com/ht_deko/items/745ad4a792d277d33831) [ [← 9. ファイル型〔裏〕](https://qiita.com/ht_deko/items/0e012da26f46b915307d) ] [ [↑ 目次へ](https://qiita.com/ht_deko/items/46fcdbb11cdc58872160) ] [ [→ 11. 手続きと関数〔裏〕](https://qiita.com/ht_deko/items/eb20c1504ea759d04e24) ]

[^1]: 木の枝をそのまま使うか、枝打ちして一部の枝だけを使うかといった感じです。