C言語関係掲示板

過去ログ

No.926 最大公約数と最小公倍数を配列に格納して返す関数

[戻る] [ホームページ]
No.11732

配列に格納された値を返す
投稿者---Tait(2004/01/13 22:45:50)


任意の正整数a,bに対して,a,bの最大公約数と最小公倍数を
大きさ2の配列A=A[0],A[1]に格納して返す関数GCDLCMの作成.
a,bを入力引数とし,Aを出力引数にする.

という問題なのですが,配列をどのように返したら良いのか分かりません.
友人に質問したら『関数はvoidでもいいのでは?』という答えが返ってきたのですが,
それだと出力引数の存在が…(私が間違っているのなら勉強し直します)
と思ってしまい,どうしたら良いのか分からない状況です.
以下に中途半端ですが一応,プログラムを作ってみました.ご教授お願いします.

#include<stdio.h>
int GCDLCM(int a,int b,int A[]){
  int c=a*b;
  while(a!=b){
    if(a<b){b=b-a;}
    else{a=a-b;}
  }
  A[0]=a; A[1]=c/a;

}

int main(void){
  int a,b,A[2];
  printf("a:"); scanf("%d",&a);
  printf("b:"); scanf("%d",&b);
  GCDLCM(a,b,A);

  return 0;
}


No.11737

Re:配列に格納された値を返す
投稿者---YuO(2004/01/13 23:02:42)


>任意の正整数a,bに対して,a,bの最大公約数と最小公倍数を
>大きさ2の配列A=A[0],A[1]に格納して返す関数GCDLCMの作成.
>a,bを入力引数とし,Aを出力引数にする.
>という問題なのですが,配列をどのように返したら良いのか分かりません.
>友人に質問したら『関数はvoidでもいいのでは?』という答えが返ってきたのですが,
>それだと出力引数の存在が…(私が間違っているのなら勉強し直します)

入出力が共に引数ですから,戻り値の型はvoidでも問題ないです。

int GCDLCM(int a,int b,int A[]){


この場合,a及びbの値を変更しても呼び出し側には伝わりませんが,
Aの要素(つまりはA[0]など)を変更した場合,呼び出し元の実引数の要素も変更されます。


int main(void){


GCDLCMを呼び出したあとにAの各要素を出力するコードを書いてみるとよいでしょう。


No.11738

Re:配列に格納された値を返す
投稿者---Tait(2004/01/13 23:24:04)


YuOさんありがとうございます.

>入出力が共に引数ですから,戻り値の型はvoidでも問題ないです。
私の勉強不足だと思うのですが,問題文に『〜を返す関数』となっていた場合
「int型で作成しなければならない.(returnで値を<返す>ので)」
と思い込んでいたのですが,思いっきり私の勘違いだったみたいですね.

それでは,このような感じでよろしいのでしょうか?お願いします.

#include<stdio.h>
void GCDLCM(int a,int b,int A[]){
  int c=a*b;
  while(a!=b){
    if(a<b){b=b-a;}
    else{a=a-b;}
  }
  A[0]=a; A[1]=c/a;
}

int main(void){
  int a,b,A[2];
  printf("a:"); scanf("%d",&a);
  printf("b:"); scanf("%d",&b);
  GCDLCM(a,b,A);
  printf("GCD:%d\n",A[0]);
  printf("LCM:%d",A[1]);
  return 0;
}


No.11741

Re:配列に格納された値を返す
投稿者---YuO(2004/01/14 01:10:04)


>>入出力が共に引数ですから,戻り値の型はvoidでも問題ないです。
>私の勉強不足だと思うのですが,問題文に『〜を返す関数』となっていた場合
>「int型で作成しなければならない.(returnで値を<返す>ので)」
>と思い込んでいたのですが,思いっきり私の勘違いだったみたいですね.

問題をよく読んでください。
>>>Aを出力引数にする
と書いてありますよ。つまり,Aは引数です。
#まぁ,戻り値に名前はないが。

また,「〜を返す関数」とあっても,引数を経由して値を返すこともよくありますよ。


元々,関数の戻り値の型は戻り値として必要な型です。
配列型と関数型でなければ,どのような型でも利用可能です。

また,どうしても配列を返したいのであれば,構造体に配列を入れて,
struct GcdLcmResult {
    int A[2];
};
struct GcdLcmResult GCDLCM (int a, int b) {

のようにすることもできます。


>それでは,このような感じでよろしいのでしょうか?お願いします.

コンパイラを入手して実行してみればよいだけだと思いますが……。

最小公倍数は,a * b / GCDではなく,
(a / GCD) * (b / GCD) * GCDと計算した方がよいです。
元のプログラムでは,例えばintが16bitのコンパイラでa, bがともに256(=0x100)の時,
c = a * b;
cの値は,a * bを単純に計算すると65536(=0x10000)だから大抵0になる。
while (a!=b)
a == bが成立するからループは一度も実行されない
A[0] = a;
最大公約数は256
A[1] = c / a;
最小公倍数はcが0だからc / aで0

という結果が生じてしまいます。
#intが32bitのコンパイラではa, bをともに65536として試すと,同じような結果になる。
最初に最大公約数で割ってやると,1 * 1 * 256で256という正しい値がちゃんと得られます。

ただし,元々表現可能な範囲外の結果をもたらす演算の動作は未定義ですから,
c = a * b;の時点でのcの値が0になるかと言うと,言い切れないです。
大抵の処理系では単純にオーバーフローしたビットを切り捨てて0になると思いますが,
例えばraise(SIGFPE);のように振る舞う処理系もあると思いますし,
いきなり強制終了する処理系もありえます。
#ハードディスクを初期化しようが鼻から悪魔を出そうが……。


No.11742

配列に格納された値を返す[済]
投稿者---Tait(2004/01/14 01:29:25)


>問題をよく読んでください。
>>>>Aを出力引数にする
>と書いてありますよ。つまり,Aは引数です。
>#まぁ,戻り値に名前はないが。
>また,「〜を返す関数」とあっても,引数を経由して値を返すこともよくありますよ。
そうですね.大変参考になります.
以後このような勘違いをしないよう気をつけます.

>最小公倍数は,a * b / GCDではなく,
>(a / GCD) * (b / GCD) * GCDと計算した方がよいです。
気がつきませんでした.こちらの方もとても参考になりました.

YuOさん,とても詳しい説明をして下さってどうもありがとうございました.
私の勉強不足も分かり,精進しなければいけないなと思いました.
またお世話になってしまう時があるかもしれませんが,その時は宜しくお願いします.