next up previous
Next: 6 ポインタ変数 Up: C言語ポインタのしくみ - コンピュータのしくみとポインタの関係 - Previous: 4 変数へのアクセス


5 アドレス演算子(&)と間接演算子(*

プログラミング言語は名前を使って変数への代入やその参照をするように作られています.しかし,2節で簡単に説明したように,実用的なプログラムを作成する場合にはそれだけでは十分ではありません.C言語ではアドレスを介して変数にアクセスすることもでき,それを実現する手段として2つの演算子( &* )が用意されています.

& は変数が割り当てられているメモリのアドレスを得る演算子で「アドレス演算子」と呼ばれています.例えば,変数 x1000 番地に割り当てられていたとすると &x の値は 1000 になります.このとき,&x を「変数 x への『ポインタ』」あるいは「変数 x を指す『ポインタ』」と呼びます.ポインタは「ポイント(point)するもの」つまり「指し示すもの」という意味です.ポインタはアドレスをC言語的に抽象化したものです.scanf を用いるときに変数名に & をつけていたのは,scanf がポインタを必要とする関数だからです.


\begin{picture}(230,100)(150,0)
\psset{unit=\unitlength}
\put(160,80){\makebox(6...
...extbf{\&x は 1000}}}}
\thicklines\put(220,40){\framebox (60,20){}}
\end{picture}

一方,scanf のような関数を作成する場合には,与えられたポインタを用いて変数への代入を行う必要があります.4 節で説明したように,変数へのポインタ,すなわち変数のアドレスがわかれば,そのメモリに値を書き込むことで代入を行うことができます.このとき,アセンブラ言語でやっていたように,1000 番地のメモリを [1000] という名前の変数のように扱えれば便利です.

このようなことを行うために,C言語には * があります.* はかけ算の演算子と同じ記号を用いていますが,その意味は全く違います.例えば,*(1000) はアセンブラ言語で [1000] と書いていたものに対応し,1000 番地のメモリを変数として扱うことを意味します.よって,

*(1000) = 10;
は,1000 番地のメモリに 10 を代入することを意味します.このように,* はポインタが指すメモリをC言語の変数として扱うための演算子で「間接演算子」と呼ばれています.本当は 1000 などの数値定数でポインタを与えることはできませんが,原理をわかりやすく説明するために,ここではあえて数値定数を使って説明します.また,括弧はわかりやすくするために入れてあるだけで,括弧がなくても意味は同じ,つまり,*(1000)*1000 は同じ意味です.* は単なる通し番号であるアドレスから変数という実体をよみがえらせる演算子です.


\begin{picture}(245,130)(135,-30)
\psset{unit=\unitlength}
\put(160,80){\makebox...
...es\put(220,40){\framebox (60,20){10}}
\put(140,0){\line(0,1){0.1}}
\end{picture}

以上の2つの演算子を用いた簡単なプログラムをつぎに示します.


プログラム 5.1
 1: /* ポインタを用いた変数への代入 */
 2: 
 3: #include <stdio.h>
 4: 
 5: /* メイン */
 6: main()
 7: {
 8:     int x;
 9: 
10:     x = 1;                      /* x の初期化           */
11:     printf( "x = %d\n", x );    /* 変数の内容の表示     */
12: 
13:     *(&x) = 0;                  /* ポインタを用いた代入 */
14:     printf( "x = %d\n", x );    /* 変数の内容の表示     */
15: }
プログラム 5.1 の12行目は x に 1 を代入し,13行目はその結果を表示しています.一方,15行目はポインタを用いて代入を行い,16行目で再び x の内容を表示しています.このプログラムを実行すると,以下の結果が得られます.
x = 1
x = 0
プログラム中に x = 0 と書いたわけでもないのに,x の値が変化していることに注意して下さい.

15行目の &xx のアドレスをあらわします.さらに,&x* を用いると,そのアドレス &x が指すメモリを変数とみなすので,*(&x)x と同じ変数に,*(&x) = 0x = 0 と同じ動作になります.その結果,x の値は 0 になります.

単に変数に代入するだけなら,こんな面倒なことをする必要はありません.しかし,関数から値を受けとる場合には,このしくみが重要な役割を果たします.関数を呼び出すときには,引数に値を渡すことしかできません.よって,そのままでは関数の内部から関数外部の変数に値を代入することはできません.ポインタを用いると,変数への代入が,一旦,ポインタという数値を経由して行われます.2 節に出てきた銀行口座の例を思い出すと,変数が銀行口座,ポインタがその口座番号に相当します.口座番号がわかれば,どこでも預金の出し入れができるのと同様に,変数へのポインタさえ知っていれば「離れた」場所から変数への代入を行うことができます.そこで,関数を呼び出すときに,変数のポインタを引数に渡しておけば,* を用いることで関数の内部から関数の外部の変数に値を代入することができるようになります.scanf を呼び出すとキーボードからの入力が変数に代入されるのは,このようなしくみによります.


\begin{picture}(520,270)(0,-150)
\psset{unit=\unitlength}
\psset{arrowscale=2}
%...
...ox(260,20){\textbf{ポインタを介して関数1の変数にアクセス可能}}}
%
\end{picture}


next up previous
Next: 6 ポインタ変数 Up: C言語ポインタのしくみ - コンピュータのしくみとポインタの関係 - Previous: 4 変数へのアクセス
Toru Asai