ページ 11

万年カレンダー

Posted: 2007年7月19日(木) 21:50
by 雪中 蓮
こんばんは。今学校の課題で、万年カレンダーのプログラムを作成しているのですが、プログラムの組み方が悪いのか上手くいきません。それ以前にコンパイルエラーになるのですが・・・。

長いですが、全文はっておきますのでご指摘、助言をお願いします。
#include <stdio.h>


/******************************************/
void ym_input(int *year, int *month);

int get_day_of_week(char *date);

void cal_disp(int year,int month, int dayofweek);


/******************************************/
char *dp,date[8] = {0,0,0,0,0,0,0,0};
int *yp, *mp;
int year,month,day,dayofweek;


/******************************************/
int main(void)
{
	yp = date[0];
	mp = date[4];
	ym_input(yp,mp);

	date[6] = '0';
	date[7] = '1';
	dp = date[0];
	dayofweek = get_day_of_week(dp);

	cal_disp(year,month,dayofweek);

	return 0;
}


/******************************************/
void ym_input(int *year, int *month)
{
	printf("表示させたいカレンダーの年を西暦で入力してください\nただし入力可能範囲は1583~3999年とする ->");
	while('15830000'>=date || '39990000'<=date){
		scanf("%d",&year);
		if('15830000'>=date || '39990000'<=date)	printf("Error:入力値が正しくありません\n");
	}
	printf("表示させたいカレンダーの月を入力してください ->");
	while('0100'>=*month || '1200'<=*month){
		scanf("%d",&month);
		if('0100'>=*month || '1200'<=*month)	printf("Error:入力値が正しくありません\n");
	}
}


/******************************************/
int get_day_of_week(char *date)
{
	int i,d[8],a;
	int *j;

	j = d[0];
	for(i=0;i<8;i++)
	{
		*(j + i) = *(date + i) - 48;
	}

	year = d[0] * 1000 + d[1] * 100 + d[2] * 10 + d[3];
	month = d[4] * 10 + d[5];
	day = d[6] * 10 + d[7];

	a=(year+(year/4)-(year/100)+(year/400) + ((13 * month)+8)/5)+day)%7 ;
	return a;
}


/******************************************/
void cal_disp(int year,int month, int dayofweek)
{
	int i,j,a,max,flag,cal[6][7]={
		{" "," "," "," "," "," "," "},
		{" "," "," "," "," "," "," "},
		{" "," "," "," "," "," "," "},
		{" "," "," "," "," "," "," "},
		{" "," "," "," "," "," "," "},
		{" "," "," "," "," "," "," "}
	};

	switch(month){
		case 2 : {
			if((year%4==0&&!(year%100==0))||year%400==0)
				max=29;
			else
				max=28;
			break;
				 }
		case 4 :
		case 6 :
		case 9 :
		case 11 : {
			max=30;
			break;
				  }
		default : {
			max=31;
			break;
				  }
	}

	a=0;
	flag=0;
	for(i=0;i<6||flag==1;i++){
		for(j=0;j<7||flag==1;j++){
			if(i=0)	j=dayofweek;
			cal[j]=a++;
			if(a==max) flag=1;
		}
	}
	printf("%.4d年 %.2d月\n",year,month);
	printf("日 月 火 水 木 金 土\n");

	for(i=0;i<6||flag==1;i++){
		for(j=0;j<7||flag==1;j++){
			if(cal[j]=" ")
				printf(" ");
			else
				printf("%.2d",cal[j]);
			printf(" ");
		}
		printf("\n");
	}

}
 
 

Re:万年カレンダー

Posted: 2007年7月19日(木) 22:07
by box
コンパイル時のエラーメッセージの意味はおわかりになりますか?
おわかりになるところは、ご自分で修正してみてください。

Re:万年カレンダー

Posted: 2007年7月19日(木) 22:40
by 雪中 蓮
エラーの部分なんですが、

printf("表示させたいカレンダーの年を西暦で入力してください\nただし入力可能範囲は1583~3999年とする ->");
while('15830000'>=date || '39990000'<=date){
scanf("%d",&year);
if('15830000'>=date || '39990000'<=date) printf("Error:入力値が正しくありません\n");
}

この行の比較でエラーが出ているようなんですが、どう対処すればいいかがわかりません。

Re:万年カレンダー

Posted: 2007年7月19日(木) 23:11
by box
そこよりも前に、main()で警告が出ていませんか?

>	yp = date[0];
>	mp = date[4];

date[0]やdate[4]というchar型のデータ(中身は0、つまり'\0')を
int *型に代入する意味がわからないです。

Re:万年カレンダー

Posted: 2007年7月19日(木) 23:23
by tk-xleader
文字列比較に、比較演算子は使えませんよ。
string.hをインクルードして、strcmp()で文
字比較を、strlen()で文字数を数えてくださ
い。これがCの厄介なとこなんですよ。

Re:万年カレンダー

