swapの受け取りは、nxnyなのに
sort2の中ではswap(n1,n2)で呼び出していますよね。
n1、n2として呼び出す必要があると思ったんですが、
どう考えればいいんでしょうか?
追記
intn1 のintはこのn1というポインタが示す値はイント型がでないといけない。(ポインタ型)
sort2の中の*n1はn1ポインタの値(実際は6、5)という理解であっていますか?
多分ポインタ型とポインタ型変数の理解が浅いのと、ポインタの前に*をつけて値を表わすために混乱しています。
何度も質問して申し訳ありませんが、どうかお力を貸して下さい。
void swap(int*nx,int*ny) { int temp=*nx; *nx=*ny; *ny=*nx; } void sort2(int*n1,int*n2) { if(*n1>*n2) swap(n1,n2); } int main(void) { int na,nb; puts("type two integers"); printf("A" ); scanf("%d",&na ); printf("B" ); scanf("%d",&nb ); sort2(&na,&nb); puts("sort value in asending order"); printf("A=%d\n",na ); printf("B=%d\n",nb ); return 0; } コード
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答5件
0
swapの仮引数部分を見ると、「前に*を付けるとint型になるもの」を渡す必要があると分かります。
sort2のswap(n1,n2)ですが、仮引数の部分を見ると、「n1がint型」ということが分かります。つまりn1は「前にを付けるとint型になるもの」です。
なので、n1 や n2 をそのまま渡します。*n1 だと int型の値になってしまうので、swapの仮引数に合いません。
なお、「前に*を付けるとint型になるもの」のことを「int型へのポインタ」と言います。
というのが、そのプログラムありきでの文法に沿っての説明です。
そうなると次に、「何故swapの仮引数は『前に*を付けるとint型になるもの』なのか?int型じゃ駄目なのか」という疑問がわくかもしれません。
アセンブラをやらずにC言語に入った人は、ポインタが難しいと感じる人が多いようで、世の中にポインタの説明文はいくらでもありますので、いろいろ調べてみてください。
投稿2015/09/02 09:49
総合スコア84505
0
ポインタは宣言するときに「int *p」こんな風に書きますが、
アドレスを扱う変数といいながら、アドレスを確認するときは「p」のように宣言したのと異なる形で参照します。
感覚的に宣言時と参照時でイメージが逆転するので、混乱するのかなと思っています。
int a = 1;
ptr p = memoryAddress(a); //動作しません
printf("d%",ReferenceValue(p)); //動作しません
冗長で不便ではありますが、こういう書式なら混乱はなかったでしょうね。
main側はこのように書くとsort2内と同じような形になります
直ぐ近くにあると違和感も減るのではないでしょうか?
C
1int na=2, nb=1; 2int *p1,*p2; 3p1 = &na; 4p2 = &nb; 5sort2(p1,p2);
コメントを書いてみました。
C
1int main(void) 2{ 3 sort2(&na,&nb); 4 //na,nbではint型の値、&na,&nbではアドレスが参照できる 5return 0; 6} 7 8void sort2(int*n1,int*n2) //アドレスを受け取る変数の宣言 9{ 10 if(*n1>*n2)swap(n1,n2); 11 //*n1,*n2でint型の値、n1,n2でアドレスが参照できる 12} 13 14void swap(int*nx,int*ny) //アドレスを受け取る変数の宣言 15{ 16 int temp=*nx; 17 *nx=*ny; 18 *ny=*nx; 19 //*ny,*nxでint型の値が参照できる 20}
投稿2015/09/02 13:59
編集2015/09/02 14:15総合スコア2068
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ポインタは最初は色々混乱しますよね。
考えた方としては、int *nx
の部分を別の型として見てみるとすっきりするかもしれません。
typedef int* intp;
として、新しい型として考えてみます。すると以下のようになります。
#include <stdio.h> typedef int* intp; void swap(intp nx, intp ny) { int temp = *nx; *nx = *ny; *ny = temp; } void sort2(intp n1, intp n2) { if (*n1 > *n2) { swap(n1, n2); } } int main(void){ int a = 6; int b = 5; sort2(&a, &b); printf("a: %d, b: %d", a, b); return 0; }
こうすると、sort2
から swap
へ同じ型の変数を渡しているのがなんとなく分かるんじゃないかと思います。
ちなみに実際に動作が確認できるものをアップしてみました↓
https://paiza.io/projects/1jlMQXBYnFEtXflEjft9PA
投稿2015/09/02 11:39
総合スコア2283
0
ベストアンサー
Cのアドレス演算子は至極単純です。
変数に値を代入する。ということは、基本的にはメモリに値をセットしている訳です。
アドレス演算子を変数に用いるというのは、セットした値ではなく、値をセットしたメモリの番地を問い合わせていることになります。
つまり、変数の値を収めた「メモリアドレス」を表すのが、アドレス演算子です。
別の見方をすると、ポインタ変数が保持するタイプの値を取得できる。ということです。
下記のように書いた場合、変数:cNumにはchar型の配列が割り当てられます。
C
1char cNum[] = "01234";
(仮に、変数:cNumが0x100番地から割り当てられた場合)以下のコードは 0x100〜0x104 を表示します。
C
1int i; 2for(i=0;i<5;i++) 3 printf("0x%x\n", &cNum[i]);
関数に参照渡し(ポインタ渡し)をするというのは、値の入っているメモリの番地を渡すことです。
アドレス演算子の利用目的は、変数のポインタを得るのに使われます。
配列じゃなく普通の変数の場合は、添え字が付かないだけです。
C
1int num = 0; 2printf("0x%x\n", &num);
話が本題とはそれますが…
先ほどの変数:cNumは配列です。
配列の場合、添え字を使わずに変数名だけ指定した場合は配列先頭のポインタと等価なので、以下のように書くこともできます。
C
1int i; 2for(i=0;i<5;i++) 3 printf("0x%x\n", cNum+i);
配列に入っているデータを順次関数に渡す場合などでは、こういった表現方法も使えます。
[追加]
関数定義の int* も 変数定義の int* もそうですが、これらは「int型のポインタ」を収める変数定義です。
ポインタというのは「"値を収めたメモリ領域(=変数に割り当てられたメモリ領域)" の番地」を表すものです。
そのポインタ変数を * で修飾すると、ポインタの示すメモリに格納された値を表します。
この逆のパターンが、アドレス修飾子 & です。
例えば int型の変数:num のポインタが欲しい場合は &num と書きます。得られるのは変数に割り当てられたメモリアドレスです。
これらをコードで示すと、以下のような感じです。
※ポインタ経由で、 num1 = num2; と同じ結果を得る処理を行います。
C
1int num1, num2; 2int* pNum; 3 4num1 = 999; // num1 に 999 を代入 5pNum = # // num1のポインタを pNum に代入 6num2 = *pNum; // pNum(num1のメモリアドレス) に格納された値 (= num1の値)を num2に代入 7 8printf("%d %d %d", num1, *pNum, num2);
関数へのポインタ渡しについては、例えば以下のような感じです。
test1関数は引数がポインタ渡しなので、test1関数を呼び出す際は 変数:numのポインタを取得して渡しています。
test2関数も引数がポインタ渡しです。test2関数を呼び出す際もポインタを渡すことになります。test1関数では既にポインタで値を受け取っていて変数:pNumの中身はnumのポインタです。test2関数を呼び出す時は、変数:pNumに収められたnumのポインタをそのまま渡します。
もし、test1関数の中で pNum のように、 で修飾するとポインタの中身ということで、intの値(変数:numに代入した値)を表すことになります。しかし、test2関数はポインタを必要とするので修飾の必要はありません。
※これは & で修飾した場合の逆パターンです。
実行結果としては、test2関数内の printf関数によって変数:numに代入した値が出力されます。
C
1void test2(int* pNum){ 2 printf("%d", *pNum); 3}; 4 5void test1(int* pNum){ 6 test2(pNum); 7}; 8 9int num; 10 11num = 123; 12test1(&num);
質問の関数でも同様のポインタ渡しが行われます。
https://teratail.com/questions/15327 でも書いたのですが、デバッガで動きを追いかけることをした方がいいですよ。
質問の実装も、sort2関数に以下のように渡すことも合わせて考えれば、多少理解の助けになるでしょうか。
C
1int *pNA, *pNB; 2 3pNA = &na; 4pNB = &nb; 5 6sort2(pNA,pNB);
投稿2015/09/02 10:15
編集2015/09/02 14:10退会済みユーザー
総合スコア0
0
void swap(intnx,intny)
この宣言ではnx,nyをintのポインタで受け取ると宣言しています。
ここで呼び出し側ですが
swap(n1,n2);
となっていてn1,n2の型は何かとみると
void sort2(intn1,intn2)
n1,n2もintのポインタです。
ですので、swapを呼び出すときはそのままn1,n2を使えばintのポインタが渡っていきます。
ここでn1,n2のポインタがさす内容は何かを確認するときに
if(*n1>*n2)
のように*n1,*n2とします。
intを例にすると
データ型が値の場合
宣言 int a
値参照 a
アドレス参照 &a
データ型がポインタの場合
宣言 int* a;
値参照 *a
アドレス参照 a
(多重ポインタはいったん話の外に置きます)
おまけ
int temp=*nx; *nx=*ny; *ny=*nx;
ここのny=nx;はny=temp;にしないとnx==*nyになってしまいますよ。
投稿2015/09/02 09:58
総合スコア985
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/09/02 10:26
2015/09/02 15:02
2015/09/02 16:22
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/09/02 09:58
2015/09/02 10:01
2015/09/02 10:03