ページ 11

参照渡し

Posted: 2011年12月15日(木) 00:23
by yuu
再帰関数の答えを参照渡ししたいのですが
うまくできません
どうしたら
いいでしょうか?

コード:

#include<stdio.h>

int fact(int *n);
int main(void)
{
	int n;
	printf("Input Integer=");
	scanf("%d",&n);
	fact( &n);
	printf("Factorial=%d\n",n);
	return 0;
}

int fact(int *n)
{   
	if(n==0)return(1);
	*n=*n*fact(n-1);	
}

一応このプログラムなんですけど
よくわかりません

Re: 参照渡し

Posted: 2011年12月15日(木) 02:42
by YuO
fact関数の,
  • nの役割
  • 入力としての*nの意味
  • 出力としての*nの意味
  • 戻り値の意味
をちゃんとコメントに書いてみると,頭の中が整理できるかと思います。
これらがちゃんと整理できないまま作ろうとしているために,
yuu さんが書きました:よくわかりません
となっているのだと思います。

そして,このままの関数仕様で作れなくもないですが,入力と出力の引数を分離するよう入れた方が作りやすいと思います。

Re: 参照渡し

Posted: 2011年12月15日(木) 09:29
by non
私も方法を思いつかない。
そもそも、参照渡しでやれっていう課題なの?

Re: 参照渡し

Posted: 2011年12月15日(木) 09:48
by yuu
そうですけど

できないですね

Re: 参照渡し

Posted: 2011年12月15日(木) 09:59
by non
条件としては
int fact(int *n)
このプロトで作りなさいって事なんですね。
値は返して良い。

Re: 参照渡し

Posted: 2011年12月15日(木) 10:14
by YuO
yuu さんが書きました:できないですね
自動変数を1個使えばできます。
できないとする根拠はなんなのでしょうか。
# できないと言い切るのは非常に難しいことだと思いますが。

というか,

コード:

int fact(int n, int *result);
とすれば綺麗になるのに,

コード:

int fact(int *n);
に固執する必要も無いと思いますが……。

Re: 参照渡し

Posted: 2011年12月15日(木) 10:16
by non
nを参照渡しにしろっていう課題だと思いますよ。
nを値渡しにしちゃ拙いのでは?

Re: 参照渡し

Posted: 2011年12月15日(木) 10:19
by beatle
non さんが書きました:nを参照渡しにしろっていう課題だと思いますよ。
nを値渡しにしちゃ拙いのでは?
「答えを参照渡ししたい」と書いてありますから、参照にするのはresultでいいのではないでしょうか。

Re: 参照渡し

Posted: 2011年12月15日(木) 10:21
by non
確かに一番最初に
>再帰関数の答えを参照渡ししたいのですが
って書いてあるなぁ。答えならnではないのか・・・
本人のRESを待ちましょう。

Re: 参照渡し

Posted: 2011年12月15日(木) 15:20
by たかぎ
もしかして、こういうことでは?

コード:

#include<stdio.h>
#include<limits.h>

int fact(int *n)
{
     if (*n == 0)
     {
          *n = 1;
     }
     else
     {
          int nn = *n - 1;
          if (fact(&nn) || INT_MAX / *n < nn)
               return -1;
          *n *= nn;
     }
     return 0;
}

int main(void)
{
     int n;
     scanf("%d", &n);
     if (fact(&n) == 0)
          printf("Factorial=%d\n", n);
     else
          puts("overflow");
}

Re: 参照渡し

Posted: 2011年12月15日(木) 15:42
by non
なるほどですね。思いつきませんでした。戻り値を、正常終了かに使うところなど、プロはさすがだと思います。

Re: 参照渡し

Posted: 2011年12月15日(木) 22:04
by RYO
質問者さんの書かれたfact()の中身はかなり変なことやってますね
何をやりたいのかは何となくわかるのですが…
fact()をポインタ変数の値渡しをやめて、参照渡しで作り直せってことではないでしょうか?

Re: 参照渡し

Posted: 2011年12月16日(金) 02:31
by yuu
遅くなりました
nの値を参照渡しにより渡すみたいです
本当は再帰関数で作るものですが
たぶん
違う方法で参照渡しするのだと思い
作り変えてみましたが
うまくいきません

コード:

#include<stdio.h>

void fact(int& n);
int main(void)
{
	int n;
	printf("Input Integer=");
	scanf("%d",&n);
	fact( n);
	printf("Factorial=%d\n",n);
	return 0;
}

