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

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

ただいまの
回答率

88.23%

C言語 カレンダー コンソールに表示した(3か月ずつなど

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 839

kokok

score 109

#pragma warning(disable: 4996)
#include<stdio.h>

#define ROW_SIZE 6  //カレンダーの行のサイズ
#define SPRING_EQ 0
#define FALL_EQ 1
#define BIRTH_MARK 0x80// 誕生日マーク 
#define TRANS_MARK 0x40// 振替祝日マーク 
#define HOLI_MARK 0x20// 祝日マーク 
#define MAX_HOLI_TBL 4 //祝日テーブルの最大


enum  M_LIST { JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOW, DEC, N_MONTH };
enum W_LIST { SUN, MON, TUE, WED, THU, FRI, SAT, N_WEEK };
int  monthdays[] = { 31,28,31,30,31,30,31,31,30,31,30,31 }; //月の日数
char* weeks[] = { "日","月","火","水","木","金","土" };
//****************************************************
//
// 祝日のデータテーブル
//

char holidays[N_MONTH][MAX_HOLI_TBL] = {
        {1,-2,0,0},        //  1月、元旦、成人の日
        {11,23,0,0},        //  2月、建国記念日、令和天皇誕生日
        {21,0,0,0},        //  3月、春分の日(計算で求める)
        {29,0,0,0},        //  4月、昭和の日
        {3,4,5,0},        //  5月、憲法記念日、みどりの日、子供の日
        { 0,0,0,0},        //  6月、なし
        {-3,0,0,0},        //  7月、海の日
        {11,0,0,0},        //  8月、山の日
        {-3,23,0,0},        //  9月、敬老の日、秋分の日(計算で求める)
        {-2,0,0,0},        // 10月、体育の日
        {3,23,0,0},        // 11月、文化の日、勤労感謝の日
        { 0,0,0,0}        // 12月、なし
};

//プロトタイプの宣言
int januaryoneday(int year);
int leapyear(int year);
int calendarmake(char  calendar[N_MONTH][ROW_SIZE][N_WEEK], int week, int year, int  birthmon, int birthday);
void  calendarprint(char  calendar[N_MONTH][ROW_SIZE][N_WEEK], int year, int display);
void spraut(int yy);


int main(void) {


    char  calendar[N_MONTH][ROW_SIZE][N_WEEK] = { 0 };    // カレンダーの多次元配列

    int year;   //入力された西暦
    //int month; //入力された月
    //int day; //入力された日
    int week;  // //入力された西暦の1月1日の曜日
    int  judgment; //入力された値がうるう年だったかどうか
    int sumday; //    入力された西暦までの日数の合計
//    int birthw; //入力された誕生日の曜日
    int monthdaysum = 0; // 入力された誕生日の月までの合計の日数
    int birthmon;  //入力された誕生月
    int birthday; //入力された誕生日
    int display; //入力された表示方法

    printf("西暦を入力してください");
    scanf("%d", &year);

    printf("誕生日を入力してください");
    scanf("%d %d", &birthmon, &birthday);

    printf("カレンダーの表示3行か4行か");
    scanf("%d", &display);

    week = januaryoneday(year);    //入力された西暦の1月1日の曜日を取得

    //printf("%s\n", weeks[week]);    //入力された西暦の1月1日の曜日を表示

    judgment = leapyear(year);       //うるう年の判定結果を取得


    monthdays[FEB] = (judgment == 0) ? 29 : 28;      // うるう年であれば2月を29日に変更



    sumday = ((year - 1) * 365) + ((year - 1) / 4) - ((year - 1) / 100) + ((year - 1) / 400);   //入力された西暦までの日数の合計

    /*for (int i = JAN; i < month - 1; i++) {  //入力された誕生日の月までの合計の日数

        monthdaysum += monthdays[i];

    }

    birthw = (sumday + monthdaysum + day) % 7;  //    入力された誕生日までの合計の日数 の曜日を取得

    printf("%s", weeks[birthw]);   //入力された誕生日の曜日を表示

    */
    week = calendarmake(calendar, week, year, birthmon, birthday);

    //printf("%s\n", weeks[week]);


    spraut(year);    //春分の日と秋分の日を設定

    calendarprint(calendar, year, display);  //カレンダーの表示

}


//入力された西暦の1月1日の曜日を返す
int januaryoneday(int year) {

    int sumday; // 入力された西暦までの累計日数
    int dayw; // 曜日計算

    sumday = ((year - 1) * 365) + ((year - 1) / 4) - ((year - 1) / 100) + ((year - 1) / 400); //入力された1月1日までの日数

    dayw = (sumday + 1) % 7;

    return dayw;
}


//入力された西暦がうるう年かの判定
int leapyear(int year) {

    int leap;

    leap = (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) ? 0 : -1;   //うるう年なら0を 違うなら-1 を

    return leap;
}


//カレンダーを作る
int calendarmake(char  calendar[N_MONTH][ROW_SIZE][N_WEEK], int week, int year, int  birthmon, int birthday) {

    int month; // 1月から12月
    int row; //カレンダーの行
    int day;//月の日にち
    int monday_cnt;
    int holiday_cnt;


    for (month = JAN; month <= DEC; month++) {

        row = 0; //月ごとに初期化
        day = 1; //月ごとに初期化
        monday_cnt = 0;// 月曜日カウント
        holiday_cnt = 0; // 祝日カウント


        while (day <= monthdays[month])
        {

            calendar[month][row][week] |= day;    //現在の日付のビットを立てる


            if (week == MON) {
                monday_cnt++;  //月曜日なら1増やす
            }


            if (holidays[month][holiday_cnt] == day) {   //固定祝日だったら

                calendar[month][row][week] |= HOLI_MARK;       //固定祝日のビットを立てる
                holiday_cnt++;

                if ((week == SUN) || (calendar[month][row][week] & TRANS_MARK)) { //固定祝日が日曜日またはすでに振替休日の場合

                    calendar[month][row][week + 1] |= TRANS_MARK;
                }
            }

            if ((holidays[month][holiday_cnt] < 0) && (holidays[month][holiday_cnt] * -1) == monday_cnt) {

                calendar[month][row][week] |= HOLI_MARK;       //固定でない祝日のビットを立てる

                holiday_cnt++;
            }

            if (week > TUE) {

                if (calendar[month][row][week] & HOLI_MARK && calendar[month][row][week - 2] & HOLI_MARK) {

                    calendar[month][row][week - 1] |= HOLI_MARK;
                }
            }


            if (month == birthmon - 1 && day == birthday) {   //引数で渡された誕生日だったら誕生日のマーク入れる

                calendar[month][row][week] |= BIRTH_MARK;
            }

            week++;
            day++;

            if (week > SAT) {

                week = SUN;
                row++;
            }
        }
    }
    return  week;   //最後の曜日を返す
}


//カレンダーを表示する
void  calendarprint(char  calendar[N_MONTH][ROW_SIZE][N_WEEK], int year, int display) {

    int month; //月のループ
    int row; //週のループ
    int col;//曜日のループ


    printf("%5d年\n", year);   // 入力された年を表示

    for (month = JAN; month <= DEC; month++) {


        printf("             %2d月\n", month + 1);
        printf("\n");

        for (int i = 0; i <= SAT; i++) {

            printf(" %2s  ", weeks[i]);     //曜日の表示
        }

        printf("\n");

        for (row = 0; row < ROW_SIZE; row++) {

            for (col = 0; col <= SAT; col++) {

                if (calendar[month][row][col] != 0)   //日数が0でなければ
                {

                    if (calendar[month][row][col] & HOLI_MARK) {
                        printf("*");
                    }
                    else if (calendar[month][row][col] & TRANS_MARK) {
                        printf("+");
                    }
                    else if (calendar[month][row][col] & BIRTH_MARK) {
                        printf("&");

                    }
                    else {

                        printf(" ");
                    }

                    printf("%2d  ", calendar[month][row][col] & 0x1F);
                }

                else {                                               //日数が0なら
                    printf("     ");
                }
            }
            printf("\n");
        }
        printf("\n");
    }
}

//春分と秋分の日を求める

void spraut(int year) {

    int yy;
    int springEQ;    // 求める春分の日
    int fallEQ;        // 求める秋分の日
    yy = year;

    if (yy <= 1899) {
        springEQ = (int)(19.8277 + 0.242194 * (yy - 1980) - ((yy - 1983) / 4));
        fallEQ = (int)(22.2588 + 0.242194 * (yy - 1980) - ((yy - 1983) / 4));
    }
    else if (yy >= 1900 && yy <= 1979) {
        springEQ = (int)(20.8357 + 0.242194 * (yy - 1980) - ((yy - 1983) / 4));
        fallEQ = (int)(23.2588 + 0.242194 * (yy - 1980) - ((yy - 1983) / 4));
    }
    else if (yy >= 1980 && yy <= 2099) {
        springEQ = (int)(20.8431 + 0.242194 * (yy - 1980) - ((yy - 1980) / 4));
        fallEQ = (int)(23.2488 + 0.242194 * (yy - 1980) - ((yy - 1980) / 4));
    }
    else if (yy >= 2100) {
        springEQ = (int)(21.851 + 0.242194 * (yy - 1980) - ((yy - 1980) / 4));
        fallEQ = (int)(24.2488 + 0.242194 * (yy - 1980) - ((yy - 1980) / 4));
    }
    holidays[MAR][SPRING_EQ] = springEQ;    // 春分の日を入れる
    holidays[SEP][FALL_EQ] = fallEQ;        // 秋分の日を入れる
}

コンソールにカレンダーを縦 一列に表示することは出来たので、横にも表示させたいと思ったのですが、どうすればいいのか思いつきませんでした。

1   2  3
4   5  6
7   8  9
10 11 12

このように表示したりしたいのですが、アドバイス頂けると幸いです。

-----追記-------

//カレンダーを表示する
void  calendarprint(char  calendar[N_MONTH][ROW_SIZE][N_WEEK], int year, int display) {

    int month; //月のループ
    int row; //週のループ
    int col;//曜日のループ


    printf("%5d年\n", year);   // 入力された年を表示

    for (month = JAN; month <= DEC; month+=display) {
        for (int m = month, dis = 0; m < N_MONTH && dis < display; m++, dis++) {

            printf("              %2d月                     ", m + 1);
        }
        printf("\n\n");
        for (int m = month, dis = 0; m < N_MONTH && dis < display; m++, dis++) {
            for (int i = 0; i <= SAT; i++) {

                printf(" %2s  ", weeks[i]);     //曜日の表示
                if (i == SAT) {
                    printf("    ");
                }
            }
        }
        printf("\n");

        for (row = 0; row < ROW_SIZE; row++) {
            printf("\n");
            for(int m = month, dis = 0; m < N_MONTH && dis < display; m++, dis++){

                for (col = 0; col <= SAT; col++) {

                    if (calendar[month][row][col] != 0)   //日数が0でなければ
                    {

                        if (calendar[month][row][col] & HOLI_MARK) {
                            printf("*");
                        }
                        else if (calendar[month][row][col] & TRANS_MARK) {
                            printf("+");
                        }
                        else if (calendar[month][row][col] & BIRTH_MARK) {
                            printf("&");
                        }
                        else {

                            printf(" ");
                        }
                        printf("%2d  ", calendar[month][row][col] & 0x1F);
                    }
                    else {                                               //日数が0なら
                        printf("     ");
                    }
                    if (col == SAT) {

                        printf("    ");
                    }
                }
            }
            printf("\n");
        }
        printf("\n");
    }
}

カレンダーを表示の部分を回答を参考に自分なりに書いてみました。

しかし、表示の仕方を

1   2   7    8
3   4   9   10
5   6  11   12

上記ののように表示をしたいのですが、なかなかうまくいきません。

追加でアドバイス頂けると幸いです。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+1

縦に並べたカレンダーを印刷して, 縦横に並べたイメージを切り貼りで実際に作っては如何でしょう.
そして, 上から一行ずつに定規等を当てていけば, いつどの表示をすれば良いのかが見えてくると思います.

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

0

display を、月を横にいくつ表示するかという意味に解釈しました。
最初に、12の約数だけ有効なコードを示しましたが、
5 や 7 などでもよいようにしてみました。

//カレンダーを表示する
void calendarprint(char  calendar[N_MONTH][ROW_SIZE][N_WEEK],
        int year, int display)
{
    printf("%5d年\n", year);   // 入力された年を表示
    for (int month = JAN; month < N_MONTH; month += display) {
        for (int m = month, k = 0; m < N_MONTH && k < display; k++, m++)
            printf("%16d月                   ", m + 1);
        printf("\n\n");

        for (int m = month, k = 0; m < N_MONTH && k < display; k++, m++) {
            if (k) printf("  ");
            for (int i = 0; i <= SAT; i++)
                printf(" %2s  ", weeks[i]);     //曜日の表示
        }
        printf("\n");

        for (int row = 0; row < ROW_SIZE; row++) {
            for (int m = month, k = 0; m < N_MONTH && k < display; k++, m++) {
                if (k) printf("  ");
                for (int col = SUN; col <= SAT; col++) {
                    if (calendar[m][row][col] != 0) { // 日数が0でないなら
                        if (calendar[m][row][col] & HOLI_MARK)
                            printf("*");
                        else if (calendar[m][row][col] & TRANS_MARK)
                            printf("+");
                        else if (calendar[m][row][col] & BIRTH_MARK)
                            printf("&");
                        else
                            printf(" ");
                        printf("%2d  ", calendar[m][row][col] & 0x1F);
                    }
                    else  // 日数が0なら
                        printf("     ");
                }
            }
            printf("\n");
        }
        printf("\n");
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/08/05 09:25

    ありがとうございます。
    if (k) printf(" "); ここは何をやっているのでしょうか?

    キャンセル

  • 2019/08/05 10:34

    すみません。コメントを書いたつもりが回答に入ってしまったようです。

    キャンセル

  • 2019/08/05 10:44

    いえいえ。
    ありがとうございます。

    キャンセル

0

3ヶ月分を横に並べられるだけの1行ぶんのバッファを用意しといて、
3ヶ月のカレンダ文字列を生成、その1行づつを位置あわせのスペースを挟みながら横に3つ並べて出力する、ということですね。
位置合わせがちょっと難しいですが、まあ、がんばってください

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

if文は「if (式) 文」という構文で、式の値が 0 でなければ文を実行します。
if (k != 0) printf(" "); と同じです。
if (k > 0) printf(" "); と書いても構いません。
2番目以降の月を書くとき、左の月との間にスペースを置くということです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/08/05 10:33

    理解できました。
    ありがとうございます。

    キャンセル

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

  • ただいまの回答率 88.23%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る