C言語の再帰を用いるプログラムでのセグフォの対処方法

このQ&Aのポイント
  • C言語の再帰を用いるプログラムでセグメンテーションフォルト(segfault)が発生する場合、再帰の終了条件を確認してください。
  • 再帰が1度しか行われない場合は正常に動作するが、再帰が2度以上行われる場合にsegfaultが発生することがあります。
  • segfaultが発生する場合は、再帰関数の引数や処理の制御フローを見直し、正しい終了条件を設定してください。
回答を見る
  • ベストアンサー

【C言語】再帰を用いるプログラムでのセグフォ

明解C言語入門編のp196にあるList8-7 再帰を用いて2つの整数の最大公約数を求めるプログラムなんですが #include<stdio.h> int gcdf(int vx, int vy) { return(vy == 0? vx: gcdf(vy,vx&vy)); } int gcd(int va, int vb) { return(va>vb? gcdf(va,vb): gcdf(vb,va)); } としてmainの中で入力された2つの整数n1,n2を 最大公約数としてgcd(n1,n2)を表示させるのですが、 (1,2)とか(2,4)などの再帰が1度しか行われない(?)プログラムでは ちゃんと結果が表示されるのですが、 (4,6)など再帰が2度以上行われるプログラムになると segmentation fault(コアダンプ) と表示されます。 どこに問題があるのでしょうか OSはubuntu14.04 エディタはvim コンパイラはclangです。 よろしくお願いします。

  • mist55
  • お礼率72% (180/247)

質問者が選んだベストアンサー

  • ベストアンサー
  • notnot
  • ベストアンサー率47% (4846/10257)
回答No.3

最大公約数はそもそもどうやって求めるか分かっていますか? それとも単純にタイプミスでしょうか? vx&vy ↓ vx%vy なお、return の返値全体を括弧で囲むのは、文法間違いではありませんが、普通はしません。 なので、 return vy == 0 ? vx : gcdf(vy, vx % vy) ;

mist55
質問者

お礼

ありがとうやで

mist55
質問者

補足

申し訳ありませんタイプミスです。 vx%vyとした上で 大きな数値(2桁以上)を入力すると すぐにセグフォが起こるのです。

その他の回答 (5)

  • Wap58
  • ベストアンサー率33% (29/87)
回答No.6

プリントしてセグフォを特定なのだ #include<stdio.h> int gcdf(int vx, int vy) { printf("gcdf vx %d vy %d\n",vx,vy); return (vy==0? vx: gcdf(vy, vx%vy)); } int gcd(int va, int vb) { printf("gcd va %d vb %d\n",va,vb); return (va>vb? gcdf(va, vb): gcdf(vb, va)); }

  • notnot
  • ベストアンサー率47% (4846/10257)
回答No.5

>vx%vyとした上で大きな数値(2桁以上)を入力するとすぐにセグフォが起こるのです。 ということであれば、書かれている範囲のプログラムにおかしい部分はないので、 書かれていない範囲のプログラムが間違っていると思います。 よく見直して下さい。

mist55
質問者

お礼

ありがとうございました

回答No.4

うーん、こちらだと特に問題ないんですけどねぇ。 Ubuntu 14.04LTSの64ビット、コンパイラは同じくclang使ってみましたが、2桁以上・・・まあ、このケースだと3桁でやってみましたが、セグフォは起きませんでした。 #include<stdio.h> // ソースは同じ int gcdf(int vx, int vy) { return (vy==0? vx: gcdf(vy, vx%vy)); } int gcd(int va, int vb) { return (va>vb? gcdf(va, vb): gcdf(vb, va)); } int main (void) { printf("%d\n", gcd(123, 456)); return 0; } // 実行 ➜ OKwave clang List8-7.c ➜ OKwave ./a.out 12 // ここまで まあ、「大きな数」ってのがどれくらい指すのか、って分からないと何とも言えないですけどねぇ。 もちろん、C言語なんかの場合、「int」が想定してる「最大の整数」を超えると挙動がおかしくなったりはするでしょう。 (Cの場合、最大の整数は32,767ですかね?) なお、このソースの場合、Lispなんかやってる人だと当たり前の知識なんですが、「末尾再帰」と言うテクニックで記述されています。 末尾再帰ってのは、再帰で関数を呼び出す場合、その呼び出された関数に「余計な操作を加えてない」って意味ですね。 int gcdf(int vx, int vy) { return (vy==0? vx: gcdf(vy, vx%vy)); <- 条件によって、returnで呼び出される関数はgcdf「だけ」で、他にgcdf自体には余計な操作を加えていない。 } さて、末尾再帰も再帰も原理的にはスタック(メモリ上の・・・簡単に言うと「関数呼び出し」の為の情報を保持しておく領域?)を消費して「効率が悪い」んですが、一方、末尾再帰の場合は、コンパイラの記述方法如何によっては「末尾再帰最適化」と言う技術が使われていて、末尾再帰で書かれたコードを単純なジャンプ構文に「自動変換」してくれて、スタックの消費を避けてくれます。 ありがたい事に、clangと言うコンパイラは末尾再帰最適化を行って、大変効率的なマシン語に落としてくれる模様です。 つまり、環境によるんですが、スタックを消費し過ぎた場合、セグメンテーションフォールトを起こす可能性がある、んですよねぇ。 clangで末尾再帰最適化を行う場合、コンパイル時点で -O3と言うオプショナル引数を与えます。 例えば、 clang -O3 自分で書いたソース のように、ですね。 一回、このように、問題のソースを末尾再帰最適化を指定してコンパイルしてみて試してみて下さい。

