ページ 11

その月に何日あるかを判定するプログラム

Posted: 2009年10月22日(木) 02:11
by まりも
 お世話になってます。
 
 今まで学習した内容がちゃんと理解できてるかどうか確認の意味で
 自分でプログラムを考えてみました。

 ★その西暦のその月に何日あるかを判定するプログラム★です。
 
 学習した範囲は 型・演算子・比較演算子・if文・switch文・for文・while文・配列 です。

 全部使いこなせないので、今回は主にif文と配列を使ってコードを書いてみました。
 
 予定している実行結果は・・・・「1900年の2月は28日あります。」→です。

うるう年の定義は
 「年が4で割り切れる年はうるう年だが100で割り切れる場合はうるう年ではない、
  そして400で割り切れる年はそれらとは無関係にうるう年」 です。

(蛇足ですが、うるう年は4年に1度だと思ってました。
   ところが、必ずしもそうではない事を
   C言語のサンプルソースで知って、ちょっと感動。
   400年に3回は、うるう年から次のうるう年まで7年位空くんです。
   ・・・最近だと1900年が通常の4年に1度のうるう年にあたらない年だと
   わかって1900年の2月に焦点を当ててみました。^^)

 コンパイラエラーが出てしまいます。

 教えてもらいたいのは、間違って書いている部分も勿論のこと
 プログラムを作る上での考え方があっているかどうか?

 ソースコードに こういう風に考えています、とわかってもらえるように
 コメントをつけていますので、そこに焦点をあててアドバイス頂けると
 とってもありがたいです。
(ココこう書くともっとスマートになるよ、とか、
こっちの表記がみやすいよ、など。)
 
 また、先に記述した 私が学習した範囲内で、if文や配列以外の
 方法でのプログラムや考え方などあったら、発想の転換にとっても参考になるので
 ぜひ、教えてください。よろしくお願いします。

 □使用しているコンパイラ gcc

◇ソースコード◇
 
#include <stdio.h>
  main ()
  {
     int year , month , days , the_days ;
     year = 1900 ;
     month = 2 ;

   // うるう年かどうかを判定し、うるう年の場合の処理
    if ( ( year%4 == 0 && year%100 != 0 ) || year%400 == 0 
            && ( month >= 1 && month <= 12) ) )
      {
        int days [12] = {31,29,31,30,31,30,31,31,30,31,30,31 } ;
        the_days = days [ month - 1 ] ;

         printf("%d年の%d月は%d日あります。\n" ,year ,month ,the_days) ;
       }

   // うるう年ではない場合の処理
  if ( ( year%4 != 0 && yaer%100 == 0 ) || yaer%400 != 0
            && ( month >= 1 && month <= 12 ) )
      {
       int days [12] = {31,28,31,30,31,30,31,31,30,31,30,31 } ;
       the_days = days [ month - 1 ] ;

         printf("%d年の%d月は%d日あります。\n" ,ywar ,month ,the_days) ;
       }

   // ありえない(例:55月など)数字入力があった時のエラー処理
    else
      {
       puts("入力エラーです。正しい数字を入力してください。");
      }
  }
コマンドプロンプト画面のコンパイルエラーの表示はこうです。
:6: error stray '\201' in program
:6: error syntax error at '@' token
  この二種類の表示が色んな行で 出ています。

 間違えないように注意しながらコメントを書いていたら
 2時間近くかかってしまいました・・・orz(不器用なので。;;)
 明日に差し支えてしまうので、今日はこれで寝ます。
 コメントを頂いた方にお礼を言うのが遅くなってしまいますが、
 必ず返しますので、許してください。

 

 
 
 
 

Re:その月に何日あるかを判定するプログラム

Posted: 2009年10月22日(木) 03:37
by Eeel
二つ目のif文は
else if ( ( year%4 != 0 || yaer%100 == 0 ) && yaer%400 != 0
    && ( month >= 1 && month <= 12 ) )
になります。
else if でなければ閏年だった場合もその後の else の内容が実行されてしまいます。
真逆の条件にする時は、
== → != 、 != → ==
だけでなく
|| → && 、 && → ||
になります。
(後半の month の式は閏年とは無関係なのでそのままで)

混乱しそうな時は実際に数値を書いたり日本語に直してみたりするといいかもしれません。
例えば、「year%4 != 0 && yaer%100 == 0」は「4で割り切れず100で割り切れるなら真」となりますが、
そのような数は無いので確実にFalseです。
「False || yaer%400 != 0」はただの「yaer%400 != 0」と同じで、これは「400で割り切れないなら真」となり、
意図した判定でないのがわかります。

今回の場合は閏年でなければ(≒最初のifで偽なら)閏年でない(≒2番目のifで真である)事が確実なので
2番目のifでは正しい範囲の数値かどうかを判定するだけでも大丈夫でしょう。
またif文をネストして

if(正しい数値か?){
 if(閏年か?){
  閏年の処理;
 }
 else{
  閏年でない年の処理;
 }
}
else{
 入力エラー;
}

とする事もできます。
ここの辺りは正解があるわけではないので一例です。
まりもさんがわかり易い書き方をするのが良いと思います。
あくまで私の場合は、ですが

