- ベストアンサー
ポインタのアドレスの不変的な性質?
- 最近奇妙な現象?に遭遇しました。ソースコードによる説明と共に、ポインタのアドレスの不変性と呼べる性質について質問します。
- ポインタのアドレスを関数に渡し、関数内でのアドレスの書き換えが呼び出し側に反映されない理由を知りたいです。目的を達成するための方法も教えてください。
- 質問の要点:ポインタのアドレスの不変性として、関数内でのアドレスの書き換えが呼び出し側に反映されない現象について説明してください。
- みんなの回答 (10)
- 専門家の回答
質問者が選んだベストアンサー
まず、ポインタを書き換えたいなら、関数の引数はポインタのポインタにしないといけません。 それから、function内のローカル変数(temp)のポインタを返してはいけません。 あと、mainは、intを返すようにするほうがいいです。(少なくとも規格ではそういうことになっています。) 直すとしたらこんな感じか #include <stdio.h> void function(int **pointer); int main(){ int sample=3; int *pointer; pointer=&sample; function(&pointer); printf("%d\n", *pointer); return 0; } void function(int **pointer){ static int temp=9; *pointer = &temp; }
その他の回答 (9)
- maronii_now
- ベストアンサー率0% (0/8)
だって、tempは関数functionの中だけで有効な変数やん。 関数の外に出たらtempって変数の存在自体なくなるやん。 値の有効な範囲・領域をちゃんと認識しましょね。
- aris-wiz
- ベストアンサー率38% (96/252)
#include <stdio.h> void function(int *pointer); void main() { int sample=3; int *pointer; //pointerはsampleへのアドレス pointer=&sample; printf("%d\n", *pointer); //pointerはsampleへのアドレス function(pointer); printf("%d\n", *pointer); //pointerはsampleへのアドレス printf("%d\n", *pointer); } void function(int *pointer) { //pointerはmainのpointerのコピーつまりsampleへのポインタ int temp=9; //pointerはtempへのポインタ pointer = &temp; printf("%d\n", *pointer); //tempが破棄される //pointerのコピーが破棄される } やるなら #include <stdio.h> void function(int *pointer); void main() { int sample=3; int *pointer; //pointerはsampleへのアドレス pointer=&sample; printf("%d\n", *pointer); //pointerはsampleへのアドレス function(pointer); printf("%d\n", *pointer); //pointerはsampleへのアドレス printf("%d\n", *pointer); } void function(int *pointer) { //pointerはmainのpointerのコピーつまりsampleへのポインタ int temp=9; //pointerの中身つまりsampleへtempの値を代入 //ここでMainのsampleが9へ *pointer = temp; printf("%d\n", *pointer); //tempが破棄される //pointerのコピーが破棄される } 厳密にはC言語ではポインタを値渡しします。
- yaemon_2006
- ベストアンサー率22% (50/220)
> このような、間違いをするのは、ANSIの記法の弱点ではないかと思います 教え方の問題かも。 例えば、 関数の引数には、'値渡し' と '参照渡し(ポインタ渡し)' があり、 '値渡し' は、呼び出した関数で定義された変数の値がコピーされて渡されるので、 元の変数は影響を受けないが、 '参照渡し(ポインタ渡し)' は、呼び出された関数で元の値に直接アクセスして、 その値を書き換えることができる。 こんな風に教わると、今回のような場合は、 "ポインタが渡されているので、元("main"関数内の"pointer")の値が書き換えられる。" と思ってしまう人も出てくるんじゃないだろうか。
- gyrocompas
- ベストアンサー率23% (24/104)
このような、間違いをするのは、ANSIの記法の弱点ではないかと思います(私見ですが) function(int *pointer) { } は、古い記法では function (pointer) int *pointer; { } となります。 この記法だと、funcのpointerの領域が、func側に確保されることがなんとなく理解でき、 int main() { int *pp; func(pp) } とすれば、 定義側と呼び出し側の引数の括弧内が同じ書き方になり pp->pointer と、一致する、このことで、 pp の値がfuncのpointerにコピーされるのであり、ppの領域は全く影響されず値は基のままだと理解できるかなと思えます。 ANSIやC++の記法には、プログラムを、却って難解にするような面があるような気がします(私見ですが)。
- yaemon_2006
- ベストアンサー率22% (50/220)
"temp"をつかってなかった。 void func(int **pointer) { int *temp = malloc(sizeof(int)); *temp = 9; *pointer = temp; return; }
- yaemon_2006
- ベストアンサー率22% (50/220)
別解 #include <stdio.h> #include <stdlib.h> void func(int **pointer) { *pointer = malloc(sizeof(int)); **pointer = 9; return; } int main(void) { int sample = 3; int *pointer = &sample; printf("%d\n", *pointer); func(&pointer); printf("%d\n", *pointer); free(pointer); return 0; }
- yaemon_2006
- ベストアンサー率22% (50/220)
> これ、ダメです。すごく危険。 この場合は、関数を抜けたときに"temp"といっしょに"pointer"も 開放されるので、何の危険もない。ただし、意味もない。 > たまたまだと思います。 たまたまじゃない。 "func"関数での処理結果は、"main"に渡されていないので、 元の値が表示されているだけ。 void function(int **pointer){ int temp=9; *pointer = &temp; return; } これは、危険。
- Interest
- ベストアンサー率31% (207/659)
void function(int *pointer){ int temp=9; pointer = &temp; } これ、ダメです。すごく危険。 なぜかというと、関数内で宣言された変数はスタックに確保されるからです。だから、関数を抜けたら変数 temp は解放されてしまって、他人の手に渡ってしまい、temp があったアドレスに何が書き込まれるか保証できないのです。 > 上の表示結果は3になります。なぜなのでしょう? たまたまだと思います。きっと debugモードとreleaseモードで値が違ったり、環境が違ったりしたら値が3でなくなるものと思います。なにせ、スタックに確保されたメモリが解放されているのですから。 > 関数にポインタのアドレスを渡し、関数の中でアドレスを書き換えて ポインタの概念や言葉の意味を正しく理解していないせいで、このような表現になったものと思います。「ポインタのアドレス」というところが混乱してしまっています。例えば、 int *pointer; // ←これポインタ &pointer // ←これポインタのアドレス int temp=9; pointer = &temp; // ←この場合は、ポインタ「に」アドレスを渡す です。もっとも、やっちゃダメな例ですが。 > 関数内でのアドレスの書き換えが呼び出し側に反映される > ようにすることができないでしょうか? 関数内でポインタが指すアドレスを変更したい、ということですよね? その場合、変更後にポインタが指すアドレスの領域が、関数を抜けたあともちゃんと確保されているところを指してあげましょう。 ローカル変数や関数の引数はスタック領域から確保される。 malloc, calloc, newなどはヒープ領域から確保される。 基本的なことですが教科書に書いてなかったりするので覚えておきましょう。 > 目的を達したいため、 もうちょっと具体的に何をしたいのか書いてもらえれば、どうやってメモリを確保して、ポインタ付け替えればいいか考えてみますよ。
- koko_u_
- ベストアンサー率18% (459/2509)
>上の表示結果は3になります。なぜなのでしょう? わかり難いので function の方の引数を void function(int* pt) { int temp = 9; pt = &temp; } として、pt には main の中で宣言されている pointer の値(アドレス値)がコピーされて格納されます。 function の中で pt = &temp とその「値」を書き換えても main の pointer のアドレス値に影響はありません。 function の中で *pt = 9 などと、pt の指す先を変更すれば、pt の指す先は pointer の指す先と同じ( sample )であるため値が function の外に伝播されます。 # たまには長々と回答してみる。