No.16178![]() |
配列の特定の要素のみを変更可にする 投稿者---RiSK(2004/08/14 23:39:18) |
||
配列の特定の要素のみを変更可能にする方法はあるでしょうか? それ以外の要素は const のようにしたいです。 以下は入力された日付の妥当性を確認するプログラムです。 #include <stdio.h> #define IS_YEAR_VALID(year) (((year) >= 1) && ((year) <= 9999)) #define IS_MONTH_VALID(month) (((month) >= 1) && ((month) <= 12)) #define IS_LEAP_YEAR(year) ((((year) % 4) == 0) && (((year) % 100) != 0) || (((year) % 400) == 0)) typedef struct { int year; int month; int day; } MY_DATE; int IsDateValid(MY_DATE *date) { /* const */ int days_a_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; if (!IS_YEAR_VALID(date->year)) { return 0; } if (!IS_MONTH_VALID(date->month)) { return 0; } /* * 日を確認 */ // 閏年確認 if (date->month == 2 && IS_LEAP_YEAR(date->year)) { days_a_month[2-1] = 29; } if ((date->day < 1) || (date->day > days_a_month[date->month-1])) { return 0; } return 1; } int main(void) { MY_DATE date; scanf("%d %d %d", &date.year, &date.month, &date.day); if (IsDateValid(&date)) { puts("有効な日付"); } else { puts("無効な日付"); } return 0; }days_a_month は基本的に変更しないので const にしたいところですが、 閏年という例外があるので const にできません。 でも days_a_month[1] 以外の要素は変更する予定はありませんし、 うっかり変更してしまうミスも避けたいです。 もしあるならば ・コンパイラでうまく確認する方法 ・それ以外で目的を達成する方法 を知りたいです。 どんなことでも構いません。よろしくお願いします。 |
No.16180![]() |
Re:配列の特定の要素のみを変更可にする 投稿者---かずま(2004/08/15 01:27:42) |
||
> 配列の特定の要素のみを変更可能にする方法はあるでしょうか? > それ以外の要素は const のようにしたいです。 キャストを使えばできます。 *(int *)&days_a_month[2-1] = 29; > どんなことでも構いません。よろしくお願いします。 const にしようがしまいが、days_a_month は自動変数ですから、 関数 IsDateValid が呼び出されるたびに、毎回毎回、12個の int の 初期化が実行されます。値の変化しない配列を利用したいのなら、 const よりも static を用いるべきです。 私なら次のようなコーディングをします。 int IsDateValid(const MY_DATE *date) { static const int days_a_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int last_day_of_a_month; if (!IS_YEAR_VALID(date->year)) return 0; if (!IS_MONTH_VALID(date->month)) return 0; if (date->month == 2 && IS_LEAP_YEAR(date->year)) last_day_of_a_month = 29; else last_day_of_a_month = days_a_month[date->month - 1]; if (date->day < 1 || date->day > last_day_of_a_month) return 0; return 1; } 変数の書き換えを心配するのなら、引数の書き換えも心配すべきでしょう。 const MY_DATE *date のことです。 |
No.16182![]() |
Re:配列の特定の要素のみを変更可にする 投稿者---RiSK(2004/08/15 16:36:28) |
||
かずまさん、レスありがとうございます。 > *(int *)&days_a_month[2-1] = 29; あーなるほど、 const 外しですね。 ちょっと気持ち悪いので、今回は採用を見送りました。 こういう方法もあると覚えておきたいと思います。 > 私なら次のようなコーディングをします。 とても参考になりました。 別の変数を用意すれば問題ないわけですね。 # うぅ、頭かたいなぁ>私 今回はこの方法を用いました。解決です。 > 変数の書き換えを心配するのなら、引数の書き換えも心配すべきでしょう。 > const MY_DATE *date のことです。 仰るとおりです。訂正しました。 # 同一掲示板上で二回目の指摘を受けてしまった。 # 猛省します。 問題解決+αの知識をありがとうございました。 |
No.16183![]() |
Re:配列の特定の要素のみを変更可にする 投稿者---かずま(2004/08/15 22:16:52) |
||
> 問題解決+αの知識をありがとうございました。 では、問題点をもう少し。 100で割り切れて 400で割り切れない年が平年というのはグレゴリオ暦で、 その暦が採用されたのはイタリアで 1582年ですから、それ以前の年について IS_LEAP_YEAR を適用するのは無意味です。すなわち、IS_YEAR_VALID の year >= 1 は変です。 |
No.16184![]() |
Re:配列の特定の要素のみを変更可にする 投稿者---RiSK(2004/08/15 23:02:13) |
||
>では、問題点をもう少し。 問題点の指摘に感謝します。 >100で割り切れて 400で割り切れない年が平年というのはグレゴリオ暦で、 >その暦が採用されたのはイタリアで 1582年ですから、それ以前の年について >IS_LEAP_YEAR を適用するのは無意味です。 なるほど。私も調べてみました。 →グレゴリオ暦 - Wikipedia >すなわち、IS_YEAR_VALID の year >= 1 は変です。 えーっと、要点ではないと思い書かなかったのですが この問題には元ネタがあり、それは ここの過去ログ29 です。 > Y:西暦(0001-9999) という指示だったので year >= 1 としていました。 「紀元前を含めないのはなぜか」と無知なりに考えていましたが、 私の思考はそこでストップしていました。 かずまさんがハッキリとした根拠を示してくださったので、 問題が悪かったことにし、 year >= 1582 とします。 # …でも、西暦が 9999 年までというのも変だよなぁ。 |
No.16186![]() |
Re:配列の特定の要素のみを変更可にする 投稿者---シャノン(2004/08/16 11:15:39) |
||
#どうでもいいことなのかもしれませんが >その暦が採用されたのはイタリアで 1582年ですから そこまでこだわるのでしたら、月日もこだわるべきでは? 1582.01.01 に導入されたのではありませんし。 Wikipedia によれば、イタリアでは 1582.10.15 ですか。 ならば 1582.10.14 以前は無効な日付とすべきでは? 参考までに。 MFC の MonthCalendarCtrl で選択できる最古の日付は 1752.09.14。 1752.09.19 の次は 1752.10.01 でした。 C# の MonthCalendarCtrl では 1753.01.01 が最古でした。 MFC はイギリス歴、C# も基本的にはイギリス歴ですが、半端な 1752 年を含まない措置が取られているようですね。 |