質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

6回答

2908閲覧

初項から第n項までのフィボナッチ数列を作成する。

fibo

総合スコア1

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2021/07/20 06:45

編集2021/07/21 01:14

解答例

c言語

1#include <stdio.h> 2int fibo(int n); 3int main(void) 4{ 5 int i, no; 6 printf("初項から第何項のフィボナッチ数を求めますか?:"); 7 scanf("%d", &no); 8 for(i=0; i<no; i++) 9 { 10 printf("%d\n", fibo(i)); 11 } 12 return 0; 13} 14 15int fibo(int n) 16{ 17 if(n == 0 || n == 1) 18 return 1; 19 return fibo(n-1) + fibo(n-2); 20} 21```### 前提・実現したいこと 22 23c言語で初項から第n項までのフィボナッチ数列を作成したいのですが、第n項の数値しか表示されません。 24### 発生している問題・エラーメッセージ 25

再帰するごとに数値を表示することができません。

### 該当のソースコード ```c言語 #include <stdio.h> int fibo(int n); int main(void) { int n; printf("初項から第何項までのフィボナッチ数を求めますか?:"); scanf( "%d", &n ); printf( "%d\n", fibo(n) ); return 0; } int fibo(int n) { if(n==0) return 0; if(n==1) return 1; if(n>=2) return fibo(n-1)+fibo(n-2); }

試したこと

ここに問題に対して試したことを記載してください。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2021/07/20 06:59

> 再帰するごとに数値を表示することができません。 現状のコードではそうならないのはわかったとして、どのように手を入れようとしましたか?
fibo

2021/07/20 07:07

printf( "%d\n", fibo(n) );の部分を変えて再帰毎に表示しようとしました。
SaitoAtsushi

2021/07/20 07:10

どうしてそれで再帰毎の表示になると考えましたか? 要するに、もちろん解答となるコードを与えることは出来るのですが説明すべきことが何であるのかわからないというのが回答者側の状況です。
fibo

2021/07/20 07:23

文章が拙くて申し訳ありません。
BeatStar

2021/07/20 07:31 編集

> 文章が拙くて申し訳ありません。 文章が拙いのは構いません。(できればちゃんとした方がいいが、他人に言えない……) えーっと、失礼ですが、質問にあるコードって、ご自身で考えて書いたのでしょうか。 それとも『どこからか持ってきたもの』でしょうか。 前者、つまり『自分で考えたもの』であれば、『どういうロジックなのか』を説明してほしいです。 もしかしたら勘違いなさっているかもしれませんし、 惜しいところまで来ていているのかもしれません。 後者、つまり『どこからかのコピペ』(手打ちであっても)であれば、『基礎からやり直しましょう』となります。 後者であれば理解せずに書いているはずなので。 つまり、『なぜこのコードになったのか』とかを説明してほしいのです。 (意外とコピペでつぎはぎだらけでも『動くからいいや』と「俺はプログラミングができる」と豪語している人が多いので)
fibo

2021/07/20 07:56

コードは自分で作成しましたが、再帰の動作の認識を誤っていたためprintf( "%d\n", fibo(n) );と入力しました。しかし、初項から第n項までのフィボナッチ数列を表示する方法が思いつかず、ソースコードでは一応動作させるためにそのようになりました。初項から第n項までのフィボナッチ数列を表示する方法をご存じでしたらご教授ください。
fana

2021/07/21 02:03 編集

(追記された「解答例」では初項の値が1になってませんか? ←→ 元々のコードでは fibo(0)の値は0になるハズ)
fibo

2021/07/21 02:17

コードを読みやすくするために解答例では初項の値を1にしました。初項の値が0か1かによって数列自体に影響はないので問題ないと思います。
Zuishin

2021/07/21 04:58

影響ないはずがないでしょう。 実際に両方動かしてみれば違うことがわかります。
guest

回答6

0

C

1int fibo(int n) { 2 int result; 3 フィボナッチ数列の第n項をresultに求めるコードをここに書く(これはアナタのしごと) 4 printf("fibo(%d) = %d\n", n, result); 5 return result; 6}

投稿2021/07/20 08:35

episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fibo

2021/07/20 09:12

解決しました。回答ありがとうございました。
Zuishin

2021/07/20 09:16

