● ポインタ

ポインタはC言語を支える大事な機構であり、それを 駆使することでさまざまなプログラムを作ることができる。 C言語でのポインタの主な役割は、関数へ変数をアドレスで渡して、 関数内でポインタ変数を使って結果をその変数に返すことで あった。C++においては同様の作業は参照渡しで簡単になされるので、 この目的でポインタを使うことは無くなった。その代わり、C++での ポインタの役割は、より高度な機構を作ることに移った。

■ ポインタの基本

すべての変数は、メモリ上での位置を表すアドレスの数字を持つ。 これは変数の値とは異なり、すべての型の変数で共通して 4byteの大きさの整数である。アドレスを表す数字を専門に記録する変数が ポインタ変数である。

各型と双対してその型の変数のアドレスを格納するポインタ型があり、 例えば int 型については int* 型のポインタ型が存在する (ポインタ変数の宣言はC言語では int *p とし、 C++言語では int* p とする。しかし、 C++で int* p1, p2 とすると p2 は普通の変数となる。) 。 構造体やクラスの型についても同様にポインタ型が存在する。

変数のアドレスは変数に & (ampersand)を冠することで 得られ、それをポインタ変数に代入する。 逆にポインタ変数が格納するアドレスにある変数の値は、その ポインタ変数に * (asterisk)を冠することで得られる。 またこの時、そのポインタ変数が格納するアドレスにある変数に値を 書き込むこともできる。

以下の例で int 型変数 b に a の値 1 が代入され、 さらに a には 2が代入されることを汲み取ってほしい。

int  a, b;
int* p;
a  = 1;
p  = &a;
b  = *p;
*p = 2;

■ 動的変数

動的変数とは、プログラムの実行中に新たに記憶領域が必要になった その時に、必要な分だけメモリを確保して作成された変数のことである。 対照的に、local変数やglobal変数は静的変数と呼ばれ、確保される メモリの量はあらかじめ決まっている。 C++では次の様にして動的変数を確保する。
int* a;
a = new int;
確保したてのメモリ領域のアドレスがポインタ変数 a に 格納される。 *a がこの確保された変数として振舞うのである。

他の型や構造体型の変数も動的確保することができる。指定の長さの 配列変数も動的確保することができる。

double* x = new double;
Particle* p = new Particle;
char* str = new char [32];
Complex (*phi)[256] = new Complex [128][256];
ただし2次元以上の多次元配列では1次元目の要素数だけが動的に調整できる。 すべての次元の要素数を動的に調整するには、次のようにする。 まず必要な全要素を1次元配列として確保し、これを細分した各々の 先頭アドレスを動的確保したポインタ配列に格納する。
Complex *phi, **phi2;
phi  = new Complex [128*256];
phi2 = new Complex* [128];
for( int i=0 ; i<128 ; i++ ) phi2[i] = &phi[i*256];
構造体型のポインタ変数でpropertyやmethodを表すには次の様にする。
p->q;   p->Evolve(0.001);
動的変数の寿命はプログラム終了までである。意図的に早く動的変数を 解体するには次の様にする。
  delete x;
  delete p;
  delete [] str;
  delete [] phi;
動的変数は次に紹介するリンクリストでその価値がわかるが、 固定長の巨大な配列を用意する目的にも使われる。

■ リンクリスト

動的変数とポインタを使った華麗な技のひとつにリンクリストがある。 リンクリストは同じ型の変数が一列に並んだデータ集合であるが、 固定長の配列変数とは異なり、プログラムの実行中にその列の任意の位置に 任意の個数の要素を追加または削除することができる柔軟性に富んだ データ集合である。

リンクリストは下図の様に、各要素がその要素の型のポインタ変数を含み、 列の次の要素のアドレスを格納する。


リンクリストの概念図

この図で start で示したひとつのポインタ変数だけは静的変数とし て用意しておく。ポインタをたどることにより全要素をアクセスすることが できる。最後の要素のポインタ変数に NULL を指させておき、 プログラムにそれ以上リストをたどらせない。

リンクリストの途中に新たな要素を追加するには下図の様に ポインタの鎖を組み変えるだけである。


リンクリストに新たな要素が追加した概念図

この様にポインタ変数の値を少し変更するだけあり、データがメモリ間 を移動することはない。以下にリンクリストの簡単な例を載せる。 このデータ構造のデータの格納の仕方を各自確認して改良を加えてほしい。
#include <stdio.h>

class List
{
  int data;                               // data
  List* next;                             // a pointer to next list
public:
  List( List* _next=NULL, int _data=0 ){  // constructor
    next = _next;    data = _data;
  }
  void Add( int _data ){                  // adds list after this list
    next = new List( next, _data );
  }
  void Show( void ){                      // shows data recursively
    printf("%d\n", data );
    if( next ) next->Show();
  }
  ~List(){                                // destructor
    if( next ) delete next;
  }
};

int main( void )
{
  List* start = new List;                 // prepares starting list

  for( int i=0 ; i<8 ; i++ ){
    start->Add(i);                        // adds new data
  }
  start->Show();                          // shows all data

  delete start;                           // deletes all data

  return(0);
}


  • 次へ
  • 目次
    Copyright(C) by Naoki Watanabe. Oct 21st, 1995.
    渡辺尚貴 naoki@cms.phys.s.u-tokyo.ac.jp