ページ 1 / 1
C言語スタートブック改訂第3版 p260,261から質問です。
Posted: 2017年4月30日(日) 10:58
by takumi
コード:
/**********************************************
基本選択法
**********************************************/
#include <stdio.h>
#define N 10 //配列要素数
//関数のプロトタイプ宣言
void swap(int *pa , int *pb);
int *getMin(int *p , int n);
void dispAll(int *p , int n);
void main(){
//ローカル変数の宣言
int x[N] = {22,58,36,42,85,72,19,28,66,51};
int i; //添字
//データの表示
dispAll(x , N);
//並べ替え
for(i = 0; i < N-1; i++)
{
//未決定の範囲の中から最小値の位置を求めて先頭と交換
swap(getMin(&x[i] , N - i) , &x[i]);
}
//データの表示
printf(" ソートしました\n");
dispAll(x , N);
}
/***********************************************************
2つのint型の値を交換する処理
************************************************************/
void swap(int *pa , int *pb)
//pa , pb:交換するデータのアドレス
{
//変数の宣言
int temp; //一時退避
//交換処理
temp = *pa;
*pa = *pb;
*pb = temp;
}
/************************************************************
配列の指定番目から指定個の中から最小値を探す
戻り値:最小値の位置(アドレス)
************************************************************/
int *getMin(int *p , int n)
//p :データが格納されている配列の対象範囲の先頭のアドレス
//n :最小値を探す範囲の個数
{
//ローカル変数の宣言
int i; //添字
int *pmin; //最小値の位置(アドレス)
//最小値を探す
pmin = p;
for(i = 0 ; i < n; i++ , p++)
{
if(*pmin > *p)
{
pmin = p; //より小さい数値がみつかった
}
}
return pmin;
}
/**************************************************
配列の内容をすべて表示する関数
**************************************************/
void dispAll(int *p , int n)
//p :データが格納されている配列のアドレス
//n :要素数
{
//ローカル変数の宣言
int i; //添字
//表示
for(i = 0 ; i < n; i++)
{
printf("%4d" , *(p + i));
}
printf("\n");
}
※ポインタを利用して数字の配列から最小値を見つけ出し、昇順に並び替えるプログラムです。このプログラムの関数の中のfor文の
if(*pmin > *p)の部分で*pminはpの内容をさすので、int *pの実引数&x
、つまり*pmin = &x[0]になり *pminは最初22をさしますよね。
*pも22を指し、 22>22となりfor文の最初の処理は意味がない事になり、次に繰り返されますが、後置演算子p++なので*pmin = x[1] つまり
58を指してしまう事と、*pも58になるので 58>58となりこれもおかしくなってしまいます。ここの部分の解釈お願いします。
Re: C言語スタートブック改訂第3版 p260,261から質問です。
Posted: 2017年4月30日(日) 13:24
by みけCAT
takumi さんが書きました:このプログラムの関数
getMin関数のことですね。
takumi さんが書きました:if(*pmin > *p)の部分で*pminはpの内容をさすので
pmintとpは別の変数なので、pminがpが指している内容をさすとは限りません。
また、*pminはint型なので何かを「さす」とは考えにくく、
pminはint型へのポインタなのでint*型の「pの内容」を指すとは考えにくいです。
takumi さんが書きました:int *pの実引数&x、つまり*pmin = &x[0]になり *pminは最初22をさしますよね。
pmin = &x[0]、*pmin = x[0]になります。「*pmin = &x[0]」とはならないでしょう。
確かに最初の呼び出しで*pminは22になります。
takumi さんが書きました:*pも22を指し、 22>22となりfor文の最初の処理は意味がない事になり
確かにそうですね。最初の要素は初期化で使っているので、2番目の要素から比較を開始してもいいでしょう。
takumi さんが書きました:次に繰り返されますが、後置演算子p++なので*pmin = x[1] つまり
58を指してしまう事と
pとpminは別の変数なので、(処理系の不都合などがなければ)p++でpminが勝手に書き換わることはありません。
takumi さんが書きました:*pも58になるので
そうですね。
takumi さんが書きました:58>58となりこれもおかしくなってしまいます。
22>58となり、おかしくはなりません。
takumi さんが書きました:ここの部分の解釈お願いします。
コード:
int *getMin(int *p , int n)
//p :データが格納されている配列の対象範囲の先頭のアドレス
//n :最小値を探す範囲の個数
{
//ローカル変数の宣言
int i; //添字
int *pmin; //最小値の位置(アドレス)
//最小値を探す
pmin = p; /* 最小値はとりあえず先頭にあると仮定する */
for(i = 0 ; i < n; i++ , p++) /* 指定された回数、見る要素の位置を進めながら繰り返す */
{
if(*pmin > *p) /* 最小値と仮定している要素の値より今見ている要素の値の方が小さければ */
{
/* 最小値の位置を今見ている要素の位置に更新する */
pmin = p; //より小さい数値がみつかった
}
}
return pmin; /* 得られた最小値の位置を返す */
}
みけCATさん 説明ありがとうございます。
Posted: 2017年4月30日(日) 15:29
by takumi
説明ありがとうございます。 つまり一回目のfor文で *pminは pmin = p; と定義していたことから、int*pを参照し、int*pは実引数x[0]を
受けるので pmin は 22となりますが、 二回目のfor文の if(*pmin > *p)の部分では、*pminは pmin = p; → p+1より (int*p)+1 → x[1] → 58
と探すような処理は行われず、一回目でpmin = 22 と処理が済んだら 二回目以降は特にコンピュータが処理を探して行う部分ではないという事ですか?
それとも、p++より、p+1となっても、pは配列とは考えられず隣の変数orアドレスを確保しない為、x[0]がx[1]に変わるようなことが起きず無効となり、
処理が行われてもずっと22のままなのですか?
Re: みけCATさん 説明ありがとうございます。
Posted: 2017年4月30日(日) 16:13
by みけCAT
takumi さんが書きました:一回目のfor文で *pminは pmin = p; と定義していたことから、int*pを参照し
pminはpの値を代入されるだけで、Verilogのassign文のような参照はしません。
takumi さんが書きました:int*pは実引数x[0]を
受けるので
x[0]ではなく&x[0]を受けます。
takumi さんが書きました:pmin は 22となりますが
pminが22となる可能性は低いです。
*pminが22となります。
takumi さんが書きました:二回目のfor文の if(*pmin > *p)の部分では、*pminは pmin = p; → p+1より
pmin = p;はfor文の外にあるので、「二回目のfor文」の中や「一回目のfor文」と「二回目のfor文」の間で実行されることは(処理系が狂っていなければ)ありません。
takumi さんが書きました:(int*p)+1 → x[1] → 58
と探すような処理は行われず、一回目でpmin = 22 と処理が済んだら 二回目以降は特にコンピュータが処理を探して行う部分ではないという事ですか?
すいません、意味がよくわかりません。
ただし、pmin = 22という処理を行う可能性は低いので、これは前件が偽である条件文とみなすことができ、
「一回目でpmin = 22 と処理が済んだら 二回目以降は特にコンピュータが処理を探して行う部分」であるということができそうです。
takumi さんが書きました:それとも、p++より、p+1となっても、
何がですか?
takumi さんが書きました:pは配列とは考えられず
このコードでは行いませんが、pを指すポインタの計算において、pは1要素の配列と考えることができます。
takumi さんが書きました:隣の変数orアドレスを確保しない為
確かに、隣の変数orアドレスは確保されていないので、(&p + 1)のデリファレンスはしてはいけません。
※(p + 1)ではなく(&p + 1)の話です!ここでは使われていません!
takumi さんが書きました:x[0]がx[1]に変わるようなことが起きず無効となり
すいません、意味がよくわかりません。
x[0]がx[1]に変わるようなことは普通に起こらないと思いますが、何が無効になるのですか?
takumi さんが書きました:処理が行われてもずっと22のままなのですか?
何がですか?
ありがとうございます。解決できました。
Posted: 2017年4月30日(日) 17:01
by takumi
pmin = p;はfor文の外にあるので、「二回目のfor文」の中や「一回目のfor文」と「二回目のfor文」の間で実行されることは(処理系が狂っていなければ)ありません。
上記の理由により、for文中の*pminはつまり*pmin(ポインタが指す先の変数の内容を求める)が22と一度でたら、何度繰り返しても for文中では
「 pmin = pだから、*pminはpと絡み、その時p++の影響を受けるから、こうなって、、、」なんて考えなくていいということですね。
ご説明ありがとうございました。理解できました。