カレンダー

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
とーます

カレンダー

#1

投稿記事 by とーます » 7年前

C言語においての知識は皆無にも関わらず授業でC言語の課題が出てしまい困っています。
/*各自この部分を作る*/の部分は所々作成してみたのですが
Date InputDate以下はどこにどういったものを入れるのかも分からず、
進むことができなくなってしまいました。
ぜひお力をお借りしたいです。

コード:

#include <stdio.h>
#include <stdlib.h>
#define GREGORIAN 1582
#define MENU         4
#define MONTH       12
#define WEEK         7
#define TRUE         1
#define FALSE        0

typedef struct {
  int year;
  int month;
  int day;
  int days;
  int leap;
} Date;

char *wday[] = {
  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};

int mday[2][13] = {
  {  0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  {  0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

void PrintMenu(void);
Date InputDate(int);
void PrintDate(Date);
int CountDays(Date);
int IsLeap(int);
Date CalcDate(int);
void BeforeAfter(void);
void Calendar(Date);
void Difference(void);
void PrintDates(Date, Date, int);

int main()
{
  Date date1, date2;
  int n;

  PrintMenu();

  do {
    printf("\nEnter (0-%d) : ", MENU);
    scanf("%d", &n);
    switch (n) {
    case 0:
      break;
    case 1: printf("\n");
      date1 = InputDate(TRUE);
      PrintDate(date1);
      printf("\n");
      break;
    case 2:
      Difference();
      break;
    case 3:
      date1 = InputDate(FALSE);
      Calendar(date1);
      break;
    case 4:
      BeforeAfter();
      break;
    case 5:
      PrintMenu();
      break;
    default:
      fprintf(stderr, "\nInvalid number : %d\n", n);
      fprintf(stderr, "Menus are as follow\n");
      PrintMenu();
      exit(1);
    }
  }while (n > 0);

  return 0;
}


void PrintDate(Date date)
{
  printf("%4d/%02d/%02d (%s)",
         date.year, date.month, date.day, wday[date.days%WEEK]);
}

void BeforeAfter(void)
{
  Date base, date;
  int n;

  base =InputDate(TRUE);
  printf("Enter (n) : ");
  scanf("%d", &n);

  date = CalcDate(base.days+n);
  PrintDates(date, base, n);
}

void Difference(void)
{
  Date dateA, dateB;
  int days;

  printf("\n --- dateA ---\n");
  dateA = InputDate(TRUE);
  printf("\n --- dateB ---\n");
  dateB = InputDate(TRUE);

  days = dateA.days - dateB.days;
  PrintDates(dateA, dateB, days);
}

void PrintDates(Date date1, Date date2, int days)
{
  PrintDate(date1);
/*days の正負により出力を BEFORE, AFTERと切り変える*/
if(days <= 10){
 printf("is 10 days AFTER ");

}
 else 
printf("is 10 days BEFORE ");
  PrintDate(date2);
  printf("\n");
}

void PrintMenu(void)
{
  printf("\t0: Quit\n");
 /* 各自この部分を作る */
  printf("\t1: Pront Date\n");
  printf("\t2: difference between 'dateA' and 'dateB'\n");
  printf("\t3: Calendar\n");
  printf("\t4: 'n' days before(after) 'date'\n");
  printf("\t5: print Menu\n");

}

Date InputDate(int flag)
{
  Date date;
/* 各自この部分を作る */  

   printf("Enter (year >= %d)  : ", GREGORIAN);
    scanf("%4d", &date.year);
   printf("Enter (month:1---12)  : ");
    scanf("%2d", &date.month); 
   printf("Enter (day:1---31)    : ");
    scanf("%2d", &date.day);

  if(flar==TRUE){
     printf("Enter (day:1---31)    : ");
     scanf("%2d", &date.day);
  }

 else 

  return date;
}

int CountDays(Date date)
{
  int days, y, j;
/* 各自この部分を作る …西暦Y年m月d日がdays日目とする*/
   
  
 return days;
}

int IsLeap(int y)
{
/* 各自この部分を作る …うるう年*/
 
   if (y % 400 == 0) return 1;
   else if (y % 100 == 0) return 0;
   else if (y % 4 == 0) return 1;
   else return 0;
 
}

void Calendar(Date date)
{
 int j, k,week,uru,y,dday,day;
 char *mname[] = {"", "Jan", "Feb", "Mar", "Apr", "May", "Jun","Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

/* 「月」の名前と「西暦」を出力する */

/*for 文を用いて4桁幅で wday[0]~wday[WEEK-1] を出力する*/
k = date.days%WEEK;

/*1 データ四文字分なので、「4つの空白」で一データkデータ分「4つの空白」を出力する。
つまり for 文で j=0, 1, 2, …, k-1 に対して「4 つの空白」を出力*/

/*1~mday[date.leap][date.month] までを for 文を使って 4 桁幅で出力kをデータ位置情報として使う。
・数字を出力する度に k の値を 1 増加させる
・k の値が KEEK と等しくなったら
「k の値を 0 に戻す」「改行する」という動作をする。*/

/*mday[date.leap][date.month] の値を出力したデータ位置によっては改行*/

 
}
 
Date CalcDate(int days)
{
 Date date;
/* 各自この部分を作る …days 日目から西暦y年m月d日を出力する。*/


  return date;
}

かずま

Re: カレンダー

#2

投稿記事 by かずま » 7年前

CountDays と CalcDate を書いてみました。

コード:

#include <stdio.h>
 
typedef struct { int year, month, day, days, leap; } Date;
 
int CountDays(Date date)
{
    static int t[] = { 306,337,0,31,61,92,122,153,184,214,245,275 };
    int y = date.year;
    if (date.month < 3) y--;
    return 365*y + y/4 - y/100 + y/400 + t[date.month-1] + date.day + 2;
}
 
int IsLeap(int y) { return y%4 == 0 && (y%100 != 0 || y%400 == 0); }

Date CalcDate(int days)
{
    static int t[] = { 0,31,61,92,122,153,184,214,245,275,306,337,366 };
    int y, m, d, leap = 0;
    Date date;

    date.days = days;
    days -= 3;

    y = days / (365 * 400 + 97) * 400;
    days %= 365 * 400 + 97;

    d = days / (365 * 100 + 24);
    if (d == 4) d--, days--, leap = 1;
    y += d * 100;
    days %= 365 * 100 + 24;

    y += days / (365 * 4 + 1) * 4;
    days %= 365 * 4 + 1;

    d = days / 365;
    if (d == 4) d--, days--, leap = 1;
    y += d;
    days %= 365;

    date.year = y;
    date.leap = IsLeap(y);
    for (m = 1; m < 12 && days > t[m]; m++) ;
    date.month = (m > 10) ? (date.year++, m - 10) : (m + 2);
    date.day = days - t[m-1] + leap + 1;

    return date;
}

void PrintDates(Date date1, Date date2, int days)
{
    PrintDate(date1);
    if (days > 0)
        printf(" is %d days AFTER ", days);
    else if (days < 0)
        printf(" is %d days BEFORE ", -days);
    else
        printf(" is just the same as ");
    PrintDate(date2);
    printf("\n");
}

かずま

Re: カレンダー

#3

投稿記事 by かずま » 7年前

CalcDate の最後の部分、date.leap の値が間違っています。
次のように訂正します。

コード:

    for (m = 1; m < 12 && days > t[m]; m++) ;
    date.month = (m > 10) ? (y++, m - 10) : (m + 2);
    date.day = days - t[m-1] + leap + 1;
    date.year = y;
    date.leap = IsLeap(y);

かずま

Re: カレンダー

#4

投稿記事 by かずま » 7年前

Calendar は、コメントに書かれていることをそのまま書くだけですね。

コード:

void Calendar(Date date)
{
    int j, k, day;
    static const char *mname[] = { "",
        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    };
 
    printf("%13s  %d\n", mname[date.month], date.year); // 月名と年を表示
    for (j = 0; j < 7; j++) printf("%4s", wday[j]);     // 曜日を表示
    putchar('\n');
    k = date.days % 7;                        // year年 month月 1日の曜日
    for (j = 0; j < k; j++) printf("    ");   // 1日の直前の空白を表示
    day = mday[date.leap][date.month];        // day は、その月の最終日
    for (j = 1; j <= day; j++) {              // 1~day を
        printf("%4d", j);                     //          表示
        if (++k == 7) k = 0, putchar('\n');   // 7個表示で改行
    }
    if (k) putchar('\n');                     // 行頭でなければ改行
}
配列の初期化は毎回実行すべきではなく、static にしたほうが良いでしょう。

かずま

Re: カレンダー

#5

投稿記事 by かずま » 7年前

InputDate がちゃんとできていないので、このままでは
今まで書いたコードが正しいかどうか確認できません。

コード:

Date InputDate(int flag)
{
    Date date;

    printf("Enter (year >= %d)  : ", GREGORIAN);
    if (scanf("%d", &date.year) != 1) exit(1);
    printf("Enter (month:1---12)  : ");
    if (scanf("%d", &date.month) != 1) exit(1);
    printf("Enter (day:1---31)    : ");
    if (scanf("%d", &date.day) != 1) exit(1);
	date.days = CountDays(date);
	date.leap = IsLeap(date.year);
	return date;
}
引数 flag の意味が分かりません。これは何ですか?
エラーチェックが甘いです。13月32日が入力できてしまいます。

かずま

Re: カレンダー

#6

投稿記事 by かずま » 7年前

CalcDate にバグがあり、2/1 が 1/32 となっていました。
 for (m = 1; m < 12 && days > t[m]; m++) ;を
 for (m = 1; t[m] <= days; m++) ; に修正します。

InputDate の flag の意味が分かりました。
Calendar を呼び出す前だけ、FALSE なのは、day の
入力をさせずに 1 にするためだろうと考えられます。

コード:

Date InputDate(int flag)
{
    Date date;
    printf("Enter (year >= %d)  : ", GREGORIAN);
    if (scanf("%4d", &date.year) != 1 || date.year < GREGORIAN)
        exit(1);
    date.leap = IsLeap(date.year);
    printf("Enter (month:1---12)  : ");
    if (scanf("%2d", &date.month) != 1 || date.month < 1 || date.month > 12)
        exit(1);
    date.day = 1;
    if (flag) {
        printf("Enter (day:1---31)    : ");
        if (scanf("%2d", &date.day) != 1 ||
                date.day < 1 || date.day > mday[date.leap][date.month])
            exit(1);
    }
    date.days = CountDays(date);
    return date;
}

とーます

Re: カレンダー

#7

投稿記事 by とーます » 7年前

非常に丁寧に教えていただきありがとうございました(><)
おかげさまで無事解決することができました!
ありがとうございます。

とーます

Re: カレンダー

#8

投稿記事 by とーます » 7年前

解決しました。

かずま

Re: カレンダー

#9

投稿記事 by かずま » 7年前

とーます さんが書きました:非常に丁寧に教えていただきありがとうございました(><)
丁寧には教えていません。
CountDays や CalcDate の説明を何もしていません。
とーます さんが書きました: おかげさまで無事解決することができました!
無事解決したのなら、コードを理解したあなたが
CountDays や CalcDaate の説明をしてみてください。
理解できていないのなら、質問するべきでしょう。

まだまだ改善の余地があります。InputDate でも、
小の月で 31 を入力させないようにしたほうがよいでしょう。

コード:

    if (flag) {
        int day = mday[date.leap][date.month];
        printf("Enter (day:1---%d)    : ", day);
        if (scanf("%2d", &date.day) != 1 || date.day < 1 || date.day > day);
            exit(1);
    }
入力ミスで終了するもの考え直したほうがいいと思います。

かずま

Re: カレンダー

#10

投稿記事 by かずま » 7年前

[quote="かずま" id=3,19936,149684]

コード:

        if (scanf("%2d", &date.day) != 1 || date.day < 1 || date.day > day);
最後の ; を削除してください。

返信

“C言語何でも質問掲示板” へ戻る