本当に解決したのかな? ベストアンサーの回答の通りにしたのならメモ化しなきゃいけないはずだけど、どこかでマルチポストしたんじゃないの?
guest

0

ベストアンサー

まずは、コードを読むことを学んだ方がいいです。

コードを読むコツは『一行レベルで、その行が何をしているのかを考えながら読む』です。

そもそも、プログラミングっていうのは『こう書けばいい』ものではありません

私の過去回答を参考にしてください。

それではやってみましょう。

C

1#include <stdio.h> 2 3// プロトタイプ宣言 4int fibo(int n); 5 6// main関数定義 7int main(void) 8{ 9 // 変数宣言 10 int n; 11 // 入力を求める 12 printf("初項から第何項までのフィボナッチ数を求めますか?:"); 13 // 入力値を受け取り, n にセット 14 scanf( "%d", &n ); 15 // fibo関数で計算し出力する 16 printf( "%d\n", fibo(n) ); 17 // 終了 18 return 0; 19}

がmain関数周辺ですね。

これを日本語でも英語でも中国語でもなんでもいいので、自分が読み書きできる言語で書き下してみる。
(現実世界のノートなりテキストファイルになり)

それを疑似コードとします。

0. 変数宣言 1. 入力を求める 2. 入力値を受け取り, n にセット 3. fibo関数を使って計算し, 出力する 4. 終了

と言う風に。

で、fibo関数が呼ばれているので、fibo関数も同様にやる。

C

1// fibo関数定義 2int fibo(int n) 3{ 4 // n が 0なら 0 を返して終了 5 if(n==0) 6 return 0; 7 8 // n が 1 なら 1を返して終了 9 if(n==1) 10 return 1; 11 12 // (それ以外なら) 13 // n が 2 以上なら 14 if(n>=2) 15 // fibo関数に n-1 のときと n-2 のときの和を返す 16 return fibo(n-1)+fibo(n-2); 17}

これも同様に疑似コードにする。

0. (関数が呼ばれたら) (= 処理開始) 1. n が 0 なら 1.1. 「0」を返す 2. n が 1 なら 2.1. 「1」を返す 3. n が 2以上なら 3.1. 再帰的にfibo関数を呼び出して n+1 のときと n-2 のときの「和」を返す

これを現実世界で、手作業でシミュレーションしてみてください。
つまり、数学とかを解くような感じで手作業でやるのです。

脳内で出来るのなら脳内でもいいですが。

そうすると、「あれ? 俺……出力してなくね?」と気づきますよね?

ではどこにどうすればいいでしょうか。

方法としては2つほど思いつきますね。

一つは、fibo関数内で疑似コードでのどこかに入れる所があるはずなのでそこに入れてみる。

もう一つは、「配列を使う」ですかね。

グローバル変数(配列だけど)として保持します。

まあ、メモ化とかのような感じでしょうか。
(厳密には違うと思いますが)

そして、最終的にmain関数かどこかで、再帰処理が完了した後に、配列の中身を出力するとか。


[追記1]

ついでに「グローバル変数の危険性」についても書いておきます。
(説明っていうか、リンクだけど)

グローバル変数は『どこからでもアクセスができる』ので、場合によっては相当やばい事になります。

ですが競技プログラミングや課題等のレベルならそこまで問題にならないようなので良く使われるようです。
(たとえば「動的計画法」とか)

参考: グローバル変数の性質とその危険性

使うときは危険性を理解した上で使ってくださいね。

投稿2021/07/20 08:17

編集2021/07/20 10:09
BeatStar

総合スコア4958

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fibo

2021/07/20 09:17

解決することができました。また、プログラミングの勉強法を丁寧に教えていただきありがとうございました。
guest

0

「メモ化」してみた。

C