回答No.2

int gcdf(int vx, int vy) { return(vy == 0? vx: gcdf(vy,vx&vy)); <- ココ } gcdfの第二引数で使われてる演算子が、&じゃなくって%にすべきなんじゃないですかね?

mist55
質問者

お礼

ありがとうやで

mist55
質問者

補足

申し訳ありませんタイプミスです。 vx%vyとした上で 大きな数値(2桁以上)を入力すると すぐにセグフォが起こるのです。

  • Wap58
  • ベストアンサー率33% (29/87)
回答No.1

プリントすればわかります、無限ループになります。 わざと間違えて考えさせるソースなんでしょう

mist55
質問者

お礼

ありがとう

関連するQ&A

  • 再帰関数とユークリッドの互除法を用いて最大公約数を求める

    学校の課題で、再帰関数とユークリッドの互除法を用いて10~100000までの最大公約数を求めるという問題が出て自分でプログラムを作ってみたのですが無限ループに入ったり、関数が使えてないみたいでできません。プログラムを見て頂いて、どこを改善したらいいかを教えてください。 #include <stdio.h> /* 正整数 n, m の最大公約数を計算する */ int gcd(int n, int m) { int res; res = n % m; if (res == 0) return m; /* 最大公約数が求まった */ return gcd(m, res); /* 再帰呼び出し */ } int main(void) { int i,j; for(i=10000;i>=10;i--){ for(j=10;j=10000;j++){ printf("%d to %d no saidaikouyakusuu ha %d \n", i, j, gcd(i, j)); } } return (0); } です。期限が今日の夜までで、ぎりぎりなんですがよろしくお願いします。

  • C言語のプログラム

    今授業でCの勉強をしているのですが。以下のプログラムはどうして 計算されないのかがわかりません。型上げされて表示されるのかなと思ったのですが。。まだ初歩の段階ですがよろしくおねがいします。 #include <stdio.h> int main(void) { int vx; double vy; puts("ふたつの数を入力してください"); printf("実数vx"); scanf("%d",&vx); printf("実数vy"); scanf("%lf",&vy); printf("vx+vy=%f\n",vx+vy);/*←vx+vyでdouble型として認識されないのでしょうか?以下同様*/ printf("vx-vy=%f\n",vx-vy); printf("vx*vy=%f\n",vx*vy); printf("vx/vy=%f\n",vx/vy); return(0); }

  • c言語でエラーが出ます。

    以下のプログラムでコンパイルするとエラーが出ます。どこが間違えていますか? #include <stdio.h> int main(void) { int vx,vy; puts("二つの整数を入力して下さい。"); printf("整数vx:"); scanf("%d", &vx); printf("整数vy:"); scanf("%d", &vy); printf("vx+vy=%d\n", vx+vy); printf("vx-vy=%d\n", vx-vy); printf("vx*vy=%d\n", vx*vy); printf("vx/vy=%d\n", vx/vy); printf("vx%%vy=%d\n", vx%vy); return(0); } コンパイラーはmicrosoft visual studio 2012です。エラー表示は「error C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. 」と出ます。 8行目のscanfの文にエラーと出ますがどこが間違っているか分かりません。どなたか分かる方教えて頂けますか?

  • このプログラム見てほしいです!!

    #include <stdio.h> int gcd2(int a, int b) { if (!b) return a; return gcd2(b, a%b); } int main() { int a, b, c; printf("2つの任意の整数を入力せよ:"); scanf("%d %d",&a,&b); c=gcd2(a,b); printf("最小公倍数は%d\n",a*b/c); printf("最大公約数は%d\n",c); return 0; } で、最小公約数を出すことはできたのですが、全ての公約数を表示させたいんです!!どうやったらいいのでしょうか??プログラミングまだ初心者なので、ちょっと行き詰ってしまいました。。。 お時間があればでいいのですが、もう一つわからないプログラムがあります。 自然数nを入力し、x^2+y^2=z^2 (x<y)を満たすようなn以下の自然数の組(x,y,z)がいくつあるのかを出力するプログラムなのですが、全くわからず行き詰っています。。どなたかお時間があれば教えて頂きたいです。 色々と申し訳ありません。お願いします(__)

  • C言語の演習2

    何度も似たような質問を出していますがよろしくお願いします。。。 問題は 2つの整数を入力してください。 整数A:54 整数B:84 Aの値はBの64.285714%です。 というものです。あっているか確認お願いします。 #include<stdio.h> int main(void) { int vx, vy; puts("2つの整数を入力してください。"); printf("整数A"); scanf("%lf",&vx"); printf("整数B"); scanf("%lf",&vy"); printf("Aの値はbの%f%です。/n",(double)(vx/vy)); return 0; } であっていますか??お願いします。

  • マイクロコンピューター制御の問題です

    「CASL2のプログラムを作成せよ」とのことで、次の問題が出されました。 問1.GR1の中身の値(正の整数)とGR2の中身の値(正の整数)の最大公約数をGR3 に入れて返すようなサブルーチンGCDを作れ。再帰を利用すること。   (ヒント)   最大公約数を求めるには、ユークリッドの互除法というアルゴリズムがある。C 言語で記述すると、再帰を使って以下のように書ける。  int gcd (int x,int y){ if (y==0)return x; return gcd(y,x%y); } 問2.IN命令により入力された10進数の数値を、16進数に変換して、OUT命令により 表示するプログラムをかけ。 以上の二つです。 手前勝手な事情ですが、明日8/9の午後4時までに、解答の方をよろしくお願いします。

  • わかりません・・・。

    二つの自然数を引数として与えられて,それらの最大公約数を返す関数 int gcd(int m, int n) { /* … */ }を作成し,それを利用して入力された二つの正整数の最大公約数を求めるプログラムを作り方を教えてください。 ユークリッドの互除法を使い、関数を使う事が条件なのですが全然わかりません。 #include<stdio.h> int gcd(int m, int n) if(m>n) {m%n}            if(m%n==0) printf("最大公約数は%d",n); ←このあたりがわかりません else if (n%(m%n)) printf("最大公約数は%d",n%(m%n)); int main( void ) { int na, nb; puts(""二つの整数を入力してください。); printf("整数1:"); scanf("%d",na); printf("整数2:"); scanf("%d",nb); printf("最大公約数は%dです。\n",gcd(int m, int n)); return0; }

  • C言語 再帰呼びだし

    C言語 再帰呼びだし 問題が解けません。もしよろしければご指導お願いします。 フィボナッチ数を求めるプログラミングを作成せよ。 非負の整数nに対するフィボナッチ数Fnは以下のように再帰的に定義される。 Fn=0 (n=0の時) Fn=1 (n=1の時) Fn=F(n-1)+F(n-2) (n>1の時) ・関数int fibo(int n)を作成し、関数mainで、複数のnに対して関数fiboを呼びだし、その結果を表示せよ。 ・関数fiboは、再帰的にfiboを呼びだすようにせよ。 よろしくお願いします。

  • c言語の再帰で(関数呼び出し)+1がわからない

    再帰がどのように処理されているのか理解するために、再帰の時に +1 してみたところ 0! = 1 1! = 2 2! = 5 3! = 16 4! = 65 5! = 326 6! = 1957 7! = 13700 8! = 109601 9! = 986410 10! = 9864101 となりました。 普通の階乗の値を求めた最後に +1され、それが戻されると思ったのですが違いました。 これはどういう処理がされているのでしょうか? #include <stdio.h> int kaijo(int); int main() { int i; for (i = 0; i < 11; i++) printf("%d! = %d\n", i, kaijo(i)); return 0; } int kaijo(int n) { if (n == 0) return 1; else return n * kaijo(n - 1) + 1; }

  • 再帰について(C言語)

    今、再帰処理を勉強しています。 しかし、以下のプログラムがどうしても理解できません。 流れ的には一体どういう手順になっているのでしょうか? return i * fact( i - 1 )の部分を考えると頭が こんがらがってしまいます。 #include <stdio.h> int main( void ){  printf("5の階乗は %d です", fact(5) );  return 0; } int fact( int i ){  if( i == 1 ) return 1;  else return i * fact( i - 1 ); } --------実行結果---------- 5の階乗は 120 です

専門家に質問してみよう