値渡し、アドレス渡しが分からない。
アドレス渡しと値渡しの違いが分からない。
この記事を読めばこれらの悩みを解決できます。
値渡しとアドレス渡しを分かりやすく説明をするために、「値渡しを使って、2つの変数に代入された値を入れ替えるプログラム」と、「アドレス渡しを使って、2つの変数に代入された値を入れ替えるプログラム」を作っていきます。
値渡しを使って値の入れ替え
値渡しとは、ある変数に、別の変数内の値を代入することで渡す方法です。(つまり、普通の代入と同じです。)この値渡しという方法を使って、2つの変数内の値を入れ替えるプログラムをつくっていきます。
例えば、「a」、「b」という値を変数宣言した後「a=3」「b=5」と代入するとします。その後、うまくプログラムをつくり、「a」と「b」の値を交換することで「a=5」「b=3」にします。
今回はこのようなプログラムをつくるのですが、よくある起こしやすいミスがあります。そのミスがこちらです。
#include<stdio.h>
int main()
{
int a, b;
a = 3;
b = 5;
a = b;
b = a;
printf("%d %d", a, b);
}
一見正しいプログラムのように見えますが、このまま出力すると「a」と「b」が両方「5」という数字を出力してしまいます。
何がいけないと思いますか?
実は、「a=b;」とすることで「a」には「b」の値「5」が代入されます。その次に、「b=a;」とすると、先ほど「a」に代入された「5」という数字を「b」にも代入することになるんです。
工夫して値渡しを使おう
ではどうすれば、「a」と「b」の値を入れ替えられるのでしょうか?
ここで、もう一つの変数「tmp」を使うことで可能になります。(変数の名前は何でも大丈夫です)
もう一つの変数に値を代入しておくことで、「a」と「b」どちらかの値が消えるということがなくなるという考え方です。
具体的に説明します。
最初に「a」、「b」、「tmp」を変数宣言し、「a=3;」「b=5;」というように代入をします。
ここからがポイントです。値を入れ替えるときに、「tmp=a;」とすることで、一旦「a」の値を「tmp」に代入します。
次に、「a=b;」、最後に「b=tmp;」とすることで「tmp」に代入されていた値を「b」に移すことができます。
こうすることで「a」と「b」の値を入れ替えることができます。
#include<stdio.h>
int main()
{
int a, b,tmp;
a = 3;
b = 5;
printf("a b¥n¥n");
printf("%d %d¥n", a, b);
tmp = a;
a = b;
b = tmp;
printf("%d %d", a, b);
}
このようにプログラミングコードを書けます。出力したときに分かりやすいように1行目に「a」「b」と、2行目に「aとbを交換する前の値」を表示するプログラムを作りました。
このようにして、値渡しでも2つの変数の値を入れ替えることができます。
アドレス渡しを使って値の入れ替え
2つのアドレス(住所)を交換することで、変数内の値も交換することができます。これをアドレス渡しと言います。
アドレス渡しのやり方を順番に説明します。
変数宣言
まず、変数を扱うので変数宣言をする必要があります。ここでは値渡しをするので「a」、「b」、「tmp」の3つの変数を使います。
さらに、アドレスを扱うので「*pa」、「*pb」の2つのポインタも必要です。
よって、このように変数宣言します。
int a,b,*pa,*pb,tmp;
変数の代入
次に、値を代入するのですが、代入をする必要があるのは「a」、「b」、「tmp」つまり変数だけです。「*pa」、「*pb」はポインタなので代入する必要がありません。今回は「a=3」「b=5」「tmp=0」とします。tmpに代入する値は実際何でも良いのですが、何でもよい場合は基本「0」を代入します。(このように、「0」を代入することを初期化と言います)
a = 3;
b = 5;
tmp = 0;
ポインタで変数のアドレスを調べる!
こちらの記事で紹介した「ポインタの性質」を利用したものが、「アドレス渡し」です。
アドレス渡しとは、ポインタのアドレスに他の変数のアドレスを代入し、変数に代入されていた値も、自動的にポインタ内に保存されることで、ポインタに値を渡す方法です。この時、変数でなくて、また別のポインタでも問題ないです。
pa=&調べたい変数;
こうすると、変数のアドレスをポインタのアドレスに代入できます。
では、さっそくアドレス渡しのプログラムをつくってみましょう。
最初に、必要な変数とアドレスを用意します。このプログラムでは、変数は3つ、ポインタは2つ使います。こういう感じです。
int a,b,*pa,*pb,tmp;
次に、aに「3」、bに「5」を代入します。最終的には、この値を入れ替えたいので、とりあえず、それぞれポインタに代入します。
pa=&a;
pb=&b;
アドレス渡しをした前後の変化が分かるようにこの状態でいったん出力します。
printf("a b\n\n");
printf("%d %d¥n", *pa, *pb);
2行目で「*pa」と「*pb」が調べたアドレス内の値を出力することができます。また、1行目は「a」と「b」のそれぞれの変化を分かりやすくするために書いています。
アドレス渡し
「*pa」に「a」の値、「*pb」に「b」の値が保存されているので、このようなミスをしやすいです。値渡しで説明したのと同じミスですね。
*pa = *pb;
*pb = *pa;
このままだと、「*pa」に「*pb」の値が入りますが、「*pb」には「*pb」の値のままになので、ここで変数「tmp」を使うことになります。
tmp = *pa;
*pa = *pb;
*pb = tmp;
どの行も値渡しをしています。
最後にこの状態でポインタの値を出力します。
printf("%d %d", *pa, *pb);
ここまでをまとめると、このようになります。
#include<stdio.h>
int main()
{
int a,b,*pa,*pb,tmp;
a = 3;
b = 5;
tmp = 0;
pa = &a;
pb = &b;
printf("a b¥n¥n");
printf("%d %d¥n", *pa, *pb);
tmp = *pa;
*pa = *pb;
*pb = tmp;
printf("%d %d", *pa, *pb);
}
出力結果です。「5」と「3」が入れ替わりました。
このようにアドレスを入れ替えることで変数内の値を入れ替えることができます。
まとめ
アドレス渡しよりも値渡しの方が簡単ですが、どちらも関数で重要な考え方なので、どちらも使えるようにしましょう。値渡しやアドレス渡しは、関数の勉強で必要になります。
次は、関数を勉強してみましょう。
コメント