プロが教える店舗&オフィスのセキュリティ対策術

/*

プログラム作成に当たっては以下の注意を守ること。
•入力は整数変数に格納し、有効な日付かどうかチェックせよ。
•日付チェックでは、月の最終日が月によって違うことも考慮にいれること。
•日付チェックにおけるif文を減らすため、daynum[]を必ず使うこと。
•日付チェック以外でも、if文やswitch-case文の数はなるべく少なくするよう工夫せよ。今回は、if文の7行並列も、12行並列も禁止。
•日付の範囲チェックと計算とを同時に実行してもよい。


2個の整数を入力し、それぞれを2011年度の月、日とみなして、
その日付からおよその月齢と月相を計算して表示するプログラムを作成せよ。
月齢と月相の対応は簡便的に3.75齢毎に相が進むとしてよい。
suuumは月齢であるが、計算は以下のもので間違いない。

また、以下の配列を定義して使うこと。

char moonphasename[][15]= {"new moon", "new crescent", "first quarter", "waxing gibbous",
"full moon", "waning gibbous", "last quarter", "old crescent"};
*/


#include <stdio.h>

int main(void)
{

int daynum[]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int i=0,j=0;

/*15はもじすう+1*/
char moonphasename[][15]= {"new moon", "new crescent", "first quarter","waxing gibbous", "full moon", "waning gibbous", "last quarter", "old crescent"};
int month,day,sum,suum,suuum;


printf("月と日付を入力してね:");

scanf("%d%d", &month, &day);


if(day>daynum[month]){
printf("2011年にそんな日はありません");
return(-1);

}



sum=(2011-1740)*210;
suum=((sum/19)-2)+month+day;

if(month==1)
suuum=suum+1;

else if(month==2)
suuum=suum+2;

else if(month==3 ||month==5)
suuum=suum-1;

else suuum=suum;

printf("月齢は%d",suuum%30);

for(i=0; i<=suuum &&suuum<i+3.75 ; i=i+3.75){

printf("月相は",moonphasename[j][15]);
j++ ;
}



return (0);
}

と書いてリナックスのeclipsで実行させました。月齢はでるのですが、月相が表示されません(月相は という文字も非表示)。
どうしたらいいでしょうか?
また、最後のfor文ではsuuumが0から3.75のときしか反応しません(見ての通り)。どう書き直せばいいでしょうか?
詳しいかたおねがいします。

A 回答 (4件)

とりあえず、


i<=suuum &&suuum<i+3.75

(i<=suuum) &&(suuum<i+3.75)
はちゃんと同じ意味になります。

Cのトークン解析は、意味が通じる「最も長い」文字を切り取りますから、スペースがないからと言って、
i<=suuum &&suuum<i+3.75 を i<=suuum & &suuum<i+3.75 と解釈したりはしません。

と、それだけでは何なので、問題についても含めて、周辺を少々。

> •日付チェック以外でも、if文やswitch-case文の数はなるべく少なくするよう工夫せよ。今回は、if文の7行並列も、12行並列も禁止。

とわざわざ指定するなら、月齢の計算も、
int offset[] = {1, 2, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0};
sum = (2011-1740)*210;
suuum = sum/19 + month + day + offset[month - 1] - 2;

か、最後の -2 も offset に取り込むなら、

int offset[] = {-1, 0, -3, -2, -3, -2, -2, -2, -2, -2, -2, -2};
sum = (2011-1740)*210;
suuum = sum/19 + month + day + offset[month - 1];

あと、ひとつ計算をするたびに、sum suum suuum なんていう変数を使うのも、間違いの元なので、お断りしたいところ。

こんな変数を使わなくても、

int offset[] = {-1, 0, -3, -2, -3, -2, -2, -2, -2, -2, -2, -2};
getsurei = (2011-1740)*210;
getsurei = getsurei/19 + month + day + offset[month - 1];
で十分だし、

offset[month - 1] がいやなら、(daynum とおなじようにして)

int offset[] = {0, -1, 0, -3, -2, -3, -2, -2, -2, -2, -2, -2, -2};
getsurei = (2011-1740)*210;
getsurei = getsurei/19 + month + day + offset[month];
でも。