配列への代入;
if(正しい数値か?){
 if(閏年か?){
  days[1] += 1;
 }
 出力;
}
else{
 入力エラー;
}

このような感じにすると思います。
参考になれば幸いです。

エラーについてはわらないのですが、
ひょっとしたらソースに全角スペースが含まれていたりしないでしょうか?
違ったらごめんなさい。

Re:その月に何日あるかを判定するプログラム

Posted: 2009年10月22日(木) 10:09
by Ma
ちゃんとコード読んでない人からのコメントです。
ぱっとみ、間違いがあったので指摘します。

int year , month , days , the_days ;
     year = 1900 ;
     month = 2 ;

   // うるう年かどうかを判定し、うるう年の場合の処理
    if ( ( year%4 == 0 && year%100 != 0 ) || year%400 == 0 
            && ( month >= 1 && month <= 12) ) )
      {
        int days [12] = {31,29,31,30,31,30,31,31,30,31,30,31 } ;
前半のみしか読んでません。。。


変数名 days の型が、二重宣言されています。
int days; として宣言しているのに
if 文内で、
int days[12]; として、再宣言してしまってます。


これって、たしかルール違反ですよね?

Re:その月に何日あるかを判定するプログラム

Posted: 2009年10月22日(木) 10:41
by toyo
>>Maさん
それは問題ないです
ブロックが違えば同じ変数名を使うことが出来ます
#include <stdio.h>

int main(void)
{
    int a = 10;
    {
        int a = 20;
        printf("%d\n", a); // 20
    }
    printf("%d\n", a); // 10
    return 0;
}
というのも許されます。
if ( ) { で別ブロックになっているのでこのブロックの先頭で宣言した変数はこのブロック内のみで有効になります。

Re:その月に何日あるかを判定するプログラム

Posted: 2009年10月22日(木) 10:52
by Ma
>toyo さん
そうでしたか、
ということはその場合、ブロック前の同じ変数名だった a は呼び出しおよび編集は不可能ということになりますよね?
逆に勉強になりました^^;どもです。

Re:その月に何日あるかを判定するプログラム

Posted: 2009年10月22日(木) 13:08
by ドラ
これまでの回答の他にも提示されたコードには以下のようなミスが存在します。

・()の対応が取れていない
・全角空白の混入
・変数名の間違い

Re:その月に何日あるかを判定するプログラム

Posted: 2009年10月22日(木) 23:56
by まりも
>> Eeelさん
 たくさんの丁寧な説明ありがとうございます。

 真逆の条件にする時の法則があるんですね。
 真逆の条件を考えて書いたつもりが、しっかり間違えていました。(^^;)

 混乱しそうな時は(実際してましたw)日本語に直して考えてみる。
 これ、とってもいいと思ったので、ひと手間ですけど、
 頭の中だけでしっかりイメージできるようになるまでは
 そうやってみます。

 Eeelさんが説明してくれたように
 「4で割り切れなくて、100で割り切れる数」って
 ・・・・・ 落ち着いて考えてみたら、ありえないですよね。(どんな数だ?)

 あと、if文をネストしての提案ありがとうございます。
 最初のコードがコンパイル成功したら、次にそれで
 コード書いてみます。(それが成功したら、最後はEeelさんのもtry予定で)

 エラーですが、他の方からの指摘もあった通り、全角スペースがあったようです。
 空白は無視されると思ってたので 全角スペースがエラーになる事を初めて知りました!!
  ・・・・とんでもない勘違いでした。・・・orz

>>Maさん toyoさん

 変数名と型、二重宣言の指摘と説明ありがとうございます。
 私も勉強になりました。

 days という変数名に 整数を入れたいので int ⇒ 型を宣言
 そして、12個の配列(=箱のイメージ)の中に入れたいのも整数だったので
 int days[12] と 
 書いてたのですが、二重宣言になってしまう事になるんでしょうか?

 たまたま ブロックが違っていたので、問題ないみたいなのですが。

 他の方からの指摘を参考にコンパイル成功したので、そのあと
 最初に宣言した int days の部分を削除してみました。

 (削除前)
int year , month , days , the_days ;
year = 1900 ;
month = 2 ;

(days削除)
  int year , month , the_days ;
year = 1900 ;
month = 2 ;

大丈夫(コンパイル成功)でした。
 (最初のdaysのint型宣言は不要だったんですね。^^;)

>>ドラさん
  ご指摘ありがとうございます。

・()の対応が取れていない
  ごめんなさい。これはまだ全く勉強してない部分ですが、
  これから調べてきます。

・全角空白の混入
  はい、その通りでした。Eeelさんからも同じ指摘があり、
  初めて全角スペースがエラーになる事を知りとても勉強になりました。

・変数名の間違い
  year ⇒ ywar でミス表記してました。
  (ミス打ちしないように気をつけてたのにも関わらず・・・;;
   すみません。)

 ○正しい比較演算子に訂正して
 ○スペースも全角ではなく半角で打つように注意して

 もう一度ソースコードを書いたら、見事コンパイル成功しました。 (∀`ヽ●)(ノ●´∀)ノ
 実行結果も狙い通り。
 皆さんありがとうございました。