![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?e8efa67)
最近奇妙な現象?に遭遇しました。
理解している人には笑われるかもしれませんが・・・・
ソースを以下に示します。
#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になります。なぜなのでしょう?
そして目的を達したいため、上のように関数内でのアドレスの書き換えが呼び出し側に反映されるようにすることができないでしょうか?
分かる方はよろしくお願いします。
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;
}
No.10
- 回答日時:
だって、tempは関数functionの中だけで有効な変数やん。
関数の外に出たらtempって変数の存在自体なくなるやん。
値の有効な範囲・領域をちゃんと認識しましょね。
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;
}
これは、危険。
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などはヒープ領域から確保される。
基本的なことですが教科書に書いてなかったりするので覚えておきましょう。
> 目的を達したいため、
もうちょっと具体的に何をしたいのか書いてもらえれば、どうやってメモリを確保して、ポインタ付け替えればいいか考えてみますよ。
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が見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- C言語・C++・C# C言語初心者 ポインタについて、お助けください、、 2 2023/03/15 23:50
- その他(プログラミング・Web制作) 十進BASICでの再帰についての質問です。 2 2022/11/18 09:17
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# c言語の問題です 課題1 (二分探索木とセット) 大きさ size の配列 array を考える。す 2 2023/01/10 21:08
- C言語・C++・C# 至急教えてください! プログラミングの問題です! お願いします! 出力2と全く同じ出力をするように、 2 2022/06/22 23:10
- C言語・C++・C# C pointer? or... 2 2022/03/29 00:47
- C言語・C++・C# C言語 3 2022/10/04 15:07
- C言語・C++・C# C 言語の Gauss Jordan 法について 2 2022/12/28 11:16
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語のポインタに直接アドレス...
-
ポインタのミスでOS壊れるの...
-
printfとscanfの違いって・・・
-
fopne で失敗する原因
-
セグメントエラー
-
LPSTR型の初期化について
-
main(int argc,char **argv[])...
-
プーさんのマウスポインタを教...
-
Run-Time Check Failure #3とい...
-
【なぜポインタを使うのか】
-
ポインタのアドレスの不変的な...
-
参照型で受け取った引数をポイ...
-
%dなどの違い
-
関数から配列を返すには?
-
VBScriptで重複レコードを削除...
-
C言語 配列の長さの上限
-
c言語プログラミング 等差数列...
-
nullと""、\\0とEOFの違いにつ...
-
アセンブラでのメモリの動的確...
-
構造体でchar name[]と*nameの...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
セグメントエラー
-
C言語のポインタに直接アドレス...
-
fopne で失敗する原因
-
init関数の意味
-
Run-Time Check Failure #3とい...
-
戻り値で構造体を返すことは可...
-
LPSTR型の初期化について
-
Cで作成したDLL関数をVBから呼...
-
ExcelVBAでのkernel32(64bit)
-
アプリを32bitから64bit移行
-
構造体とfscanf
-
c言語で任意のファイルから読み...
-
デバイスハンドルとは?
-
main(int argc,char **argv[])...
-
基本アルゴリズムの『返す』の...
-
コンストラクタでnewを失敗した...
-
C言語の関数と配列に関する質問
-
参照型で受け取った引数をポイ...
-
ハンドル、アドレス、ポインタ...
-
DLL<->VB間での受け渡し(文字...
おすすめ情報