ポインタのアドレスの不変的な性質?

このQ&Aのポイント
  • 最近奇妙な現象?に遭遇しました。ソースコードによる説明と共に、ポインタのアドレスの不変性と呼べる性質について質問します。
  • ポインタのアドレスを関数に渡し、関数内でのアドレスの書き換えが呼び出し側に反映されない理由を知りたいです。目的を達成するための方法も教えてください。
  • 質問の要点:ポインタのアドレスの不変性として、関数内でのアドレスの書き換えが呼び出し側に反映されない現象について説明してください。
回答を見る
  • ベストアンサー

ポインタのアドレスの不変的な性質?

最近奇妙な現象?に遭遇しました。 理解している人には笑われるかもしれませんが・・・・ ソースを以下に示します。 #include <stdio.h> void function(int *pointer); void main(){ int sample=3; int *pointer; pointer=&sample; function(pointer); printf("%d\n", *pointer); } void function(int *pointer){ int temp=9; pointer = &temp; } 今上のソースとは別のプログラムを作成中で、上のような状態になっています。関数にポインタのアドレスを渡し、関数の中でアドレスを書き換えて表示を違うものにしようと考えました。 上の表示結果は3になります。なぜなのでしょう? そして目的を達したいため、上のように関数内でのアドレスの書き換えが呼び出し側に反映されるようにすることができないでしょうか? 分かる方はよろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • rabbit_cat
  • ベストアンサー率40% (829/2062)
回答No.2

まず、ポインタを書き換えたいなら、関数の引数はポインタのポインタにしないといけません。 それから、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)

回答No.10

だって、tempは関数functionの中だけで有効な変数やん。 関数の外に出たらtempって変数の存在自体なくなるやん。 値の有効な範囲・領域をちゃんと認識しましょね。

  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.9

#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言語ではポインタを値渡しします。

回答No.8

  > このような、間違いをするのは、ANSIの記法の弱点ではないかと思います  教え方の問題かも。 例えば、  関数の引数には、'値渡し' と '参照渡し(ポインタ渡し)' があり、 '値渡し' は、呼び出した関数で定義された変数の値がコピーされて渡されるので、 元の変数は影響を受けないが、 '参照渡し(ポインタ渡し)' は、呼び出された関数で元の値に直接アクセスして、 その値を書き換えることができる。 こんな風に教わると、今回のような場合は、 "ポインタが渡されているので、元("main"関数内の"pointer")の値が書き換えられる。" と思ってしまう人も出てくるんじゃないだろうか。  

回答No.7

このような、間違いをするのは、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++の記法には、プログラムを、却って難解にするような面があるような気がします(私見ですが)。

回答No.6

   "temp"をつかってなかった。 void func(int **pointer) { int *temp = malloc(sizeof(int)); *temp = 9; *pointer = temp; return; }  

回答No.5

   別解 #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; }  

回答No.4

  > これ、ダメです。すごく危険。  この場合は、関数を抜けたときに"temp"といっしょに"pointer"も 開放されるので、何の危険もない。ただし、意味もない。 > たまたまだと思います。  たまたまじゃない。 "func"関数での処理結果は、"main"に渡されていないので、 元の値が表示されているだけ。 void function(int **pointer){ int temp=9; *pointer = &temp; return; }  これは、危険。  

  • Interest
  • ベストアンサー率31% (207/659)
回答No.3

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)
回答No.1

>上の表示結果は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 の外に伝播されます。 # たまには長々と回答してみる。

