ページ 1 / 1
関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月21日(月) 18:50
by ケトン
たとえば次の関数を宣言(定義)するときに
コード:
void swap (int *pX,int *pY);
引数には*pX,*pYの二つ(変数の値!)があって,
関数を呼び出すときに
引数には二つの変数のアドレス!を使います。
なぜ,宣言(定義)するときは値で,実際使うときはアドレスを引数にするのですか?
理由もしくは考え方の間違っているところをおしえてください。お願いします。
Re: 関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月21日(月) 19:49
by みけCAT
アドレスは値の一種です。
ケトンさんの考える「値」「アドレス」の定義を教えていただけますか?
Re: 関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月21日(月) 20:03
by ケトン
例えば変数aを
で初期化したとき、10がaの値、&aがaのアドレスということです。
*pAは僕のいう「値」で、pAは「アドレス」のはずなのに、どうして質問のようなことが起こるのでしょうか。
Re: 関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月21日(月) 20:19
by みけCAT
ケトン さんが書きました:コード:
void swap (int *pX,int *pY);
引数には*pX,*pYの二つ(変数の値!)があって
ありません。
引数はint *型(ポインタ型 = アドレスが入る)のpXとpYです。
でポインタ型の変数pAにaのアドレスを入れるのと同じようなものですね。
Re: 関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月21日(月) 21:28
by C6b14
あ 質問の 意味が 閃いた ので 書いておきます。 この場合は 関数 の 問題です。
厳密にいうと a には 値 と アドレス が あって 中身 と 箱 の関係 です。
引数には 2種類あって 仮引数 と 実引数 です。
void swap (int *pX,int *pY);
この関数の場合は a のアドレスを コピーして渡し て くださいと 言っています。(機械語ではスタックメモリーをアドレスが入る分用意する)
void swap (int pX,int pY);
この関数の場合は a の値(中身)を コピーして渡し て くださいと 言っています。(機械語ではスタックメモリーを値が入る分用意する)
関数の宣言時 欲しいの はスタックメモリーの用意する容量であって つまりは型情報 です。( int * ,int * )だけで pX ,pY は何でもよいので Foo, Hoge でもいいはずです。
呼び出すときは swap (&num1,&num2);
の num1, num2 は int として 「宣言」 が必要です。
[ アドレス渡し] [値 渡し] については
我々はあまりにも常識化して疑問がわかないけれど 誰もが 一度は 疑問に 思ったはずです。
Re: 関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月21日(月) 21:57
by C6b14
あごめんなさい。 a のところは pX, pY の間違い です。
Re: 関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月21日(月) 22:21
by あんどーなつ
カーニハン、リッチー著「プログラミング言語C 第2版」のp. 114に非常に興味深い記述があります。
(※著者はC言語の開発者)
ポインタipの宣言
int * ip
は記号表現として、*ipという表現がintであることを表わす。変数に対するこの宣言の構文は、変数が現われる式の構文を真似たものである。この解釈は関数の宣言にも当てはまる。例えば
double *dp, atof(char *);
は、ある式の中で*dpとatof(s)がdoubleの型をもち、atofの引数がcharへのポインタであることを表わす。
私は上記のことをアフォーダンスに優れているとは思いませんが、答えにはなっているでしょう。
値渡し、アドレス渡しというのは、あまり考えなくてよいと思います。江戸幕府の成立はいつなのか、というような議論と同じだとおもってください。
Re: 関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月21日(月) 23:23
by C6b14
失礼いたしました。”値渡し、アドレス渡しというのは” 間違い。 ”関数の アドレス を呼びだす 仕組みは” とかくつもりが 今読むと変な事を書いてました。 ごめんなさい。
Re: 関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月21日(月) 23:35
by box
ケトン さんが書きました:
コード:
void swap (int *pX,int *pY);
引数には*pX,*pYの二つ(変数の値!)があって,
ここを即値とお考えでしたらちょっと違うと思います。
int *型の値ですから、中身は変数のアドレス値です。一方、
呼び出す側では、変数のアドレスという値を渡しています。
何もおかしくないと思います。
Re: 関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月22日(火) 09:38
by ケトン
>>4 みけCAT氏
>>9 box氏
なるほど、int型の*pXではなく、int*型のpXを宣言したと考えればよいのですね。
そうだとすれば、
という宣言は、int*型のpXとint型のYを宣言したと考えてよいですか?
Re: 関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月22日(火) 10:19
by みけCAT
ケトン さんが書きました:
という宣言は、int*型のpXとint型のYを宣言したと考えてよいですか?
いいえ。
マクロ定義がなければ、コンパイルエラーになるでしょう。
コンマを追加した
なら、int*型のpXとint型のYになりますね。
Re: 関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月22日(火) 10:51
by ケトン
>>11 みけCAT氏
おっと、カンマつけ忘れていました。
Re: 関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月22日(火) 17:15
by C6b14
お使いの C コンパイラ では この コード は 正常に動きますか?
コード:
#include <stdio.h>
void swap(int *, int *);//[宣言]
int Global_pX=100, Global_pY =999;
void main(void)
{
printf("%d:%d\n", Global_pX, Global_pY);
swap(&Global_pX, &Global_pY); //[実行]
printf("%d:%d\n", Global_pX, Global_pY);
}
void swap(int *pX, int *pY) //[定義]
{
int Temp; Temp = *pX; *pX = *pY; *pY = Temp;
}
100:999
999:100
VC++2015 では コンパイル できます。C ではなく C++ です。C では どうだったか?
Re: 関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月22日(火) 21:17
by みけCAT
C6b14 さんが書きました:C ではなく C++ です。
このコードはVC++ではコンパイルできるとしても、main関数の戻り値の型がintではないのでC++の規格に違反しています。
C言語では処理系定義で許されることがあるかもしれません。
void main()をめぐるどうでもいい話 - Qiita
Re: 関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月22日(火) 22:01
by C6b14
ありがとうございます。
最近は C と言っても C++ 上 の 例が 多い から こういう 宣言 を 見かけるのですね。
void swap(int *, int *);//[宣言]
最近の C++ の void は int を 返すとみなされる というように 記憶してます。
ただ このような 宣言 は いまは C++ 上 で動いているのものは 許されても
C 言語 の 規約では 許されて いるのか いないのか。 初心者 にとっては この書き方
の方が 迷わない 親切な 書き方 なんだな と思ったものです から 質問しました。
Re: 関数の引数にポインタを使うときの初歩的な質問
Posted: 2016年11月23日(水) 23:09
by C6b14
この ページ は まともな ことが書いてあると 思います。( あいまいな ページ が おおい です )
http://www.cc.kyoto-su.ac.jp/~yamada/ap ... ument.html
「実引数が関数に引き渡されるとき,その実引数自身ではなく,実引数のコピーが引き渡される.」
( たとえ その 実引数 が 「ポインター型」 でも ) [ ややこしい ので いつも 迷う 話 ... ]