1#include <stdio.h> 2#include <stdlib.h> 3 4int fibo(int n, int* table); 5 6int main(void) { 7 int n; 8 printf("初項から第何項までのフィボナッチ数を求めますか?:"); 9 scanf( "%d", &n ); 10 11 // 空の表(メモ)を用意する 12 int* fibo_table = (int*)malloc(sizeof(int)*(n+1)); 13 for ( int i = 0; i <= n; ++i ) { 14 fibo_table[i] = 0; 15 } 16 17 fibo(n, fibo_table); 18 19 free(fibo_table); 20 return 0; 21} 22 23int fibo(int n, int* table) { 24 // 表を引く 25 int result = table[n]; 26 // 表に載ってなかったら計算し、表に載せてプリントする 27 if ( result == 0 ) { 28 result = ( n <= 2 ) ? 1 : fibo(n-2, table) + fibo(n-1, table); 29 table[n] = result; 30 printf("fibo(%d) = %d\n", n, result); 31 } 32 return result; 33}

投稿2021/07/20 21:29

episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

再帰するごとに数値を表示することができません。

フィボナッチ数列を再帰呼出しで書くことは簡単ですが、
同じ計算を何度も行い非効率です。

初項(第0項)から第n項まで、(n+1)個の数値を表示しなければならないのに、
fibo の呼出し回数はそれ以上になります。

したがって、再帰するごとに数値を表示することはできません。

解決したのなら、そのコードを質問に追記して下さい。
出来ないことを出来たというのだから、非常に興味深いものです。

再起を行っている内部で結果を出力する場合、どのようにプログラムを行えばいいですか?

再帰呼出しを行いながら、必要に時だけ表示して、
そうでない時は表示しないというやりかたなら出来ます。

c

1#include <stdio.h> 2 3int fibo(int n); 4 5int main(void) 6{ 7 int n; 8 printf("初項から第何項までのフィボナッチ数を求めますか?:"); 9 scanf( "%d", &n ); 10 fibo(n); 11 return 0; 12} 13 14int fibo(int n) 15{ 16 static int k = 0; 17 int f; 18 if (n == 0) f = 0; 19 else if (n == 1) f = 1; 20 else f = fibo(n-1) + fibo(n-2); 21 if (k <= n && (k > 0 || n == 0)) { 22 printf("%d\n", f); 23 k++; 24 } 25 return f; 26}

投稿2021/07/20 10:56

編集2021/07/20 11:17
kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

for(i=0;i<n;i++)printf( "%d\n", fibo(i) );

投稿2021/07/20 09:18

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BeatStar

2021/07/20 09:22

いや、それだと相当な計算量になるんだが…… (数学苦手な私ですらヤバいと分かるレベル…)
BeatStar

2021/07/20 09:28

計算ミスもあるかもしれないけど、私が考えるに、質問にあるコードのfibo関数を使うと、 少なくともO(n)はあるはず。 それをn回繰り返すわけだから、最低でもO(n^2)はかかりますよ? 普通にちゃんとやればO(n)で済むのに……
退会済みユーザー

退会済みユーザー

2021/07/20 09:31

付きまとわないで、
fana

2021/07/20 09:59

本件は > 再帰するごとに数値を表示する っていう面倒そうな話にわざわざなっていて,「関数fiboの中で表示する」という方針らしいので,この回答ではその話に即していないのではないだろうか. (動けばいいじゃん,っていうなら「そもそも再帰で書かねぇだろこんなもん」っていう根本から否定する話になりますし)
退会済みユーザー

退会済みユーザー

2021/07/20 10:08

分からない...
dodox86

2021/07/20 10:25

@BeatStarさん、@fanaさん 指摘によって後で読んだ方の為の検討材料が示されたことは良いことだと思いますが、とりあえず計算量の問題は置いておくとして、質問として求める回答は単純に「初項から第n項までのフィボナッチ数列を表示する方法」が当初のものであったと思うので、アリなのではないでしょうか。再帰の過程で表示するかどうかは質疑応答が進んだところで出た話だと思います。 ※本コメントはBeatStarさんの計算量についての指摘で投稿しようと考えていたものですが、よくよく読んでみると本回答と同じものがmaisumakunさんの回答中の[2021/07/20 16:59]のコメントで先に示されてたので、投稿を控えていました。
BeatStar

2021/07/20 10:30

dodox86さん > 、とりあえず計算量の問題は置いておくとして、質問として求める回答は単純に「初項から第n項までのフィボナッチ数列を表示する方法」が当初のものであったと思うので、... あー……、確かにそうですね……(言われたらそうかも) ……あ、確かに書いてありますね。
BeatStar

2021/07/20 10:32

発言を取り消します。(削除した方がいいでしょうか?)
fana

