- ベストアンサー
C言語のポインタの考え方について
ポインタについて理解ができていないのでお聞きしたいのですが 値を交換する関数のプログラミングでこの場合ポインタ で以下にしないといけないと思います。 #include<stdio.h> void swap(int *a int *b){ int c; c=*a; *a=*b; *b=c; } main(){ int x,y; x=123; y=456; swap(&x,&y); printf("x = %d, y = %d\n", x, y); } またポインタを使用せず以下のプログラムではなぜダメのでしょうか。 よろしくお願い致します。 #include<stdio.h> void swap(int a int b){ int c; c=a; a=b; b=c; } main(){ int x,y; x=123; y=456; swap(x,y); printf("x = %d, y = %d\n", x, y); }
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
eiki0520さん、こんにちわ。 main(){ int x,y; x=123; y=456; ///////////////////// メモリの メモリの アドレス 値 …… …… 2000 13748 ←x は空いている番地に割当てられ、123がセットされる。 …… …… 2004 92852 ←y は空いている番地に割当てられ、546がセットされる。 …… …… …… …… ///////////////////// swap(x,y); //swap呼出し時のメモリは以下のようになる。 ///////////////////// メモリの メモリの アドレス 値 …… …… 2000 123 ←x の実態はココ …… …… 2004 456 ←y の実態はココ …… …… 2016 4898 ←x の"値のコピー"を入れる場所として、空いている番地が割当てられる。 …… …… 2020 125 ←y の"値のコピー"を入れる場所として、空いている番地が割当てられる。 …… …… ///////////////////// swap(int a,int b){ int c; c = a; a = b; b = c; ///////////////////// メモリの メモリの アドレス 値 …… …… 2000 123 ←x の実態はココ …… …… 2004 456 ←y の実態はココ …… …… 2016 456 ←a の実態が456に書き換わる。 …… …… 2020 123 ←b の実態が123に書き換わる。 …… …… ///////////////////// }; swapが受け取る引数は、あくまでも値がコピーされた別の変数ですので swapが受け取った引数に対して値の書き換えを行ってもmain()側のx,yの値は 変わりません。 これに対して、x,yのポインタを swap に渡す場合は以下のようになります。 swap(int* a,int* b){ int c; c = *a; *a= *b; // a は x のアドレス(例:2000)を指している。 *b= *a; // b は y のアドレス(例:2004)を指している。 ///////////////////// メモリの メモリの アドレス 値 …… …… 2000 456 ←x の実態が456に書き換わる。 …… …… 2004 123 ←y の実態が123に書き換わる。 .... .... ///////////////////// }; ※ポインタを使わず関数に引数を渡した場合、内部では「値をコピーした別の変数」が渡される。というルールがあることを覚えてください。 ※なぜ関数呼び出しの方法に「値渡し」と「アドレス(参照)渡し」があるのか疑問に思いませんか?用途によって、両者それぞれにメリット・デメリットがあります。それを理解されるとポインタの悩みはスッキリ解決するのではないかと思います。
その他の回答 (4)
- dennou2000
- ベストアンサー率62% (18/29)
C言語の大きな一つの約束事として、関数呼び出し時にパラメータの値そのものは変化 しないというのがあります。 なぜなら、呼び出し側が呼び出し時に渡した値は、呼び出される側で一旦その値をコピー して処理をするというのがC言語の仕様だからです。 従って、質問文の例の後者のプログラムでは、swap(int a,int b)では、 呼び出し側はswap(x,y)としてもswap(int a,int b)関数本体では(値をコピーするので) 変数x,yと同じ値を持つ変数x',y'で処理をしてしまいます。 結果、変数x'と変数y'の値は入れ替わりますが、変数x,yの値はそのままになってしまい ます。 これと前者のポインタを使ったswap関数はどう違うかを説明します。 まず、&x,&yとは、変数x,yがどこにあるかを示す値を示します。 (変数とはプログラムで使う値の場所に名前をつけたもの、もしくは値の入れ物に名前を つけたものと思ってください。そして&x,&yで得られる値が、その変数へのポインタと いうことになります。) そして、&x,&yの値が得られれば、変数x,yは操作可能です。 呼び出し側でswap(&x,&y)として呼び出すとswap(int *a,int *b)関数本体には(やはり 値をコピーするので)&x,&yと同じ値が渡されます。 すると、swap(int *a,int *b)関数本体では、&x,&yという変数x,yがどこにあるかを示す 値を受け取ります。従って、x,yがどこにあるかを知ることできます。 変数x,yの在り処が判れば、その中身をみる事も変更する事も可能です。 この観点で、前者のプログラムをみてみると void swap(int *a int *b){ int c; c=*a; // 変数aが指し示す変数の値を参照して、変数cに代入する。 // (実際には渡された&xの指し示す変数xを参照して、変数cに保存する) *a=*b; // 変数bが指し示す変数の値を参照してその値で変数aが指し示す変数 // の値を書き換える。 // (実際には渡された&yの指し示す変数yを参照してその値で、&xが指し // 示す変数xを変更する) *b=c; // 変数bが指し示す変数を変数cの値で書き換える // (実際には渡された&yの指し示す変数yを変数cで書き換える) } ということになります。
お礼
お世話になります。 ご回答ありがとうございます。 じっくり説明を読ませていただきます。
- nerosuke
- ベストアンサー率33% (39/115)
ポインタはまず感覚で覚えましょう。 たとえば デスクトップにAというフォルダとA.txtというテキストファイルをつくってみてください。 そして先程作ったAというフォルダのショートカットを作って見てください。 それでA.txtをそのショートカットに移動するとどうなりますか? A.txtはAというフォルダに入ってますよね? ポインタとはこういう感覚です。 実際はアドレス(ポインタ)にある数値のやり取りですが、 これは頭で理解しても実際使って恩恵を感じなければポインタを理解できません。 ためしに日本語で注釈を入れてみましょう。 void swap(int *a int *b){ //aに渡された場所(xのアドレス)とbに渡された場所(yのアドレス) int c; c=*a; //cにaに渡された場所にある箱(変数)の値を入れる *a=*b; //aに渡された場所にある箱の中にbに渡された場所にある箱の値を入れる *b=c; bに渡された場所にある箱にcの値を入れる。 } void swap(int a int b){ //aに渡された値(123) bに渡された値(456) int c; c=a; //cにaに渡された値を入れる a=b; //aにbに渡された値を入れる b=c; //bにcの値を入れる } 質問に書かれているソースでは上記と下記のものでは 明らかに実行結果が異なりますのでポインタを使わずに ポインタを使ったのと同じ結果のswap関数を作ってみて下さい。 そうすればポインタの感覚がわかると思います。
お礼
お世話になります。 わかりやすい説明ありがとうございます。 もう少しポイントを使うのと使わない場合で同じ処理ができるプログラムを考えてみたいと思います。 ご回答ありがとうございました。
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
後の方のプログラムで swap(int a,int b) の変数a ,b は、いわゆるスタックに確保されます。 main のx,y がスタックに積まれてswap が呼び出されると考えるといいでしょう。 つまり、a,b は、x,y のコピーの値が入った変数で 関数swap から復帰する時にはスタックは戻されて無くなります。 x,y 自体は別のmain で確保されたスタック上にあって、 swap での操作はx,y に影響を与えません。 最初のプログラムでは、x,y のアドレスを(スタックに積んで)swap で利用して、x,y 自体の内容を変更しているので、x,y 自体を操作しているのと同じになります。
お礼
お世話になります。 ご回答ありがとうございます。 ポインタを考える上での参考にさせていただきます。
- nebel
- ベストアンサー率37% (117/308)
メモリの概念はわかるのかな? わかりやすくいうと、変数っていうのは、値をいれる箱。 mainにあるxとyという箱にそれぞれ123と456というものをいれました。 swap(x,y); この部分では、xとyの箱の中身をaとbという箱に移しました(実際はコピー) で、aとbの箱の中身を入れ替えました。 このときxとyの箱の中身は?ってのと同じ。 xとyの箱の中身自体はいじってないから元のままでしょ? ポインタは、xとyの箱のある場所を教えて、swap()の中では、その場所にあるものを入れ替えますってやってる。
お礼
お世話になります。 ポインタを機にメモリの概念的な事も勉強していきたいと思います。 ご回答ありがとうございます。
お礼
お世話になります。 具体的にプログラム内でどう動いているのか細かく説明していただいた おかけでポイントを使うのと使わないので変数やその値がどのような 動きをするのかイメージすることができました。 ご回答ありがとうございます。