あと、もうひとつ大きな間違いは、この時点で、30に正規化していない点。
それを含めれば、最後に、
getsurei %= 30;
が必要です。

質問のソースの中で、これも引っかかってますね。
月齢の表示は、suuum % 30 を表示しているので、それらしい数字が表示できてきますが、月相の判定は、suuum をそのまま使ってしまっているから、ここでも、正解から遠ざかっています。

あと、入力された日付の判定で、「有効な月か」の判定がないですし(問題の指定にもないけど)
マイナスの日付に対するチェックもないですね。


複数のチェックをする場合には、関数を使って

int dayIsOK(int month, int day)
{
if (month <= 0) return 0;
if (month > 12) return 0;
if (day <= 0) return 0;
if (day > daynum[month]) return 0;
return 1;
}

として、main() で、

if (! dayIsOK(month, day)
{
printf("2011年にそんな日はありません");
return(-1);
}

などとすれば、チェックの条件が複雑になっても見かけを単純にすることができます。
    • good
    • 0

for文の 「 i<=suuum &&suuum<i+3.75 ; 」 ですが、実際のソースもこのままの状態ですか?


きちんと空白を挟むか、試しに「 (i<=suuum) &&(suuum<i+3.75) ; 」 としてみてはどうでしょうか?
(&& と & の優先順のような気がします...)

あと、「 printf("月相は",moonphasename[j][15]); 」 ですが、
「 printf("月相は",moonphasename[j]); 」 なのでは?

参考URL:http://www.bohyoh.com/CandCPP/C/operator.html
    • good
    • 0

> 月相が表示されません(月相は という文字も非表示)



> 最後のfor文ではsuuumが0から3.75のときしか反応しません
というのは、矛盾するような気がしますがどうなのでしょう?

「最後の for で、suuum が、0 から 3.75のときには『反応する』」
というのは、どういう状況なのかなと。

ソースを見ると、suuum が、0以上 3.75未満の時には、「月相は」だけ表示。
それ以外の時には、何も表示されないというのだとは思いますが。



まず、月齢計算は、int で良いのじゃないかなと思います。
簡易的な月齢の計算式で、あえて、切り捨てをしている気がしますが。

それ以前に、いろいろな問題があります。

printf("月相は",moonphasename[j][15]);

これでは、(表示されたとしても)「月相は」しか表示されません。
文字(列)の表示方法を復習しましょう。
(少なくとも、2つ間違いがあります)

あと、たとえば、suuum が、20 の時に、

for(i=0; i<=suuum &&suuum<i+3.75 ; i=i+3.75)
{
printf("月相は",moonphasename[j][15]);
j++ ;
}

が、どういう風に実行されるのか、ひとつずつ確かめましょう。
(i が int なのは問題ですが、それ以外にも大きな間違いをしています)

前にやった似たような(と思う)課題から、ひっぱってくるのではなく、
どう動くはずなのか、suuum が、0のとき、10のとき、20のとき、くらいは
手作業で確認しましょう。
    • good
    • 0

アルゴリズムが合っているのならsuum変数の宣言の問題かと思います。



suumは整数でないからfloat宣言して
 float suum;
 float f;

 suum=((sum/19.)-2.)+(float)month+(float)day;
   :
 if(month==1)
 suuum=suum+1.;
   :
 for(f=0; f<=suuum && suuum<f+3.75 ; f=f+3.75){

のようにキャストした変数を代入して、整数値の後ろは念のためドットをつけたらどうでしょう?

もしくはsuumが小数点2桁まで有効にしたいのであれば1000倍して整数のまま計算するとか
 suum=((sum*1000/19)-2*1000)+(month+day)*1000;
   :
 if(month==1)
 suuum=suum+1000;
   :
 for(i=0; i<=suuum &&suuum<i+3750 ; i=i+3750){

この場合は問題無いと思いますが、suumがオーバーフローしないように注意して下さい。

------------
ともかく小数を扱うならfloatかdouble変数を利用して
しないのなら整数の範囲で扱えるように値を常数倍しましょう。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!