void fact(int& n)
{   
        int i,c;
	c=n;
	for(i=0;n>i;i++)
	{
		n*=(c-i);
	}
}

nの階乗の値が返されません
どうしたらいいのでしょうか?

Re: 参照渡し

Posted: 2011年12月16日(金) 02:31
by yuu
遅くなりました
nの値を参照渡しにより渡すみたいです
本当は再帰関数で作るものですが
たぶん
違う方法で参照渡しするのだと思い
作り変えてみましたが
うまくいきません

コード:

#include<stdio.h>

void fact(int& n);
int main(void)
{
	int n;
	printf("Input Integer=");
	scanf("%d",&n);
	fact( n);
	printf("Factorial=%d\n",n);
	return 0;
}

void fact(int& n)
{   
        int i,c;
	c=n;
	for(i=0;n>i;i++)
	{
		n*=(c-i);
	}
}

nの階乗の値が返されません
どうしたらいいのでしょうか?

Re: 参照渡し

Posted: 2011年12月16日(金) 02:54
by YuO
どうしたらいいかの前になぜそうなったかを考えましょう。
それがわからなければ,どうすればいいのかはわかりません。

なぜそうなったかを調べる手段の一つは,丹念にコードを追うことです。
このサイズなら机上でも十分だと思いますが,
実際にデバッガ上で動かして一行ずつ進めながら変数の値を確認していく,というのは基本的なデバッグ方法です。

とりあえず机上デバッグ。
3を入力した場合に,fact関数は,
  • 18行目 : i = 0, n = 3, c = 3, n > i : true
  • 20行目 : i = 0, c = 3, c - i = 3, n = 9
  • 18行目 : i = 1, n = 9, c = 3, n > i : true
  • 20行目 : i = 1, c = 3, c - i = 2, n = 18
  • 18行目 : i = 2, n = 18, c = 3, n > i : true
  • 20行目 : i = 2, c = 3, c - i = 1, n = 18
  • 18行目 : i = 3, n = 18, c = 3, n > i : true
  • 20行目 : i = 3, c = 3, c - i = 0, n = 0
  • 18行目 : i = 4, n = 0, c = 3, n > i : false
というループの過程を経ます。

これを見れば,問題点がわかると思います。
まず,20行目での計算がおかしいことがすぐにわかります。
最初にc - iが3であるのがそもそもおかしいわけですが,単純にiが0の時にnに2をかければよいとばかりに

コード:

n *= c - i - 1;
とするとi=c-1の時にnが0になり正しい結果がでません。
これらは,i=0ではなくi=1から始めることで解決します。
次に,ループの継続条件のうちのnがどんどん変化していることがわかります。
階乗の計算では計算回数は変化しないはずなので,nが変化するのもおかしいことになります。
これは,継続条件をnではなくcを元にすることで,解決します。

2点をまとめて,

コード:

for (i = 1; i < c; ++i)
{
  n *= c - i;
}
これを追うと,
  • 1行目 : i = 1, n = 3, c = 3, i < c : true
  • 3行目 : i = 1, c = 3, c - i = 2, n = 6
  • 1行目 : i = 2, n = 6, c = 3, i < c : true
  • 3行目 : i = 2, c = 3, c - i = 1, n = 6
  • 1行目 : i = 3, n = 6, c = 3, i < c : false
となり,少なくともnが3の場合において正しい結果が得られていることがわかります。

Re: 参照渡し

Posted: 2011年12月16日(金) 08:53
by non
yuu さんが書きました: nの値を参照渡しにより渡すみたいです
本当は再帰関数で作るものですが
そのものずばりを、たかぎさんから作っていただいたのですから、お礼ぐらい言っときなさいよ。
その上で、再帰はまだ理解できないから、再帰を使わずに使ってみたいってお願いする。
スルーするのは、マナーとしてなっていない。

Re: 参照渡し

Posted: 2011年12月16日(金) 10:03
by みけCAT
yuu さんが書きました:再帰関数の答えを参照渡ししたいのですが
つまりこういうことですか?

コード:

#include<stdio.h>
 
int fact(int& n);
int fact2(int n);
int main(void)
{
    int n;
    printf("Input Integer=");
    scanf("%d",&n);
    fact( n);
    printf("Factorial=%d\n",n);
    return 0;
}
 
int fact(int& n)
{
    n=fact2(n);
    return 0;
}

int fact2(int n) 
{
    if(n<=1)return 1;
    return n*fact2(n-1);
}