🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

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

Q&A

解決済

6回答

4135閲覧

C言語において1つの関数内に複数のreturn文を記述することは文法上問題あるでしょうか?

Suika01

総合スコア12

C

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

0グッド

2クリップ

投稿2022/02/15 17:05

質問内容

プログラミング初心者です。今回が初めての質問になります。

私なりに素数を判定するプログラムを書いてみたのですが、main関数内で3回"return 0"と記述しています。このように1つの関数内で複数のreturn文を用いることは文法上問題あるでしょうか?
return文は関数の最後に使うものというイメージがあるので、このような使い方が正しいのか悩んでおります。
文法上問題なかったとしても、このようなコードは美しくないとされるでしょうか?

回答よろしくお願いいたします。

該当のソースコード

C言語

1#include <stdio.h> 2 3int main(void) 4{ 5 int i, num; 6 7 printf("自然数を入力してください。\n"); 8 scanf("%d", &num); 9 10 if (num == 1) 11 { 12 printf("%dは素数ではありません。\n", num); 13 return 0; 14 } 15 16 for (i = 2; i < num; i++) 17 if (num % i == 0) 18 { 19 printf("%dは素数ではありません。\n", num); 20 return 0; 21 } 22 23 printf("%dは素数です。\n", num); 24 return 0; 25}

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

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

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

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

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

guest

回答6

0

ベストアンサー

言語仕様には以下のように明記されています。 (C99 の項目 6.8.6.4 の第二段落から抜粋)

A function may have any number of return statements.
(一つの関数は,任意の個数のreturn文をもってもよい。)

作法として美しいかどうかというのは総合的な判断なのでこの場合についての皆さんの意見が他の場合にそのまま当てはめられるわけではないということは強く主張しておきます。 どちらかを常に適用するという教条主義に陥らないように各状況をよく把握して考えてください。

投稿2022/02/16 02:31

SaitoAtsushi

総合スコア5684

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

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

Suika01

2022/02/16 15:06

回答ありがとうございます。 とりあえずは問題ないと分かり安心しました。 また、ケースバイケースということも肝に銘じていきたいです。
guest

0

まず根本的なこととして、「文法上問題がないか」というのはコンパイラに聞けば分かる話なので、
貴方のプログラムをコンパイラがエラーや警告を出さずにコンパイルしてくれたのなら、
他人に訊くまでもなく、それが「問題ない」という答えだと判断できます。
(まぁ、コンパイラによって多少の違い(方言)はあるようですが、本件のような重要な点はまず同じです。)

その上で「これは良い書き方なのか?」と疑問を持つのなら、それは良いことだと思いますし、この場合は疑問を持って正解です。

で、既に他の回答者の方々が仰っている通り、returnは必要に応じた数を書くのが適切です。

「returnを複数書いていいのか?」というのはどちらかと言うと心配のベクトルが逆で、
「returnをただ1つにすることに(大した根拠もなく)こだわってはまずいのではないか?」と心配した方が良いです。

return文は関数の最後に使うものというイメージがある

との事ですが、できれば、何故そのようなイメージを抱くに至ったのか教えて欲しいです。
勉強中に見たサンプルコードが、たまたまそういうものばかりだったとかでしょうか?

私も「ガード節」でググってみましたが、例えばこんなサイトがヒットしますね。
初心者向け。覚えておきたい 「ガード節」という書き方。 - Qiita https://qiita.com/kouyan/items/7b8b456b626447a1e24e
この解説はPHPの話ですが、本質的な所はどの言語でも同じなので理解できると思います。

人間の脳の記憶領域というのは狭いものなので、考えるべきことを可能な限り減らしてあげることが大事です。
例えば、貴方が(不幸にも!)他人の書いた関数の途中のある行を読んでいるとして、
それより上のif節の中にreturnがあれば、「if節の条件に当てはまる場合」は考慮しなくて済むことになり、理解がしやすくなります。
if節に対応するelse節を使えば同様のことはできますが、それをやっていくとネストがどんどん深くなって可読性が下がるので、典型的な悪いコードの一種になります。
言い換えれば、returnするということは、「この場合のことは、ここより下ではもう考えなくていいよ!」と、コードを読んでいる人に言ってあげる行為だと言えるでしょう。

文法上問題なかったとしても、このようなコードは美しくないとされるでしょうか?

「美しくない」という表現を使っていることがちょっと気になったので、蛇足的ですが所見を書いておきます。

コードの「美しさ」に配慮するのは良いことなので、それはそれで大事にしてください。
ただ、本件に関しては、「美しい」かどうかの問題に留まらず、「可読性」「保守性」と言った現実的な問題が実際に発生するからこちらの方が良いとされているのだ、と理解して欲しいです。
ある方法が良い/悪いとされるのにはそれなりの合理的な理由があるものであり、純粋に「美しさ」だけが問題になるようなケースはさほど多くないでしょう。

