<戻る  目次  進む>  
          <戻 進> 雑誌 白黒 明暗   フォント 既定 ゴシック 明朝 手書き   サイズ   標準  


   &つけが必要な変数の正体   

  1. 第1項:&付き変数の正体
  2. 第2項:全ては値渡しである
  3. 第3項:scanf関数で&をつける理由

[1]&付き変数の正体

前節では、変数のアドレスを表示する方法について説明しました。
このとき、変数名の前に&をつけて表示していましたが、
この書き方は、第6章でscanf関数を使う時にも使いました。

つまり、&付き変数は、アドレスを表示する時だけに使われるのではなくて、
様々な所で使われている書き方なのです。

この&付き変数の正体は、非常に単純です。
実は、&は変数のアドレスを求める演算子なのです。
+や×などと同じように、なんらかの計算を行うための記号なのです。

どんな変数でも、&演算子を使うと、変数のアドレスを求めることが出来ます。
言い換えると、&演算子を使うと、その変数のメモリ上の番号を知ることが出来ます。

目次に戻る


[2]全ては値渡しである

前項では、&演算子を使うと、変数のアドレスを知ることが出来ると説明しました。
しかし、一体何のために、変数のアドレスを知る必要があるのでしょうか。
実は、これにはC言語の関数の仕組みが関係しているのです。

第12章では、自作関数と変数のスコープについて説明しました。
ここでは、引数という仕組みで、関数に数値を渡すことが出来ると説明しました。
しかし、この引数で渡すことが出来るのは、あくまでも数値です。
関数を呼び出す時に変数を指定した場合には、
変数に記憶されている値が、呼び出された関数の実引数にコピーされます。

つまり、引数で関数に渡されるデータは、全て数値であるということです。
この様に、引数で数値を渡す方式を、値渡しと呼ぶことがあります。


[  値渡し  ]
関数に単なる数値として情報を渡す方法。
ここで重要なのは、変数を実引数に指定しても、渡されるのは中身の数値である点です。
数値を受け取った関数では、それを元に色々計算して、結果を戻り値として返します。

通常はこれで問題ありませんが、もし、変数の中身を直接変更したい場合には困ります。
何故なら、関数に渡されたのは変数の中身のコピーに過ぎないので、
そのコピーをいくら変更しても、呼び出し側の変数には何の影響もありません。

そこで、&演算子を使ってアドレスを求めて、そのアドレスの数値を渡します。
そうすれば、関数に呼び出し側の変数のアドレス、すなわちメモリ上の番号がわかり、
その番号のメモリを書き換えてやれば、呼び出し側の変数を書き換えられます。
つまり、これが変数のアドレスを知る必要がある理由です。


[  参照渡し  ]
値渡しに対して、参照渡しという機能が存在する言語もあります。
これは、アドレスを渡す処理を言語の機能で自動的に行うことです。
C言語では、あくまでも値渡ししか出来ないのですが、
アドレスを渡すことを慣習的に参照渡しと呼ぶことがあります。

目次に戻る


[3]scanf関数で&をつける理由

前項で説明したことから考えれば、scanf関数で&をつける理由がわかると思います。
scanf関数は、キーボードからの入力を行い、変数に記憶する関数です。

しかし、前項で説明した通り、C言語では値渡ししか出来ません。
つまり、関数には変数に記憶された値のコピーしか渡すことが出来ません。
これでは、変数に新たな値を記憶することが出来なくなってしまいます。

その場合、前項で説明したように、変数のアドレスを数値として渡してやれば、
関数の側で、そのアドレスにデータを記憶することが出来るわけです。
これが、scanf関数で変数に&をつける理由です。

しかし、疑問なのは、文字列を入力する時は、配列名の前に&をつけなかったことです。
これは、前節で説明したように、配列名は配列の最初の要素のアドレスを表しています。
従って、配列名を渡せば、配列の場所がわかるため、&は不要です。

つまり、ある意味配列名でなくても、配列のアドレスさえ指定すれば良いのです。
例えば、次のようにすれば、配列名でなくても入力が出来ます。


#include <stdio.h>

int main(void)
{
	char str[256];
	scanf("%s",&str[0]); /* 0番の要素のアドレス */
	printf("%s\n",str);
	return 0;
}
このプログラムの実行結果は、次の通りになります。

MARIO キーボードから入力した文字列
MARIO
このプログラムは、配列名の代わりに、要素0番のアドレスを指定しただけです。
どちらも全く同じことを意味しているので、問題ありません。
更に、次のようにすれば、配列の途中から入力させることすら出来ます。

#include <stdio.h>

int main(void)
{
	char str[256] = "DRAGON";
	scanf("%s",&str[6]); /* 6番の要素のアドレス */
	printf("%s\n",str);
	return 0;
}
このプログラムの実行結果は、次の通りになります。

QUEST キーボードから入力した文字列
DRAGONQUEST
このプログラムでは、初期化の段階で配列に DRAGON の文字列を代入しています。
つまり、配列の0〜5番までには文字が既に代入されています。
そこで、scanf関数に6番要素のアドレスを指定して入力すれば、
文字列は6番要素から入力されるので、最初からの文字列と結合されています。

つまり、配列名だけを渡している場合、確かに見た目には&をつけていないのですが、
実際に行っていることは、&付きの変数を指定しているのと全く同じなのです。

目次に戻る


<−前に戻る  先頭に戻る  次へ進む−>