■[補足(1)] C言語におけるポインタの役割

Last modified: Tue Apr 9 2024
このページは,基礎工学部システム科学科機械科学コース2年生向けの 「情報科学演習」における演習1の教材の1つです.

C言語のポインタには様々な役割がある.

  1. 関数の引数の参照渡しに代る手段としてのポインタ
  2. 配列参照のためのポインタ
  3. 動的に確保した記憶領域を参照する手段としてのポインタ
  4. データ構造を実現する要素としてのポインタ
  5. メモリの実アドレスをアクセスする手段としてのポインタ
役割は色々あるが,どの場合でも文法は同じである.

本来ポインタというと4のことであるが,この演習では, まずはポインタの基本を押さえて, 1と2がきちんと使えるようになることを目指している. 3についても少しだけ紹介した. 3,4,5のポインタが使えなくても多くのプログラムを読み書きできるが, 1や2がわからないとお話にならない.


1. 関数の引数の参照渡しに代る手段としてのポインタ

関数呼び出しにおいて, 呼び出す側と呼び出される側(関数側)との間のデータのやり取りを考える. これまでに習った方法は以下の2つである.

値渡しは関数の独立性を高めるには有効であるが (呼び出し側に副作用を及ぼさないので),以下のような場合には都合が悪い. このような場合に使われるのが「参照渡し(call by reference)」である. 「参照渡し」とは,呼出し側の変数の値ではなく, 変数の存在そのものを関数側に渡す方法である. したがって,関数側で参照渡しの変数の値を書き換えると, 呼出し側の変数の値も変化する. これを使えば,上のような不都合が解消できる.

他のプログラミング言語では, 引数の「値渡し」と「参照渡し」を区別できるものもあるが, C言語には「値渡し」しかない. そこで,C言語で「参照渡し」と同等の機能を実現するためにポインタを用いる.

これまでは,例外として, 「配列(文字列を含む)を引数にした場合は, その中身を関数側で書き換えると呼び出し側でも変化する」 と述べてきたが,実は,関数の引数にする場合は,配列もポインタも等価なのである.


2. 配列参照のためのポインタ

配列がメモリ上に隙間なく順に並んでいるという性質を前提として, 配列上のデータに高速かつ簡潔な表現でアクセスする手段としてポインタを用いる.

機械語によるメモリアクセスの手法を考慮しているので, 機械語に変換されたときに効率の良いプログラムになる.

手続きを簡潔な表現で記述できることが多いが, 反面,慣れていないと,それを読みこなせない.


3. 動的に確保した記憶領域を参照する手段としてのポインタ

C言語では, 変数を記憶領域(メモリ)に割り当てる方法として,主に以下の2つがある.

自動変数 (auto)
関数内で型名の前に何も付けずに宣言した変数.
関数が呼び出される度にメモリ上に割り当て, 関数が終了すると割り当てを取り消す.
静的変数 (static)
関数外で宣言するか,関数内で型名の前に「static」を付けて宣言した変数.
プログラムを実行する最初にメモリ上に固定的に割り当てられる.
以上のいずれの場合も, 割り当てられる際のメモリの量はあらかじめ決まっていないといけない. 例えば,配列の要素数を,ある時には100, ある時には1000というような割り当て方はできない.

それでは不便なので,標準ライブラリには,OSの助けを借りて, 実行時に記憶領域を指定した量だけ確保する関数が用意されている (確保するだけでなく,解放する関数もあり).

ところが,このような領域に変数を割り当てることはできない. そこで,このような領域を「指す」ためポインタを用意し, 間接的な表現でそこへアクセスする.


4. データ構造を実現する要素としてのポインタ

Pascalなどの他のプログラミング言語で使われる「本来の意味のポインタ」. 「リスト」や「木構造」のような少し複雑な「データ構造」 を実現するためには欠かせない.

プログラミング言語を一通り習い終わった後に, さらにプログラミングの授業があるとすれば, たいてい「アルゴリズムとデータ構造」を学ぶことになるが, そのような時には必ずこのポインタが登場する. しかし,この演習では,ポインタのこの役割は, 構造体を学ぶ回に少し紹介するにとどめる.


5. メモリの実アドレスをアクセスする手段としてのポインタ

コンピュータによっては,メモリ空間内のあるアドレスに, 入出力のインターフェースが割り当てられることがある. 例えば,メモリのある番地の内容が画像取り込み装置が取り込んだ画像の明度のデータだったり, あるアドレスに値を書き込むことが装置への信号の出力だったりする.

ポインタ値としてメモリ番地を直接代入することは, 本来のC言語の仕様の範疇を越えているが,現実には, ハードウェアに関わるプログラムを作るにあたっては多用される方法である.


[演習1のインデックス] [前の教材(ちょっと進んだ内容)] [次の教材(補足(2):scanf()の問題)]