例えば「#include <stdio.h>」を「おまじない」と呼ぶような風潮に対しても私は良くないな~といつも思うのですが、
それと同様に、「美しいか否か」という曖昧な観点でコードの是非の判断をするのは、問題の本質をぼやけさせ、思考停止を生む要因になり得るので危険ではないか…と私は思います。
コードの書き方の理由を問われた時に、「一般に、これが美しい書き方だとされているのでこう書きました」と受け売りだけの回答をするようなプログラマは、私に言わせれば信頼性が低いです。
こういう理由があるからこう書いているんだよ、とちゃんと説明できるような人になって欲しいですね。

投稿2022/02/24 08:06

rabbitman

総合スコア37

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

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

0

文法上はなんの縛りもありません。
文法の縛りではありませんが、誤ってunreachableな部分を作ってしまうとコンパイラは警告ぐらいはしてくることが多いでしょう。

かつて、「入り口一つ、出口も一つが美しいんだ」という主張を聞いたことはありますが、あまり流行ってはいないようです。デバッグ時に関数を出る時にブレークを張るのも簡単でしょ? みたいなことも言っていたように思います。

私的には、returnというよりは外部への出力処理(質問の場合ではprintf)を一箇所にまとめたいなぁという意識があるので、このプログラムを私の趣味に合わせて書くと結果としてreturnが一つになったりします。しかしこれは組み込み屋的な都合によるものですので、一般論かと言われるとちょっと。

C

1nt main(void) 2{ 3 int i, num; 4 const char* result="です"; 5 const char* notPrime="ではありません"; 6 7 printf("自然数を入力してください。\n"); 8 scanf("%d", &num); 9 10 if (num != 1) 11 { 12 for (i = 2; i < num; i++) { 13 if (num % i == 0) 14 { 15 result=notPrime; 16 break; 17 } 18 } 19 } 20 printf("%dは素数%s。\n", num, result); 21 return 0; 22}

投稿2022/02/15 22:59

thkana

総合スコア7703

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

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

fana

2022/02/16 03:08

美しさ(?) の話ではないですが, 「関数の出口は末尾の1箇所だけにしろや」っていう規約だかガイドラインだかがどこかにあったような気がします. (そんなルールが適用されたらやってられんので猛反発した記憶が)
thkana

2022/02/16 11:09

このプログラムではきれいに書けましたが、決してそうではないことも多いですからね。脱出条件がいろいろあったりするときに「returnはひとつ」に縛られると悲惨なことになります。 ループしないwhile(1){}でくくってbreakしまくるのか、それくらいなら素直にgoto使えとかいう話で結局それって嬉しい? みたいな。
Suika01

2022/02/16 15:11

回答ありがとうございます。 printf文を一つにまとめたいという考え方共感しました。 自分なりに美しいコードの書き方を模索していこうと思います。
yohhoy

2022/02/18 06:29

> 「関数の出口は末尾の1箇所だけにしろや」っていう規約だかガイドラインだかがどこかにあったような気がします. fanaさんコメントは MISRA-C にある「関数では、関数の最後に唯一の出口があるべきである。」のことかもしれません。このルール自体も時代ごとに変遷してはいるようです。 https://swest.toppers.jp/SWEST16/data/s3d_proceeding.pdf
guest

0

「条件を満たさない場合にさっさとreturnする」ことは、ガード節と名前が付く程度には一般的な書き方です。

投稿2022/02/15 22:59

maisumakun

総合スコア145982

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

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

Suika01

2022/02/16 15:12

回答ありがとうございます。 ガード節に関して調べてみようと思います。
guest

0

このように1つの関数内で複数のreturn文を用いることは文法上問題あるでしょうか?

問題ないです

それよりも、returnが実行されないパスが無いように注意しましょう
コンパイルオプションで、ワーニングを全有効にしておけば、そういう基本的な抜けを指摘してくれるんで、おすすめです。
#が、余計なお世話の指摘もガンガン出てくるんで初心者のうちは混乱するかも

投稿2022/02/15 22:42

y_waiwai

総合スコア88040

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

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

Suika01

2022/02/16 15:13

回答ありがとうございます。 エディタやコンパイラの設定なども工夫すれば色々捗りそうですね。 勉強になります。
guest

0

幾つあっても問題ありません。
むしろ、必要なら速やかに終了すると言うことはコードを分かり易くすると思います。(異論はあるかも知れません。)

素数の判定部分を関数として分けると、"素数ではありません"の表示が1つに出来ます。

c

1#include <stdio.h> 2 3int isPrimeNumbers(int n) 4{ 5 if (n == 1) 6 return 0; 7 8 for (int i = 2; i < n; i++) 9 if (n % i == 0) 10 return 0; 11 12 return 1; 13} 14 15int main(void) 16{ 17 int num; 18 19 printf("自然数を入力してください。\n"); 20 scanf("%d", &num); 21 22 if (isPrimeNumbers(num)) 23 printf("%dは素数です。\n", num); 24 else 25 printf("%dは素数ではありません。\n", num); 26 27 return 0; 28}

ついでに、変数は最初に全て宣言するもの、というのも可能なら止められた方が(個人的には)良いと思います。

投稿2022/02/15 17:40

編集2022/02/15 19:09
jimbe

総合スコア13204

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

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

Suika01

2022/02/16 15:15

回答ありがとうございます。 判定部分など機能的な部分は関数に分けるという考え方、非常に美しいと感じます。 関数を使いこなせるよう勉強していこうと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問