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

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

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

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

Q&A

解決済

3回答

1217閲覧

C言語 西暦と月を入力してカレンダーを作成

amu.

総合スコア2

C

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

0グッド

0クリップ

投稿2023/05/14 00:45

編集2023/05/16 11:41

C言語を用いてカレンダーの作成をしています。

コード #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #define BASEYEAR 2000 /*プロトタイプ宣言*/ int leap_year(int);/*うるう年の場合の関数*/ int day_week(int, int, int*);/*曜日計算の関数*/ void main(void) { /*変数の宣言*/ int year = 0; int month = 0; int firstday = 0; /*データ入力・やり直し*/ while (1) { printf("西暦:"); scanf("%d", &year); if (year >= 1) /*yearが1以上でループを抜ける*/ { break; } printf("西暦は1以上で入力してください。\n"); } while (1) { printf("月:"); scanf("%d", &month); if (month >= 1 && month <= 12) /*monthが1~12の間でループを抜ける*/ { break; } printf("月は1~12の範囲で入力してください。\n"); } int day[12] = { 31,28 + leap_year(year),31,30,31,30,31,31,30,31,30,31 }; /*月末*/ /* 1日の曜日を取得 */ firstday = day_week(year, month, day); /* 曜日の表示 */ printf(" 日 月 火 水 木 金 土 \n"); printf(" -------------------- \n"); /* 1日の曜日まで空白を挿入 */ for (int i = 0; i < (firstday + 6) % 7; i++) { printf(" "); } /* 日付の表示 土曜日(0)で改行 */ for (int i = 1; i <= day[month - 1]; i++) { printf(" %2d", i); if (firstday == 0) { printf("\n"); } firstday = (firstday + 1) % 7; } /* 0を入力で表示を終了します */ int end = 0; do { printf("\n表示を終了する場合、0を入力してください\n"); scanf("%d", &end); rewind(stdin); } while (0 != end); } /*うるう年の場合の関数*/ int leap_year(int year) { if (year % 400 == 0) /*yearが400で割り切れればretun1*/ { return 1; } else if (year % 4 == 0 && year % 100 != 0) /*yearが4割り切れ,0でないとretun1*/ { return 1; } return 0; } /*曜日計算の関数*/ int day_week(int year, int month, int* day) { int yy = 0; /*2000年以降の曜日計算*/ if (BASEYEAR < year) { for (int i = BASEYEAR; i < year; i++) { yy += 1 + leap_year(i) ; } } /*2000年より前の曜日計算*/ else if (year < BASEYEAR) /*1996年からずれている*//*うるう年は+6でなく+7されている*/ { for (int i = year; i < BASEYEAR; i++) { yy += 6 + leap_year(i); } } /* 各月分の日付を足す */ for (int i = 1; i < month; i++) { yy += day[i - 1]; } /* 最後に7で割ると、その月の1日の曜日が求まる */ yy %= 7; return yy; }

C言語始めたての初心者です。
C言語を用いてカレンダーの作成をしています。ツェラーの公式等を使用しないで簡単な形でfor文・if文で作成したいです。

2000年1月を基準として行っています。
アドバイスをいただければ幸いです。

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

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

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

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

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

actorbug

2023/05/14 04:50

そもそも、基準としているはずの2000年1月時点で結果がずれているので、まずはそちらから合わせることを目標にしてみてはいかがでしょうか。
amu.

2023/05/14 05:43

コメントありがとうございます。曜日計算の関数にある最初のifのfor文内がずれてるという認識でよろしいでしょうか。
actorbug

2023/05/14 06:00

2000年1月と入力した際に、どうなるのが正しいか考えてください。2000年1月は基準なのだから、day_week内のyyの値が「yy%=7;」する前の時点で0になるのが正しいはずですが、そうなっていません。day_week内の節目節目でyyの値を確認し、どの処理でyyが0でなくなるのか調べるのがよろしいかと思います。確認方法は、デバッガを使うなり、printfで表示するなり、やりやすい方法でどうぞ。
退会済みユーザー

退会済みユーザー

2023/05/14 08:58

> C言語を用いてカレンダーの作成をしています。 C の話であればあなたが付けたタグの C# は間違ってます。C のタグがあるのでそれに付け替えてください。
jimbe

2023/05/14 10:32 編集