関連するQ&A

  • ポインタいついて教えてください

    ポインタがわかりません。 教えてください。 下の二つは、共に「100」を表記すると思いますが、 どこがどのように違うのですか。 また、f1()という関数をつくって、ここで scanfを使って、5つぐらい値を代入させて、 他の関数でこの値を使おうと思っています。 この場合下のどちらを使うのが、よろしいのでしょうか。 よろしくお願いします #include <stdio.h> int main(void) { int *p, q; q = 100; /* q に100を代入 */ p = &q; /* p にq のアドレスを割り当てる */ printf("%d", *p); return 0; } #include <stdio.h> int main(void) { int *p, q; p = &q; /* q のアドレスを得る */ *p = 100; /* ポインタを使ってq に値を代入する */ printf("%d", q); return 0; }

  • C 関数とポインタ

    ポインタと関数がよく分かりません。 (日本語がおかしくてすみません(^_^;)) たとえば↓のようなプログラムで、 #include <stdio.h> void increase(int *i); int main(void) { int x = 3; increase(&x); printf("%d\n", x); return 0; } void increase(int *i) { (*i)++; } 結果は4になりますが、increase(&x)が&xとなっていて、 関数はvoid increase(int *i)でint *iになっているのですが、 これはvoid increase(int *i)はint型の「ポインタ」なので、 increase(&x)も&xと「アドレス」を渡さなければいけないということですか?? そして、void increase(int *i)内では、アドレス&xの指す値をインクリメント、という考えで良いのでしょうか?

  • ポインタ定義は必要なんですか?

    #include <stdio.h> int main( void ) { int x; int *p; p = &x; printf("Address = %p\t\n", p ); return 0; } を #include <stdio.h> int main( void ) { int x; int p;←ここを上とはかえた p = &x; printf("Address = %p\t\n", p ); return 0; } にしたところコンパイル時に p = &x に関して 移植性のないポインタ変換と表記されますが 結果は同じだったのでポインタ定義というのは結局必要なんですか? 移植性のないポインタ変換とはなんなんですか? よければ詳しく教えてください

  • 教えてポインタ

    例えば、以下のようなソース。 関数の中で、引数のポインタに値を入れてmainに戻す。 とても簡単なものです。 void func(int *N) {  *N=0; } main {  int  *N=1;  func(N);  printf("%d",*N) } 疑問は、ここからです。 (1)void func(int  *N) (2)void func(int*  N) (3)void func(int*  &N) 上記は、何が違いますか? なお、当方のVS2010で同じソースを作ると、 (1)の場合、エラーになります。(func関数の*N=0のところでダウン) (2)だと、OKになります。 (3)は、なに?

  • ポインタについて

    今初めてポインタというものを勉強しております。 よろしくお願いします。 ◎1---------------------------------- #include<stdio.h> int main(void) { int mydt=1234; int *pt; pt=&mydt; printf("*pt=%d\n",*pt); printf("&mydt=%p\n",&mydt); return 0; } --------------------------------------- ◎1のようにmydtのアドレスをポインタptに代入すれば、このプログラムは正常に動きました。 ◎2----------------------------------- #include<stdio.h> int main(void) { int mydt=1234; int *pt=&mydt; printf("*pt=%d\n",*pt); printf("&mydt=%p\n",&mydt); return 0; } ---------------------------------------- ◎2で「int *pt=&mydt;」があまりどういう意味かはわかりませんが、これも正常に動きました。 ◎3------------------------------------ #include<stdio.h> int main(void) { int mydt=1234; int *pt; *pt=&mydt printf("*pt=%d\n",*pt); printf("&mydt=%p\n",&mydt); return 0; } -------------------------------------- ◎3のように◎2と違って「*pt=&mydt」の代入を後から行うと、「'=' : 'int *__w64 ' から 'int' に変換できません。」といったようなエラーが起きてしまいます。 ◎1と◎2の違い、後何故◎3はダメなのかがわかりません。 教えていただけると嬉しいです。 後補足として、配列とポインタについてですが、 ◎4------------------------------ char ss[10]="ABCDE"; char *ssp=ss; --------------------------------- ◎5---------------------------- char ss[10]="ABCDE"; char *ssp; ssp=ss; -------------------------------- ◎4と◎5も同じような事だとは思いますが違いを教えていただけると嬉しいです。 よろしくお願いします。

  • C++ ポインタ初級

    C++で、自作関数内でメインの数字をインクリメントします。 自作関数はVOIV型でやりたいんです。 #include <stdio.h> void plus( int * ); main( ){  int a = 1;  int *&p = &a;  plus( p );  printf( "%d" , *p ); } void plus( int *i ){  ( *i )++; } int型の変数を2つ宣言したけど、1つでやる方法はないですか? #include <stdio.h> void plus( int * ); main( ){  int a = 1;  plus( &a ); // aのアドレスを渡して、  printf( "%d" , a ); } void plus( int *i ){ // アドレスの値を  ( i )++; // インクリメントしたつもりだけど } 結果は1のままでした。

  • Javaでポインタ的なことはできるか?

    JavaでC言語のようにポインタを使おうとしたらJavaには ポインタが表面上はサポートされていないことを知りました。 関数を呼び出した際に、呼び出し元の変数に影響を与えるようなプログラムは Javaで作れるのでしょうか? 例えば、以下のプログラムはCで関数を呼び出した際に呼び出し元の 変数の中身を関数内で書き換えてしまうプログラムです。 こういうことをJavaでするにはどう書けばよいのでしょうか? もしこういうことができないのであれば、Javaにはポインタに代わるやりかたがあるのでしょうか? 実行結果: 1 10 #include <stdio.h> void func( int *n ){   *n = 10; } int main(){   int n = 1;   printf("%d ", n );   func( &n );   printf("%d ", n ); }

    • ベストアンサー
    • Java
  • CでいうポインタみたいなことをJAVAでも・・・

    Cでいうポインタを使ったプログラム #include <stdio.h> void nibai (int *a , int *b) {   *a *= 2;   *b *= 2; } int main(void) {   int a=3 , b=5;   nibai(&a,&b);   printf("a=%d b=%d\n",a,b);   return 0; } nibai関数はint型のアドレスを貰ってそのアドレスが指す値を書き換えているためmain関数に戻った際に値が変化している。 このようなことをJAVAでやりたいんですけど方法が見当たりません。 グローバルで共有するしか方法はないのでしょうか? CかつJAVAを知っている方限定の質問になってしまいますが よろしくお願いします。

    • ベストアンサー
    • Java
  • 【C言語】別関数でポインタの値を変えたのに変わらない。

    【C言語】別関数でポインタの値を変えたのに変わらない。 メイン関数のポインタの値を、別関数で書き換えるプログラムを作りました。 以下がそのプログラムになります。 そのままだと、ダブルポインタを操作する必要があるので分かり辛いです。なので、ダブルポインタをシングルポインタにしてからポインタの書き換えを行うようにしました。その結果、きちんとポインタの書き換えが出来なくなってしまいました。 なぜ出来なくなってしまったのでしょうか。 2つのプログラムの違いは、 >  *pp = &dummy; が >  p = *pp;      // ダブルポインタをシングルポインタにした >  p = &dummy; に変わっただけです。 【参考】http://www.kouno.jp/home/c_faq/c4.html#8 -----------------正しいプログラム---------------- // 以下プログラムは、正しく動作する // 実行結果は、 //   p = 5 // と表示される void func( int **pp ); int main (void){   int *p;   int a = 0;   p = &a;   func( &p );   printf("p = %d\n", *p);   return 0; } void func( int **pp ){   static int dummy = 5;   *pp = &dummy; } ---------------------------------------------- -----------------間違いプログラム---------------- // 以下プログラムは、正しく動作しない // 実行結果は、 //   p = 0 // と表示される void func( int **pp ); int main (void){   int *p;   int a = 0;   p = &a;   func( &p );   printf("p = %d\n", *p);   return 0; } void func( int **pp ){   static int dummy = 5;   int *p;   p = *pp;      // ダブルポインタをシングルポインタにした   p = &dummy; } ----------------------------------------

  • 関数ポインタについて

    関数ポインタを使用する際に、 指定する先の関数でデフォルト引数が指定されている場合、 関数ポインタを用いて、その引数を省略して呼び出すことはできるのでしょうか? 以下例とします。 void function(int a = 10){}; typedef void (*test)(int a); test a = &function; a(); //このように呼び出したい

専門家に質問してみよう