Posted: 2007年7月19日(木) 23:26
by 雪中 蓮
ypにはdateの先頭アドレスを入れようとしているのですが・・・

>char *dp,date[8] = {'0','0','0','0','0','0','0','0'};

> yp = date;
> mp = yp + 4;

・・・このようにすればよいのでしょうか?

Re:万年カレンダー

Posted: 2007年7月19日(木) 23:28
by たかぎ
> printf("表示させたいカレンダーの年を西暦で入力してください\nただし入力可能範囲は1583~3999年とする ->");
> while('15830000'>=date || '39990000'<=date){
> scanf("%d",&year);
> if('15830000'>=date || '39990000'<=date) printf("Error:入力値が正しくありません\n");
> }
>
> この行の比較でエラーが出ているようなんですが、どう対処すればいいかがわかりません。

2文字以上を含む文字定数の値は処理系定義ですが、エラーにはならないはずです。
実際に試してみましたが、上の箇所では、警告は出ますがエラーにはなりませんでした。
なお、一重引用符で囲まれた文字の並びは、「文字列定数」ではなく「文字定数」になります。
「文字定数」の比較は関係演算子を使うべきで、strcmpは役に立ちません。

もっとも、そんなこと以前に根本的に間違っていると思います。

ちなみに、最初のエラーは、

> a=(year+(year/4)-(year/100)+(year/400) + ((13 * month)+8)/5)+day)%7 ;

の部分で、括弧がバランスしていないことによるものです。

ところで、西暦3999年まで扱う場合には、
http://www.water.sannet.ne.jp/kazuya-ai/14/weak-5.html
にあるように、閏年の計算が上記では通用しなくなる可能性が大です。

Re:万年カレンダー

Posted: 2007年7月19日(木) 23:45
by box
int型の年とint型の月を与えて、その年・月の
カレンダーを出力する、という問題ですよね?

ym_input()で年・月を入力し、入力結果を他の関数に渡すのであれば、
int型の年・月のための変数を定義してから、
それらのアドレスをym_input()に渡せばよい(他にも方法はあります)わけで、
date[/url]というchar型の配列を介する必要は全くないと思います。

年・月として有効な値かどうかを判定する際にも、
int型の年・月をそのまま使えばよいのです。

なお、3999年だと閏年の計算がずれるという話は事実なのでしょうけれど、
「カレンダーを出力するためのロジックを学ぶ」という今回の話とは
本質的に異なるので、気になさる必要はありません。
「自分は何に着目すべきなのか?」を常に考えて、
横道にそれていきそうな話には目を向けないようにすることが大切です。

Re:万年カレンダー

Posted: 2007年7月19日(木) 23:52
by 雪中 蓮
すみません、このプログラムには仕様書がありまして・・・。

>void ym_input(int *year, int *month);
>int get_day_of_week(char *date);
>void cal_disp(int year,int month, int dayofweek);

この3つの関数をそのままの形で使わなければならないのです。

Re:万年カレンダー

Posted: 2007年7月19日(木) 23:56
by box
>int get_day_of_week(char *date);

dateには何が入っているのですか?
また、戻り値は何の値ですか?

仕様書があるということは、引数や戻り値についての説明があるはずです。

Re:万年カレンダー

Posted: 2007年7月20日(金) 00:03
by 雪中 蓮
すみません。入力し忘れてました。

>void ym_input(int *year, int *month);
戻り値:なし
year・・・年、month・・・月
>int get_day_of_week(char *date);
戻り値:曜日を表す数値(0~6)
0:日1:月2:火3:水4:木5:金6:土
date・・・年月日を表す8桁の数字文字列(年:西暦4桁、月:2桁、日:2桁)
>void cal_disp(int year,int month, int dayofweek);
戻り値:なし
year・・・年、month・・・月、dayofweek・・・曜日を現す整数値

Re:万年カレンダー

Posted: 2007年7月20日(金) 00:13
by box
ということは、int型で入力した年・月をもとにして、
char *型のdateを組み立てればよいです。

しかし、2桁の日をどこからも与えませんので、
どうやってdateを組み立てるかがよくわからないですね。

ただ、get_day_of_week()の戻り値がおそらく
その年・月の初日の曜日であろう(当方の思いこみかも)ことから推して、
"YYYYMM01"の形式(YYYY:西暦年、MM:月)の文字列を組み立てることを
期待しているのでしょうか。これも推測です。

仮にこれらの推測が当たっているとしても、当該年・月の初日の曜日を
求めるにはint型のままの方が楽なはずなので、
やはりchar *dateの必要性については個人的に疑問が残ります。

Re:万年カレンダー

Posted: 2007年7月20日(金) 00:20
by 雪中 蓮
この課題が出された時に、わざとややこしい事をしていると言っていたのでそう思われるのも無理は無いでしょう。
とりあえず、助言を参考にもう一度プログラムを組みなおしてみます。
またなにかあったときはよろしくお願いします。

Re:万年カレンダー