2021/07/20 10:37

> 単純に「初項から第n項までのフィボナッチ数列を表示する方法」 で良いのであれば, あえて自分で把握もできない再帰を採用して自爆する必要性はどこにもないんだから,もっと素直にやればいいだけなんじゃないかと思うんだけど,誰もそこらへんに突っ込んでない様子だったので,これはもう「再帰の中で表示する」前提で話が進んでいるのかな,と. ま,とりあえず,このteratailでもfor1つで解決する素直な話が見られるので,リンクを示しておきます. https://teratail.com/questions/297503
dodox86

2021/07/20 10:41

@BeatStarさん > 発言を取り消します。(削除した方がいいでしょうか?) 質問主でも回答主でもない者のいち意見ですが、回答を否定している訳ではなく、情報の補足、意見的な意味合いがあると思うので、削除するほどのことは無いと私は考えます。コメントの経緯も分からなくなってしまいますし。
BeatStar

2021/07/20 11:03

dodox86さん > 削除するほどのことは無いと私は考えます。 了解しました。
fana

2021/07/21 02:17

結局この形が質問者によって解決策として採用された様子. よって,質問を読み違えていたのは私であった.
BeatStar

2021/07/21 02:20 編集

ですね……(私も)
退会済みユーザー

退会済みユーザー

2021/07/21 04:42

ねえ高評価は?これ実質、詐欺だろ?正当な報酬が与えれてない
Zuishin

2021/07/21 04:57

n を 20 にしてみればわかるけど、高評価に値するようなものではない。 間違ってないから低評価が入ってないだけで、ギリギリ最低限でしかない。 評価なしで妥当。
退会済みユーザー

退会済みユーザー

2021/07/21 05:01

揚げ足だから付きまとわないで、
Zuishin

2021/07/21 05:09

じゃあ黙ってろ。
退会済みユーザー

退会済みユーザー

2021/07/21 05:12

??? あなたが勝手に付きまとっている。
dodox86

2021/07/21 05:16

いえ、揚げ足取りではありませんよ。私も正直、Zuishinさんと同じ意見です。計算量の話から違う話に行きそうになったのでコメントした迄です。
退会済みユーザー

退会済みユーザー

2021/07/21 05:20

Zuishin 私が勉強して、IT技術の知識の立場が逆になっても、後で後悔しないでください、泣かないでください。
episteme

2021/07/21 05:45 編集

質問には「"再帰するごとに"数値を表示することができません。」が問題だ とある。 この回答は上記の問題を解決していない。低評価。
退会済みユーザー

退会済みユーザー

2021/07/21 05:51

答えを教えて。
dodox86

2021/07/21 06:00 編集

@回答主 YukkuriReimuさん 当初のコメントは助け舟を出したつもりもあったのですが、大きなお世話に終わった様ですね。以降はスルーさせていただきます。
退会済みユーザー

退会済みユーザー

2021/07/21 05:57

https://prnt.sc/1dm4uli https://prnt.sc/1dm4qw0 低評価ありがとう!!!!!!!!!!!!!!!!!!!!!!!!!!!144398/144412、屈辱的である。楽しいですか?
fana

2021/07/21 05:58

評価に関して言えば,この回答内容は ・(最初にコメントした時点で)これは話として違くない?と思った(←結局質問者は文面の内容にこだわってはいなかったということが事後に判明したが) ・「いちばん原始的には…」という断りの上で,既にコメントで既出の話であった ・そのような断りがされているくらい,方法論としては上策とは言えない.(非常にnが小さい場合に限定してよいならば,まぁそれでもいいかな,という) と,まぁ,若干ネガティブ寄りな方向の要素が多い気もしますけど,あえてマイナスつけるほどでもないかな,と. で,プラス評価を付けるべき良い要素を含んでいるわけでも無いので,わたしは「どっちも付けてない」という結論です.
退会済みユーザー

退会済みユーザー

2021/07/21 06:00

プログラミング難しい...
episteme

2021/07/21 06:03

> 楽しいですか? いいえ 質問に相応しい回答ではないと判断し、低評価した。
退会済みユーザー

退会済みユーザー

2021/07/21 06:06

スコアを上げたい、やめてほしい ランキングに乗りたい
BeatStar