とりあえずコードのご提示にはコードのマークダウン(```だけの行で前後を囲む)を用いるように修正してください。コメントの /* */ の "*" が消えている等でコピペしても正常に動作させられません。
jimbe

2023/05/14 10:41

うるう年でズレるのは分かっているはずですから >/*曜日は1年で1日進む*/ というような前提でやるよりも、単純に2000年1月1日から指定年月まで何日あるかをループで年月の日数を足してそれを7日で割って余りを求めるほうが簡単ではないでしょうか。
jimbe

2023/05/16 02:41 編集

>int day[12] = { 31,28 + leap_year(year),31,30,31,30,31,31,30,31,30,31 }; /*月末*/ これは恐らく想像されている(year が変わったら配列の値も変わる)ようには動作しません。
guest

回答3

0

ベストアンサー

このコードには4つの誤りがあります。

  • 該当月の日数も含めてずらしてしまっている
    例えば、2月1日の曜日を求める際に、1月1日の曜日から31+28日分(1月と2月の日数)ずらしてしまっている。1月1日と2月1日の間は31日離れているので、31日分(1月の日数)だけずらすのが正しい。
  • 2月の日数を28日固定で計算している
    閏年なら2月は29日のはず
  • 2000年より後の計算で「曜日は1年で1日進む」の対応を二重に行っている
    yy = (year - BASEYEAR);とforループ内のyy += leap_year(i) + 1;で2日進めている。yy = (year - BASEYEAR);の処理を削除すべき。
  • 2000年より前の計算が間違っている
    1年さかのぼるたびに-1(閏年は-2)なので、最後にyy %= 7;することを考えると1年ごとに+6(閏年は+5)すべきだが、このコードだと1年ごとに+5(閏年は+6)してしまっている。

投稿2023/05/14 20:28

actorbug

総合スコア2212

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

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

amu.

2023/05/15 10:36

細かく見ていただきありがとうございます。 上記の誤りを修正したところ定数2000年以降の西暦を入力してもずれることなくできました! しかし、2000年前の入力(うるう年1996年)からずれてしまいます。デバッグで確認したところ、 /*2000年より前の曜日計算*/の関数にある yy += 6 + leap_year(i);が1996年から最初のループで+7されており、1日目の曜日がずれます。/*うるう年の場合の関数*/でreturn1していることから余計に+1されているのでしょうか。
actorbug

2023/05/15 13:31 編集

どうしても分からないなら、leap_year(i)の戻り値を足すようなトリッキーなコードはやめて、素直にif文で判定するのはいかがでしょうか。 if (leap_year(i)) yy += 5; else yy += 6;
actorbug

2023/05/15 21:26 編集

質問の内容を大幅に変えてしまうと、後から読んだときに既存の回答との整合性が取れなくなるので、避けるようにしてください。今回のケースなら、修正後のソースを追記するなど、元の質問が残る形にするのが望ましいです。
guest

0

2020年1月1日水曜日を基点に月の日数を加減算して指定年月の月初の曜日を求めています。

※ fflush(stdout) はこちらの環境(Eclipse)で必要だったもので、削除して構いません。

c

1#include <stdio.h> 2 3/** うるう年なら 1. 違うなら 0 を返す */ 4int leap_year(int year) { 5 if(year%400 == 0 || (year%100 != 0 && year%4 == 0)) return 1; 6 return 0; 7} 8 9/** 指定年月の日数を返す */ 10int number_of_days(int year, int month) { 11 if(month == 2) return 28 + leap_year(year); 12 if(month == 4 || month == 6 || month == 9 || month == 11) return 30; 13 return 31; 14} 15 16/** 指定年月の1日の曜日を返す(0=日) */ 17int day_of_week_of_first_day(int year, int month) { 18 int dow = 3; /*2020年1月1日は水曜日*/ 19 20 if(year >= 2020) { 21 /*指定年月まで日数を加算(指定年月自体の日数は含まない)*/ 22 for(int y=2020; y<=year; y++) { 23 for(int m=1; m<=12; m++) { 24 if(y == year && m == month) break; /*指定年月ならループ終了(y==year なので y のループも終わる)*/ 25 dow += number_of_days(y, m); 26 } 27 } 28 } else { /*year < 2020*/ 29 /*指定年月まで日数を減算(指定年月自体の日数を含む)*/ 30 for(int y=2020-1; y>=year; y--) { 31 for(int m=12; m>=1; m--) { 32 dow -= number_of_days(y, m); 33 if(y == year && m == month) break; /*指定年月ならループ終了(y==year なので y のループも終わる)*/ 34 } 35 } 36 } 37 38 dow %= 7; 39 if(dow < 0) dow = 7 + dow; 40 return dow; 41} 42 43int main(void) { 44 /* 入力 */ 45 int year = 0; 46 while(1) { 47 printf("西暦:"); fflush(stdout); 48 scanf("%d", &year); 49 if(1 <= year) break; /*入力が正常ならループ終了*/ 50 printf("西暦は1以上で入力してください。\n"); 51 } 52 int month = 0; 53 while(1) { 54 printf("月:"); fflush(stdout); 55 scanf("%d", &month); 56 if(1 <= month && month <= 12) break; /*入力が正常ならループ終了*/ 57 printf("月は1~12の範囲で入力してください。\n"); 58 } 59 60 /* 初日の曜日を取得 */ 61 int dow = day_of_week_of_first_day(year, month); 62 63 /* 表示 */ 64 printf(" 日 月 火 水 木 金 土 \n"); 65 printf(" -------------------- \n"); 66 for(int i=0; i<dow; i++) printf(" "); 67 for(int d=1, n=number_of_days(year, month); d<=n; d++, dow=(dow+1)%7) { 68 if(d != 1 && dow == 0) printf("\n"); 69 printf(" %2d", d); 70 } 71 printf("\n"); 72}
西暦:2000 月:2 日 月 火 水 木 金 土 -------------------- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

投稿2023/05/14 13:21

編集2023/05/15 05:30
jimbe

総合スコア12545

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

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

0

C言語 通算日の算出、でぐぐればコードが出てきます。
それらの解説を見て、組んでみよう

投稿2023/05/14 08:00

y_waiwai

総合スコア87719

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問