Posted: 2007年7月20日(金) 00:21
by 雪中 蓮
すみません、マークを変え忘れました・・・。

Re:万年カレンダー

Posted: 2007年7月22日(日) 19:07
by 雪中 蓮
先日に助言していただき、それを元に組み直してみましたが、またよくわからなくなってしまいました。
ポインタに関連する部分のイメージがわからなくなってしまっているので、またご助言ください。

-------------------------------------------

#include <stdio.h>
#include <string.h>


/******************************************/
void ym_input(int *year, int *month);

int get_day_of_week(char *date);

void cal_disp(int year,int month, int dayofweek);


/******************************************/
char *dp,date[8];
int *yp, *mp;
int year,month,day,dayofweek;


/******************************************/
int main(void)
{
int y2,m2;
char moji,moji_hen;

strcpy(date,"10000101");

yp = &y2;
mp = &m2;
ym_input(yp,mp);
moji=(char)y2;
moji_hen=(moji/1000+'0')*1000+(moji/100%10+'0')*100+(moji/10%10+'0')*10+(moji%10+'0');
strcpy(date,moji_hen);
moji=(char)m2;
moji_hen=(moji/1000+'0')*1000+(moji/100%10+'0')*100+(moji/10%10+'0')*10+(moji%10+'0');
strcpy(date,moji_hen);

dp = date[0];
dayofweek = get_day_of_week(dp);

cal_disp(year,month,dayofweek);

return 0;
}


/******************************************/
void ym_input(int *year, int *month)
{
int i;

printf("表示させたいカレンダーの年を西暦で入力してください\nただし入力可能範囲は1583~3999年とする ->");
while(1583>=i || 3999<=i){
scanf("%d",i);
if(1583>=i || 3999<=i) printf("Error:入力値が正しくありません\n");
}
*year=i;

printf("表示させたいカレンダーの月を入力してください ->");
while(01>=i || 12<=i){
scanf("%d",i);
if(1>=i || 12<=i) printf("Error:入力値が正しくありません\n");
}
*month=i;
}


/******************************************/
int get_day_of_week(char *date)
{
int i,a,d[8];
int *j;

j = d[0];
for(i=0;i<8;i++)
{
*(j + i) = *(date + i) - 48;
}

year = d[0] * 1000 + d[1] * 100 + d[2] * 10 + d[3];
month = d[4] * 10 + d[5];
day = d[6] * 10 + d[7];

a=((year+(year/4)-(year/100)+(year/400) + ((13 * month)+8)/5)+day)%7 ;
return a;
}


/******************************************/
void cal_disp(int year,int month, int dayofweek)
{
int i,j,a,max,flag;
char cal[6][7];

for(i=0;i<6||flag==1;i++){
for(j=0;j<7||flag==1;j++){
strcpy(cal[j]," ");
}
}


switch(month){
case 2 : {
if((year%4==0&&!(year%100==0))||year%400==0)
max=29;
else
max=28;
break;
}
case 4 :
case 6 :
case 9 :
case 11 : {
max=30;
break;
}
default : {
max=31;
break;
}
}

a=0;
flag=0;
for(i=0;i<6||flag==1;i++){
for(j=0;j<7||flag==1;j++){
if(i==0) j=dayofweek;
cal[j]=a++;
if(a==max) flag=1;
}
}
printf("%.4d年 %.2d月\n",year,month);
printf("日 月 火 水 木 金 土\n");

for(i=0;i<6||flag==1;i++){
for(j=0;j<7||flag==1;j++){
if(!(strcmp((char)cal[j]," ")))
printf(" ");
else
printf("%.2d",cal[j]);
printf(" ");
}
printf("\n");
}

}

Re:万年カレンダー

Posted: 2007年7月23日(月) 20:54
by box
cal_disp()の例を載せます。
他の関数のコードは考えてみてください。


void cal_disp(int year, int month, int dayofweek)
{
	int days[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 },		// 閏年
	};
	int leap, lastday, w, d, n;
	
	leap = year % 4 == 0 && year % 100 != 0 || year % 400 == 0;		// 閏年の判定
	lastday = days[leap][month];			// 当該月の日数
	
	printf("\n%d年%2d月\n", year, month);
	printf("日 月 火 水 木 金 土\n");
	for (w = 0; w < 6; w++) {				// 1ヶ月を6週とする
		n = 7 * w + 1 - dayofweek;			// 第w週日曜日の日付
		for (d = n; d < n + 7; d++) {		// 第w週を出力する
			if (1 <= d && d <= lastday)		// 有効な日付ならば
				printf("%2d ", d);			// 出力する
			else							// 無効な日付ならば
				printf("   ");				// 空白を出力する
		}
		printf("\n");
	}
	printf("\n");
}

Re:万年カレンダー

Posted: 2007年7月24日(火) 16:35
by 雪中 蓮
ありがとうございます。
その他の部分もなんとか解決できました。
色々とすみませんでした。