2021/07/21 06:14 編集

マジでツッコミたいんだけど、 YukkuriReimuさん、以前のやりとりとかで『自分はとあるWebアプリ(かなんか)で教えたり、すごい有名なアプリも作っていて、とても素晴らしい技術をもっている。だから黙○』とかみたいな暴言を吐いていた気がしますが、『計算量』すら満足に理解していない人がそれは無理じゃないかなと。 頻繁にサーバがダウンしたり、場合によっては個人情報が…とかもありえます。 怖いことですよ。 今回は、質問者さんが『単に動けば良い』という前提らしいので低評価まではいきませんが、 少なくとも『納得できるレベルではない』です。 YukkuriReimuさんがお使いのアプリやソフトなんかが異様に処理が遅いとかだとどう思いますか? 例えば私がこのteratailさんのようなアプリを開発したとします。 ですが、たかがメインページを開くだけでも10分ぐらいはかかるとかだとしたら『使います』か? 私なら使いません。 プログラミングは組むだけではありません。
fana

2021/07/21 06:16

> ランキングに乗りたい 仮にあなたが週に10個の回答をして,そのうちの半数が高評価され,半数がベストアンサーに選ばれたとしても,スコアは +55 点(10*2 + 5*2 + 5*5). 週間ランキングに並んでいるスコアと比較してみれば,我々みたいなふつーの利用者はランキングがどうのとか考えるだけ無駄ってことがわかるよ.
BeatStar

2021/07/21 06:17

そもそもここは『プログラミング関係での問題を解決するための糸口を見つけるためのもの』です。 レスバしたいだけ、自己顕示欲や承認欲求を満たしたいだけならここではなく、別の場所(某袋とか)でやりましょう。
BeatStar

2021/07/21 06:24

YukkuriReimuさんが今やっていらっしゃることは 『真剣に相談しているところに、無関係の人が出てきて暴言を吐いたり、叫び回って邪魔している状態』です。 そもそもアドバイスする気もなく、単に『構ってちゃん』的な言動をしていたら邪魔でしょうがない。
退会済みユーザー

退会済みユーザー

2021/07/21 06:30

私はアドバイス必要ではない、私は数学が得意。私はtwitterで1000いいね1000RT1000コメント獲得したことがある。私は人気がある。しかも、discordでは有能な管理者として認められています。100人以上のユーザーがいるアクティブなサーバーをたくさん管理して、信頼されている。私は権力がある。多くのコミュニティを正しい方向に導き、より早く成長させるためのスキルを持っています。プログラミングを完全にマスターし、完全なウェブサービスを作れる。日本人は陰湿である。 私は『構ってちゃん』的な言動をしていない。私が解答して貢献している。
BeatStar

2021/07/21 07:31 編集

(不適切発言に見えなくもないため削除予定)
退会済みユーザー

退会済みユーザー

2021/07/21 07:33

私は日本人である。私は日本語を流暢に話します。私は寿司、美少女、美少年が好きです。
guest

0

printf( "%d\n", fibo(n) );の部分を変えて再帰毎に表示しようとしました。

その場所は1回しか通りませんので、再帰の全結果を表示させることはできません。

再帰を行っているfibo内部で出力させましょう。

投稿2021/07/20 07:10

maisumakun

総合スコア145208

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fibo

2021/07/20 07:23

再起を行っている内部で結果を出力する場合、どのようにプログラムを行えばいいですか?
maisumakun

2021/07/20 07:46

試してみた状況も見せないままで、次の質問をするのはなぜでしょうか?
maisumakun

2021/07/20 07:59

(いちばん原始的には、「1からnまで」fibo(n)を呼んでその結果を表示する、という方法があります)
fana

2021/07/20 08:47 編集

> fibo(n-1)+fibo(n-2) ここの2つの項の評価順序ってC言語的に決まってるんでしょうか? 仮に決まってないなら,fiboの内部で出力すると,必ずしも「良い順序で」表示できるとは限らない…のかも. > 再帰するごとに数値を表示することができません。 という話になってるから,(何故だか不明ですがとにかく)fiboが呼ばれるたびに何かを表示するんですよね?(その妥当な表示結果イメージが湧かないな)
fibo

2021/07/20 09:19

解決しました。回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問